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": { "/apis/api.console.halo.run/v1alpha1/themes": {
"get": { "get": {
"description": "List themes.", "description": "List themes.",
@ -13467,6 +13549,10 @@
"type": "string", "type": "string",
"format": "date-time" "format": "date-time"
}, },
"observedVersion": {
"type": "integer",
"format": "int64"
},
"replyCount": { "replyCount": {
"type": "integer", "type": "integer",
"format": "int32" "format": "int32"
@ -16437,8 +16523,7 @@
"RESOLVED", "RESOLVED",
"STARTED", "STARTED",
"STOPPED", "STOPPED",
"FAILED", "FAILED"
"UNLOADED"
] ]
}, },
"lastStartTime": { "lastStartTime": {
@ -17469,7 +17554,8 @@
"apiVersion", "apiVersion",
"kind", "kind",
"metadata", "metadata",
"spec" "spec",
"status"
], ],
"type": "object", "type": "object",
"properties": { "properties": {
@ -17484,6 +17570,9 @@
}, },
"spec": { "spec": {
"$ref": "#/components/schemas/ReplySpec" "$ref": "#/components/schemas/ReplySpec"
},
"status": {
"$ref": "#/components/schemas/ReplyStatus"
} }
} }
}, },
@ -17642,6 +17731,15 @@
} }
} }
}, },
"ReplyStatus": {
"type": "object",
"properties": {
"observedVersion": {
"type": "integer",
"format": "int64"
}
}
},
"ReplyVo": { "ReplyVo": {
"required": [ "required": [
"metadata", "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()))); category -> defaultIfNull(category.getSpec().getPriority(), 0).toString())));
}); });
schemeManager.register(Tag.class, indexSpecs -> { schemeManager.register(Tag.class, indexSpecs -> {
indexSpecs.add(new IndexSpec()
.setName("spec.displayName")
.setIndexFunc(simpleAttribute(Tag.class, tag -> tag.getSpec().getDisplayName())));
indexSpecs.add(new IndexSpec() indexSpecs.add(new IndexSpec()
.setName("spec.slug") .setName("spec.slug")
.setIndexFunc(simpleAttribute(Tag.class, tag -> tag.getSpec().getSlug())) .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, VSpace,
VLoading, VLoading,
VPagination, VPagination,
IconRefreshLine,
} from "@halo-dev/components"; } from "@halo-dev/components";
import HasPermission from "@/components/permission/HasPermission.vue"; import HasPermission from "@/components/permission/HasPermission.vue";
import TagEditingModal from "./components/TagEditingModal.vue"; import TagEditingModal from "./components/TagEditingModal.vue";
@ -18,6 +19,12 @@ import { useRouteQuery } from "@vueuse/router";
import { apiClient } from "@/utils/api-client"; import { apiClient } from "@/utils/api-client";
import { usePostTag } from "./composables/use-post-tag"; import { usePostTag } from "./composables/use-post-tag";
import TagListItem from "./components/TagListItem.vue"; 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 editingModal = ref(false);
const selectedTag = ref<Tag | null>(null); const selectedTag = ref<Tag | null>(null);
@ -25,12 +32,22 @@ const selectedTag = ref<Tag | null>(null);
const selectedTagNames = ref<string[]>([]); const selectedTagNames = ref<string[]>([]);
const checkedAll = ref(false); const checkedAll = ref(false);
const keyword = useRouteQuery<string>("keyword", "");
const page = useRouteQuery<number>("page", 1, { const page = useRouteQuery<number>("page", 1, {
transform: Number, transform: Number,
}); });
const size = useRouteQuery<number>("size", 20, { const size = useRouteQuery<number>("size", 20, {
transform: Number, transform: Number,
}); });
const selectedSort = useRouteQuery<string | undefined>("sort");
const hasFilters = computed(() => {
return !!selectedSort.value;
});
const handleClearFilters = () => {
selectedSort.value = undefined;
};
const { const {
tags, tags,
@ -38,12 +55,15 @@ const {
hasNext, hasNext,
hasPrevious, hasPrevious,
isLoading, isLoading,
isFetching,
handleFetchTags, handleFetchTags,
handleDelete, handleDelete,
handleDeleteInBatch, handleDeleteInBatch,
} = usePostTag({ } = usePostTag({
page, page,
size, size,
keyword,
sort: selectedSort,
}); });
const handleOpenEditingModal = (tag: Tag | null) => { const handleOpenEditingModal = (tag: Tag | null) => {
@ -66,10 +86,6 @@ const handleCheckAllChange = () => {
}; };
const handleSelectPrevious = async () => { const handleSelectPrevious = async () => {
if (!hasPrevious.value) {
return;
}
if (!tags.value) return; if (!tags.value) return;
const currentIndex = tags.value.findIndex( const currentIndex = tags.value.findIndex(
@ -84,15 +100,14 @@ const handleSelectPrevious = async () => {
if (currentIndex === 0 && hasPrevious.value) { if (currentIndex === 0 && hasPrevious.value) {
page.value--; page.value--;
await handleFetchTags(); await handleFetchTags();
setTimeout(() => {
if (!tags.value) return;
selectedTag.value = tags.value[tags.value.length - 1]; selectedTag.value = tags.value[tags.value.length - 1];
});
} }
}; };
const handleSelectNext = async () => { const handleSelectNext = async () => {
if (!hasNext.value) {
return;
}
if (!tags.value) return; if (!tags.value) return;
if (!selectedTag.value) { if (!selectedTag.value) {
@ -109,7 +124,10 @@ const handleSelectNext = async () => {
if (currentIndex === tags.value.length - 1 && hasNext.value) { if (currentIndex === tags.value.length - 1 && hasNext.value) {
page.value++; page.value++;
await handleFetchTags(); await handleFetchTags();
setTimeout(() => {
if (!tags.value) return;
selectedTag.value = tags.value[0]; selectedTag.value = tags.value[0];
});
} }
}; };
@ -184,7 +202,59 @@ watch(selectedTagNames, (newVal) => {
{{ $t("core.common.buttons.delete") }} {{ $t("core.common.buttons.delete") }}
</VButton> </VButton>
</VSpace> </VSpace>
<SearchInput v-else v-model="keyword" />
</div> </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>
</div> </div>
</template> </template>

View File

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

View File

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

View File

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