feat: add search and filtering functions to post tags (#5710)

pull/5662/head
Takagi 2024-04-23 17:26:29 +08:00 committed by GitHub
parent 06e0b63b5b
commit a692c622c9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 687 additions and 23 deletions

View File

@ -3585,6 +3585,88 @@
]
}
},
"/apis/api.console.halo.run/v1alpha1/tags": {
"get": {
"description": "List Post Tags.",
"operationId": "ListPostTags",
"parameters": [
{
"description": "Page number. Default is 0.",
"in": "query",
"name": "page",
"schema": {
"type": "integer",
"format": "int32"
}
},
{
"description": "Size number. Default is 0.",
"in": "query",
"name": "size",
"schema": {
"type": "integer",
"format": "int32"
}
},
{
"description": "Label selector. e.g.: hidden!\u003dtrue",
"in": "query",
"name": "labelSelector",
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
},
{
"description": "Field selector. e.g.: metadata.name\u003d\u003dhalo",
"in": "query",
"name": "fieldSelector",
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
},
{
"description": "Sorting criteria in the format: property,(asc|desc). Default sort order is ascending. Multiple sort criteria are supported.",
"in": "query",
"name": "sort",
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
},
{
"description": "Post tags filtered by keyword.",
"in": "query",
"name": "keyword",
"schema": {
"type": "string"
}
}
],
"responses": {
"default": {
"content": {
"*/*": {
"schema": {
"$ref": "#/components/schemas/TagList"
}
}
},
"description": "default response"
}
},
"tags": [
"api.console.halo.run/v1alpha1/Tag"
]
}
},
"/apis/api.console.halo.run/v1alpha1/themes": {
"get": {
"description": "List themes.",
@ -13467,6 +13549,10 @@
"type": "string",
"format": "date-time"
},
"observedVersion": {
"type": "integer",
"format": "int64"
},
"replyCount": {
"type": "integer",
"format": "int32"
@ -16437,8 +16523,7 @@
"RESOLVED",
"STARTED",
"STOPPED",
"FAILED",
"UNLOADED"
"FAILED"
]
},
"lastStartTime": {
@ -17469,7 +17554,8 @@
"apiVersion",
"kind",
"metadata",
"spec"
"spec",
"status"
],
"type": "object",
"properties": {
@ -17484,6 +17570,9 @@
},
"spec": {
"$ref": "#/components/schemas/ReplySpec"
},
"status": {
"$ref": "#/components/schemas/ReplyStatus"
}
}
},
@ -17642,6 +17731,15 @@
}
}
},
"ReplyStatus": {
"type": "object",
"properties": {
"observedVersion": {
"type": "integer",
"format": "int64"
}
}
},
"ReplyVo": {
"required": [
"metadata",

View File

@ -0,0 +1,139 @@
package run.halo.app.core.extension.endpoint;
import static org.springdoc.core.fn.builders.apiresponse.Builder.responseBuilder;
import static org.springdoc.core.fn.builders.parameter.Builder.parameterBuilder;
import static run.halo.app.extension.index.query.QueryFactory.all;
import static run.halo.app.extension.router.QueryParamBuildUtil.sortParameter;
import static run.halo.app.extension.router.selector.SelectorUtil.labelAndFieldSelectorToListOptions;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springdoc.core.fn.builders.operation.Builder;
import org.springdoc.webflux.core.fn.SpringdocRouteBuilder;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import run.halo.app.core.extension.content.Tag;
import run.halo.app.extension.ListOptions;
import run.halo.app.extension.ListResult;
import run.halo.app.extension.PageRequestImpl;
import run.halo.app.extension.ReactiveExtensionClient;
import run.halo.app.extension.index.query.QueryFactory;
import run.halo.app.extension.router.IListRequest;
/**
* post tag endpoint.
*
* @author LIlGG
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class TagEndpoint implements CustomEndpoint {
private final ReactiveExtensionClient client;
@Override
public RouterFunction<ServerResponse> endpoint() {
final var tag = "api.console.halo.run/v1alpha1/Tag";
return SpringdocRouteBuilder.route()
.GET("tags", this::listTag, builder -> {
builder.operationId("ListPostTags")
.description("List Post Tags.")
.tag(tag)
.response(
responseBuilder()
.implementation(ListResult.generateGenericClass(Tag.class))
);
TagQuery.buildParameters(builder);
}
)
.build();
}
Mono<ServerResponse> listTag(ServerRequest request) {
var tagQuery = new TagQuery(request);
return client.listBy(Tag.class, tagQuery.toListOptions(),
PageRequestImpl.of(tagQuery.getPage(), tagQuery.getSize(), tagQuery.getSort())
)
.flatMap(tags -> ServerResponse.ok().bodyValue(tags));
}
public interface ITagQuery extends IListRequest {
@Schema(description = "Keyword for searching.")
Optional<String> getKeyword();
@ArraySchema(uniqueItems = true,
arraySchema = @Schema(name = "sort",
description = "Sort property and direction of the list result. Supported fields: "
+ "creationTimestamp, name"),
schema = @Schema(description = "like field,asc or field,desc",
implementation = String.class,
example = "creationTimestamp,desc"))
Sort getSort();
}
public static class TagQuery extends IListRequest.QueryListRequest
implements ITagQuery {
private final ServerWebExchange exchange;
public TagQuery(ServerRequest request) {
super(request.queryParams());
this.exchange = request.exchange();
}
@Override
public Optional<String> getKeyword() {
return Optional.ofNullable(queryParams.getFirst("keyword"))
.filter(StringUtils::hasText);
}
@Override
public Sort getSort() {
var sort = SortResolver.defaultInstance.resolve(exchange);
sort = sort.and(Sort.by(
Sort.Order.desc("metadata.creationTimestamp"),
Sort.Order.asc("metadata.name")
));
return sort;
}
public ListOptions toListOptions() {
final var listOptions =
labelAndFieldSelectorToListOptions(getLabelSelector(), getFieldSelector());
var fieldQuery = all();
if (getKeyword().isPresent()) {
fieldQuery = QueryFactory.and(fieldQuery, QueryFactory.or(
QueryFactory.contains("spec.displayName", getKeyword().get()),
QueryFactory.contains("spec.slug", getKeyword().get())
));
}
listOptions.setFieldSelector(listOptions.getFieldSelector().andQuery(fieldQuery));
return listOptions;
}
public static void buildParameters(Builder builder) {
IListRequest.buildParameters(builder);
builder.parameter(sortParameter())
.parameter(parameterBuilder()
.in(ParameterIn.QUERY)
.name("keyword")
.description("Post tags filtered by keyword.")
.implementation(String.class)
.required(false));
}
}
}

View File

@ -226,6 +226,9 @@ public class SchemeInitializer implements ApplicationListener<ApplicationContext
category -> defaultIfNull(category.getSpec().getPriority(), 0).toString())));
});
schemeManager.register(Tag.class, indexSpecs -> {
indexSpecs.add(new IndexSpec()
.setName("spec.displayName")
.setIndexFunc(simpleAttribute(Tag.class, tag -> tag.getSpec().getDisplayName())));
indexSpecs.add(new IndexSpec()
.setName("spec.slug")
.setIndexFunc(simpleAttribute(Tag.class, tag -> tag.getSpec().getSlug()))

View File

@ -0,0 +1,104 @@
package run.halo.app.core.extension.endpoint;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.same;
import static org.mockito.Mockito.when;
import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.springSecurity;
import static org.springframework.test.web.reactive.server.WebTestClient.bindToRouterFunction;
import java.time.Instant;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.test.web.reactive.server.WebTestClient;
import reactor.core.publisher.Mono;
import run.halo.app.core.extension.content.Tag;
import run.halo.app.extension.ListResult;
import run.halo.app.extension.Metadata;
import run.halo.app.extension.PageRequest;
import run.halo.app.extension.ReactiveExtensionClient;
/**
* Tag endpoint test.
*
* @author LIlGG
*/
@ExtendWith(MockitoExtension.class)
class TagEndpointTest {
@Mock
ReactiveExtensionClient client;
@InjectMocks
TagEndpoint tagEndpoint;
WebTestClient webClient;
@BeforeEach
void setUp() {
webClient = WebTestClient.bindToRouterFunction(tagEndpoint.endpoint())
.apply(springSecurity())
.build();
}
@Nested
class TagListTest {
@Test
void shouldListEmptyTagsWhenNoTags() {
when(client.listBy(same(Tag.class), any(), any(PageRequest.class)))
.thenReturn(Mono.just(ListResult.emptyResult()));
bindToRouterFunction(tagEndpoint.endpoint())
.build()
.get().uri("/tags")
.exchange()
.expectStatus().isOk()
.expectBody()
.jsonPath("$.items.length()").isEqualTo(0)
.jsonPath("$.total").isEqualTo(0);
}
@Test
void shouldListTagsWhenTagPresent() {
var tags = List.of(
createTag("fake-tag-1"),
createTag("fake-tag-2")
);
var expectResult = new ListResult<>(tags);
when(client.listBy(same(Tag.class), any(), any(PageRequest.class)))
.thenReturn(Mono.just(expectResult));
bindToRouterFunction(tagEndpoint.endpoint())
.build()
.get().uri("/tags")
.exchange()
.expectStatus().isOk()
.expectBody()
.jsonPath("$.items.length()").isEqualTo(2)
.jsonPath("$.total").isEqualTo(2);
}
Tag createTag(String name) {
return createTag(name, "fake display name");
}
Tag createTag(String name, String displayName) {
var metadata = new Metadata();
metadata.setName(name);
metadata.setCreationTimestamp(Instant.now());
var spec = new Tag.TagSpec();
spec.setDisplayName(displayName);
spec.setSlug(name);
var tag = new Tag();
tag.setMetadata(metadata);
tag.setSpec(spec);
return tag;
}
}
}

View File

@ -11,6 +11,7 @@ import {
VSpace,
VLoading,
VPagination,
IconRefreshLine,
} from "@halo-dev/components";
import HasPermission from "@/components/permission/HasPermission.vue";
import TagEditingModal from "./components/TagEditingModal.vue";
@ -18,6 +19,12 @@ import { useRouteQuery } from "@vueuse/router";
import { apiClient } from "@/utils/api-client";
import { usePostTag } from "./composables/use-post-tag";
import TagListItem from "./components/TagListItem.vue";
import SearchInput from "@/components/input/SearchInput.vue";
import FilterCleanButton from "@/components/filter/FilterCleanButton.vue";
import { computed } from "vue";
import { useI18n } from "vue-i18n";
const { t } = useI18n();
const editingModal = ref(false);
const selectedTag = ref<Tag | null>(null);
@ -25,12 +32,22 @@ const selectedTag = ref<Tag | null>(null);
const selectedTagNames = ref<string[]>([]);
const checkedAll = ref(false);
const keyword = useRouteQuery<string>("keyword", "");
const page = useRouteQuery<number>("page", 1, {
transform: Number,
});
const size = useRouteQuery<number>("size", 20, {
transform: Number,
});
const selectedSort = useRouteQuery<string | undefined>("sort");
const hasFilters = computed(() => {
return !!selectedSort.value;
});
const handleClearFilters = () => {
selectedSort.value = undefined;
};
const {
tags,
@ -38,12 +55,15 @@ const {
hasNext,
hasPrevious,
isLoading,
isFetching,
handleFetchTags,
handleDelete,
handleDeleteInBatch,
} = usePostTag({
page,
size,
keyword,
sort: selectedSort,
});
const handleOpenEditingModal = (tag: Tag | null) => {
@ -66,10 +86,6 @@ const handleCheckAllChange = () => {
};
const handleSelectPrevious = async () => {
if (!hasPrevious.value) {
return;
}
if (!tags.value) return;
const currentIndex = tags.value.findIndex(
@ -84,15 +100,14 @@ const handleSelectPrevious = async () => {
if (currentIndex === 0 && hasPrevious.value) {
page.value--;
await handleFetchTags();
selectedTag.value = tags.value[tags.value.length - 1];
setTimeout(() => {
if (!tags.value) return;
selectedTag.value = tags.value[tags.value.length - 1];
});
}
};
const handleSelectNext = async () => {
if (!hasNext.value) {
return;
}
if (!tags.value) return;
if (!selectedTag.value) {
@ -109,7 +124,10 @@ const handleSelectNext = async () => {
if (currentIndex === tags.value.length - 1 && hasNext.value) {
page.value++;
await handleFetchTags();
selectedTag.value = tags.value[0];
setTimeout(() => {
if (!tags.value) return;
selectedTag.value = tags.value[0];
});
}
};
@ -184,7 +202,59 @@ watch(selectedTagNames, (newVal) => {
{{ $t("core.common.buttons.delete") }}
</VButton>
</VSpace>
<SearchInput v-else v-model="keyword" />
</div>
<VSpace spacing="lg" class="flex-wrap">
<FilterCleanButton
v-if="hasFilters"
@click="handleClearFilters"
/>
<FilterDropdown
v-model="selectedSort"
:label="$t('core.common.filters.labels.sort')"
:items="[
{
label: t('core.common.filters.item_labels.default'),
},
{
label: t(
'core.post.tag.filters.sort.items.create_time_desc'
),
value: 'metadata.creationTimestamp,desc',
},
{
label: t(
'core.post.tag.filters.sort.items.create_time_asc'
),
value: 'metadata.creationTimestamp,asc',
},
{
label: t(
'core.post.tag.filters.sort.items.display_name_desc'
),
value: 'spec.displayName,desc',
},
{
label: t(
'core.post.tag.filters.sort.items.display_name_asc'
),
value: 'spec.displayName,asc',
},
]"
/>
<div class="flex flex-row gap-2">
<div
class="group cursor-pointer rounded p-1 hover:bg-gray-200"
@click="handleFetchTags()"
>
<IconRefreshLine
v-tooltip="$t('core.common.buttons.refresh')"
:class="{ 'animate-spin text-gray-900': isFetching }"
class="h-4 w-4 text-gray-600 group-hover:text-gray-900"
/>
</div>
</div>
</VSpace>
</div>
</div>
</template>

View File

@ -1,6 +1,6 @@
import { apiClient } from "@/utils/api-client";
import type { Tag } from "@halo-dev/api-client";
import { ref, type Ref } from "vue";
import { ref, watch, type Ref } from "vue";
import { Dialog, Toast } from "@halo-dev/components";
import { useQuery, type QueryObserverResult } from "@tanstack/vue-query";
import { useI18n } from "vue-i18n";
@ -11,19 +11,21 @@ interface usePostTagReturn {
hasPrevious: Ref<boolean>;
hasNext: Ref<boolean>;
isLoading: Ref<boolean>;
isFetching: Ref<boolean>;
handleFetchTags: () => Promise<QueryObserverResult<Tag[], unknown>>;
handleDelete: (tag: Tag) => void;
handleDeleteInBatch: (tagNames: string[]) => Promise<void>;
}
export function usePostTag(filterOptions?: {
sort?: Ref<string[]>;
sort?: Ref<string | undefined>;
page?: Ref<number>;
size?: Ref<number>;
keyword?: Ref<string>;
}): usePostTagReturn {
const { t } = useI18n();
const { sort, page, size } = filterOptions || {};
const { sort, page, size, keyword } = filterOptions || {};
const total = ref(0);
const hasPrevious = ref(false);
@ -32,16 +34,19 @@ export function usePostTag(filterOptions?: {
const {
data: tags,
isLoading,
isFetching,
refetch,
} = useQuery({
queryKey: ["post-tags", sort, page, size],
queryKey: ["post-tags", sort, page, size, keyword],
queryFn: async () => {
const { data } =
await apiClient.extension.tag.listcontentHaloRunV1alpha1Tag({
page: page?.value || 0,
size: size?.value || 0,
sort: sort?.value || ["metadata.creationTimestamp,desc"],
});
const { data } = await apiClient.tag.listPostTags({
page: page?.value || 0,
size: size?.value || 0,
sort: [sort?.value as string].filter(Boolean) || [
"metadata.creationTimestamp,desc",
],
keyword: keyword?.value,
});
total.value = data.total;
hasPrevious.value = data.hasPrevious;
@ -110,12 +115,22 @@ export function usePostTag(filterOptions?: {
});
};
watch(
() => [sort?.value, keyword?.value],
() => {
if (page?.value) {
page.value = 1;
}
}
);
return {
tags,
total,
hasPrevious,
hasNext,
isLoading,
isFetching,
handleFetchTags: refetch,
handleDelete,
handleDeleteInBatch,

View File

@ -12,6 +12,7 @@ api/api-console-halo-run-v1alpha1-reply-api.ts
api/api-console-halo-run-v1alpha1-single-page-api.ts
api/api-console-halo-run-v1alpha1-stats-api.ts
api/api-console-halo-run-v1alpha1-system-api.ts
api/api-console-halo-run-v1alpha1-tag-api.ts
api/api-console-halo-run-v1alpha1-theme-api.ts
api/api-console-halo-run-v1alpha1-user-api.ts
api/api-console-migration-halo-run-v1alpha1-migration-api.ts

View File

@ -25,6 +25,7 @@ export * from './api/api-console-halo-run-v1alpha1-reply-api';
export * from './api/api-console-halo-run-v1alpha1-single-page-api';
export * from './api/api-console-halo-run-v1alpha1-stats-api';
export * from './api/api-console-halo-run-v1alpha1-system-api';
export * from './api/api-console-halo-run-v1alpha1-tag-api';
export * from './api/api-console-halo-run-v1alpha1-theme-api';
export * from './api/api-console-halo-run-v1alpha1-user-api';
export * from './api/api-console-migration-halo-run-v1alpha1-migration-api';

View File

@ -0,0 +1,215 @@
/* tslint:disable */
/* eslint-disable */
/**
* Halo Next API
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: 2.0.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
import type { Configuration } from '../configuration';
import type { AxiosPromise, AxiosInstance, RawAxiosRequestConfig } from 'axios';
import globalAxios from 'axios';
// Some imports not used depending on template conditions
// @ts-ignore
import { DUMMY_BASE_URL, assertParamExists, setApiKeyToObject, setBasicAuthToObject, setBearerAuthToObject, setOAuthToObject, setSearchParams, serializeDataIfNeeded, toPathString, createRequestFunction } from '../common';
// @ts-ignore
import { BASE_PATH, COLLECTION_FORMATS, RequestArgs, BaseAPI, RequiredError, operationServerMap } from '../base';
// @ts-ignore
import { TagList } from '../models';
/**
* ApiConsoleHaloRunV1alpha1TagApi - axios parameter creator
* @export
*/
export const ApiConsoleHaloRunV1alpha1TagApiAxiosParamCreator = function (configuration?: Configuration) {
return {
/**
* List Post Tags.
* @param {Array<string>} [fieldSelector] Field selector for filtering.
* @param {string} [keyword] Keyword for searching.
* @param {Array<string>} [labelSelector] Label selector for filtering.
* @param {number} [page] The page number. Zero indicates no page.
* @param {number} [size] Size of one page. Zero indicates no limit.
* @param {Array<string>} [sort] Sort property and direction of the list result. Supported fields: creationTimestamp, name
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
listPostTags: async (fieldSelector?: Array<string>, keyword?: string, labelSelector?: Array<string>, page?: number, size?: number, sort?: Array<string>, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
const localVarPath = `/apis/api.console.halo.run/v1alpha1/tags`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
// authentication BasicAuth required
// http basic authentication required
setBasicAuthToObject(localVarRequestOptions, configuration)
// authentication BearerAuth required
// http bearer authentication required
await setBearerAuthToObject(localVarHeaderParameter, configuration)
if (fieldSelector) {
localVarQueryParameter['fieldSelector'] = fieldSelector;
}
if (keyword !== undefined) {
localVarQueryParameter['keyword'] = keyword;
}
if (labelSelector) {
localVarQueryParameter['labelSelector'] = labelSelector;
}
if (page !== undefined) {
localVarQueryParameter['page'] = page;
}
if (size !== undefined) {
localVarQueryParameter['size'] = size;
}
if (sort) {
localVarQueryParameter['sort'] = Array.from(sort);
}
setSearchParams(localVarUrlObj, localVarQueryParameter);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
return {
url: toPathString(localVarUrlObj),
options: localVarRequestOptions,
};
},
}
};
/**
* ApiConsoleHaloRunV1alpha1TagApi - functional programming interface
* @export
*/
export const ApiConsoleHaloRunV1alpha1TagApiFp = function(configuration?: Configuration) {
const localVarAxiosParamCreator = ApiConsoleHaloRunV1alpha1TagApiAxiosParamCreator(configuration)
return {
/**
* List Post Tags.
* @param {Array<string>} [fieldSelector] Field selector for filtering.
* @param {string} [keyword] Keyword for searching.
* @param {Array<string>} [labelSelector] Label selector for filtering.
* @param {number} [page] The page number. Zero indicates no page.
* @param {number} [size] Size of one page. Zero indicates no limit.
* @param {Array<string>} [sort] Sort property and direction of the list result. Supported fields: creationTimestamp, name
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async listPostTags(fieldSelector?: Array<string>, keyword?: string, labelSelector?: Array<string>, page?: number, size?: number, sort?: Array<string>, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<TagList>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.listPostTags(fieldSelector, keyword, labelSelector, page, size, sort, options);
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
const localVarOperationServerBasePath = operationServerMap['ApiConsoleHaloRunV1alpha1TagApi.listPostTags']?.[localVarOperationServerIndex]?.url;
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
},
}
};
/**
* ApiConsoleHaloRunV1alpha1TagApi - factory interface
* @export
*/
export const ApiConsoleHaloRunV1alpha1TagApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) {
const localVarFp = ApiConsoleHaloRunV1alpha1TagApiFp(configuration)
return {
/**
* List Post Tags.
* @param {ApiConsoleHaloRunV1alpha1TagApiListPostTagsRequest} requestParameters Request parameters.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
listPostTags(requestParameters: ApiConsoleHaloRunV1alpha1TagApiListPostTagsRequest = {}, options?: RawAxiosRequestConfig): AxiosPromise<TagList> {
return localVarFp.listPostTags(requestParameters.fieldSelector, requestParameters.keyword, requestParameters.labelSelector, requestParameters.page, requestParameters.size, requestParameters.sort, options).then((request) => request(axios, basePath));
},
};
};
/**
* Request parameters for listPostTags operation in ApiConsoleHaloRunV1alpha1TagApi.
* @export
* @interface ApiConsoleHaloRunV1alpha1TagApiListPostTagsRequest
*/
export interface ApiConsoleHaloRunV1alpha1TagApiListPostTagsRequest {
/**
* Field selector for filtering.
* @type {Array<string>}
* @memberof ApiConsoleHaloRunV1alpha1TagApiListPostTags
*/
readonly fieldSelector?: Array<string>
/**
* Keyword for searching.
* @type {string}
* @memberof ApiConsoleHaloRunV1alpha1TagApiListPostTags
*/
readonly keyword?: string
/**
* Label selector for filtering.
* @type {Array<string>}
* @memberof ApiConsoleHaloRunV1alpha1TagApiListPostTags
*/
readonly labelSelector?: Array<string>
/**
* The page number. Zero indicates no page.
* @type {number}
* @memberof ApiConsoleHaloRunV1alpha1TagApiListPostTags
*/
readonly page?: number
/**
* Size of one page. Zero indicates no limit.
* @type {number}
* @memberof ApiConsoleHaloRunV1alpha1TagApiListPostTags
*/
readonly size?: number
/**
* Sort property and direction of the list result. Supported fields: creationTimestamp, name
* @type {Array<string>}
* @memberof ApiConsoleHaloRunV1alpha1TagApiListPostTags
*/
readonly sort?: Array<string>
}
/**
* ApiConsoleHaloRunV1alpha1TagApi - object-oriented interface
* @export
* @class ApiConsoleHaloRunV1alpha1TagApi
* @extends {BaseAPI}
*/
export class ApiConsoleHaloRunV1alpha1TagApi extends BaseAPI {
/**
* List Post Tags.
* @param {ApiConsoleHaloRunV1alpha1TagApiListPostTagsRequest} requestParameters Request parameters.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof ApiConsoleHaloRunV1alpha1TagApi
*/
public listPostTags(requestParameters: ApiConsoleHaloRunV1alpha1TagApiListPostTagsRequest = {}, options?: RawAxiosRequestConfig) {
return ApiConsoleHaloRunV1alpha1TagApiFp(this.configuration).listPostTags(requestParameters.fieldSelector, requestParameters.keyword, requestParameters.labelSelector, requestParameters.page, requestParameters.size, requestParameters.sort, options).then((request) => request(this.axios, this.basePath));
}
}

View File

@ -260,6 +260,14 @@ core:
label: Template
cover:
label: Cover
tag:
filters:
sort:
items:
create_time_desc: Latest Created
create_time_asc: Earliest Created
display_name_desc: Descending order by tag name
display_name_asc: Ascending order by tag name
deleted_post:
title: Deleted Posts
empty:

View File

@ -252,6 +252,14 @@ core:
label: 自定义模板
cover:
label: 封面图
tag:
filters:
sort:
items:
create_time_desc: 较近创建
create_time_asc: 较早创建
display_name_desc: 标签名降序
display_name_asc: 标签名升序
deleted_post:
title: 文章回收站
empty:

View File

@ -1,6 +1,7 @@
import {
ApiConsoleHaloRunV1alpha1PluginApi,
ApiConsoleHaloRunV1alpha1PostApi,
ApiConsoleHaloRunV1alpha1TagApi,
ApiConsoleHaloRunV1alpha1SinglePageApi,
ApiConsoleHaloRunV1alpha1ThemeApi,
ApiConsoleHaloRunV1alpha1UserApi,
@ -207,6 +208,7 @@ function setupApiClient(axios: AxiosInstance) {
plugin: new ApiConsoleHaloRunV1alpha1PluginApi(undefined, baseURL, axios),
theme: new ApiConsoleHaloRunV1alpha1ThemeApi(undefined, baseURL, axios),
post: new ApiConsoleHaloRunV1alpha1PostApi(undefined, baseURL, axios),
tag: new ApiConsoleHaloRunV1alpha1TagApi(undefined, baseURL, axios),
singlePage: new ApiConsoleHaloRunV1alpha1SinglePageApi(
undefined,
baseURL,