diff --git a/packages/api-client/src/.openapi-generator/FILES b/packages/api-client/src/.openapi-generator/FILES index 06a63513b..425962537 100644 --- a/packages/api-client/src/.openapi-generator/FILES +++ b/packages/api-client/src/.openapi-generator/FILES @@ -1,6 +1,5 @@ .gitignore .npmignore -.openapi-generator-ignore api.ts api/api-console-halo-run-v1alpha1-attachment-api.ts api/api-console-halo-run-v1alpha1-comment-api.ts diff --git a/packages/api-client/src/api/api-console-halo-run-v1alpha1-user-api.ts b/packages/api-client/src/api/api-console-halo-run-v1alpha1-user-api.ts index 83b848e3f..1e90edf01 100644 --- a/packages/api-client/src/api/api-console-halo-run-v1alpha1-user-api.ts +++ b/packages/api-client/src/api/api-console-halo-run-v1alpha1-user-api.ts @@ -38,6 +38,8 @@ import { GrantRequest } from '../models' // @ts-ignore import { User } from '../models' // @ts-ignore +import { UserList } from '../models' +// @ts-ignore import { UserPermission } from '../models' /** * ApiConsoleHaloRunV1alpha1UserApi - axios parameter creator @@ -223,6 +225,85 @@ export const ApiConsoleHaloRunV1alpha1UserApiAxiosParamCreator = function (confi options: localVarRequestOptions, } }, + /** + * List users + * @param {Array} [sort] Sort property and direction of the list result. Supported fields: creationTimestamp + * @param {string} [keyword] + * @param {string} [role] + * @param {number} [size] Size of one page. Zero indicates no limit. + * @param {number} [page] The page number. Zero indicates no page. + * @param {Array} [labelSelector] Label selector for filtering. + * @param {Array} [fieldSelector] Field selector for filtering. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + listUsers: async ( + sort?: Array, + keyword?: string, + role?: string, + size?: number, + page?: number, + labelSelector?: Array, + fieldSelector?: Array, + options: AxiosRequestConfig = {}, + ): Promise => { + const localVarPath = `/apis/api.console.halo.run/v1alpha1/users` + // 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 (sort) { + localVarQueryParameter['sort'] = Array.from(sort) + } + + if (keyword !== undefined) { + localVarQueryParameter['keyword'] = keyword + } + + if (role !== undefined) { + localVarQueryParameter['role'] = role + } + + if (size !== undefined) { + localVarQueryParameter['size'] = size + } + + if (page !== undefined) { + localVarQueryParameter['page'] = page + } + + if (labelSelector) { + localVarQueryParameter['labelSelector'] = labelSelector + } + + if (fieldSelector) { + localVarQueryParameter['fieldSelector'] = fieldSelector + } + + setSearchParams(localVarUrlObj, localVarQueryParameter) + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {} + localVarRequestOptions.headers = { ...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers } + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + } + }, /** * Update current user profile, but password. * @param {User} user @@ -328,6 +409,40 @@ export const ApiConsoleHaloRunV1alpha1UserApiFp = function (configuration?: Conf const localVarAxiosArgs = await localVarAxiosParamCreator.grantPermission(name, grantRequest, options) return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration) }, + /** + * List users + * @param {Array} [sort] Sort property and direction of the list result. Supported fields: creationTimestamp + * @param {string} [keyword] + * @param {string} [role] + * @param {number} [size] Size of one page. Zero indicates no limit. + * @param {number} [page] The page number. Zero indicates no page. + * @param {Array} [labelSelector] Label selector for filtering. + * @param {Array} [fieldSelector] Field selector for filtering. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async listUsers( + sort?: Array, + keyword?: string, + role?: string, + size?: number, + page?: number, + labelSelector?: Array, + fieldSelector?: Array, + options?: AxiosRequestConfig, + ): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.listUsers( + sort, + keyword, + role, + size, + page, + labelSelector, + fieldSelector, + options, + ) + return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration) + }, /** * Update current user profile, but password. * @param {User} user @@ -403,6 +518,29 @@ export const ApiConsoleHaloRunV1alpha1UserApiFactory = function ( .grantPermission(requestParameters.name, requestParameters.grantRequest, options) .then((request) => request(axios, basePath)) }, + /** + * List users + * @param {ApiConsoleHaloRunV1alpha1UserApiListUsersRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + listUsers( + requestParameters: ApiConsoleHaloRunV1alpha1UserApiListUsersRequest = {}, + options?: AxiosRequestConfig, + ): AxiosPromise { + return localVarFp + .listUsers( + requestParameters.sort, + requestParameters.keyword, + requestParameters.role, + requestParameters.size, + requestParameters.page, + requestParameters.labelSelector, + requestParameters.fieldSelector, + options, + ) + .then((request) => request(axios, basePath)) + }, /** * Update current user profile, but password. * @param {ApiConsoleHaloRunV1alpha1UserApiUpdateCurrentUserRequest} requestParameters Request parameters. @@ -474,6 +612,62 @@ export interface ApiConsoleHaloRunV1alpha1UserApiGrantPermissionRequest { readonly grantRequest: GrantRequest } +/** + * Request parameters for listUsers operation in ApiConsoleHaloRunV1alpha1UserApi. + * @export + * @interface ApiConsoleHaloRunV1alpha1UserApiListUsersRequest + */ +export interface ApiConsoleHaloRunV1alpha1UserApiListUsersRequest { + /** + * Sort property and direction of the list result. Supported fields: creationTimestamp + * @type {Array} + * @memberof ApiConsoleHaloRunV1alpha1UserApiListUsers + */ + readonly sort?: Array + + /** + * + * @type {string} + * @memberof ApiConsoleHaloRunV1alpha1UserApiListUsers + */ + readonly keyword?: string + + /** + * + * @type {string} + * @memberof ApiConsoleHaloRunV1alpha1UserApiListUsers + */ + readonly role?: string + + /** + * Size of one page. Zero indicates no limit. + * @type {number} + * @memberof ApiConsoleHaloRunV1alpha1UserApiListUsers + */ + readonly size?: number + + /** + * The page number. Zero indicates no page. + * @type {number} + * @memberof ApiConsoleHaloRunV1alpha1UserApiListUsers + */ + readonly page?: number + + /** + * Label selector for filtering. + * @type {Array} + * @memberof ApiConsoleHaloRunV1alpha1UserApiListUsers + */ + readonly labelSelector?: Array + + /** + * Field selector for filtering. + * @type {Array} + * @memberof ApiConsoleHaloRunV1alpha1UserApiListUsers + */ + readonly fieldSelector?: Array +} + /** * Request parameters for updateCurrentUser operation in ApiConsoleHaloRunV1alpha1UserApi. * @export @@ -555,6 +749,31 @@ export class ApiConsoleHaloRunV1alpha1UserApi extends BaseAPI { .then((request) => request(this.axios, this.basePath)) } + /** + * List users + * @param {ApiConsoleHaloRunV1alpha1UserApiListUsersRequest} requestParameters Request parameters. + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof ApiConsoleHaloRunV1alpha1UserApi + */ + public listUsers( + requestParameters: ApiConsoleHaloRunV1alpha1UserApiListUsersRequest = {}, + options?: AxiosRequestConfig, + ) { + return ApiConsoleHaloRunV1alpha1UserApiFp(this.configuration) + .listUsers( + requestParameters.sort, + requestParameters.keyword, + requestParameters.role, + requestParameters.size, + requestParameters.page, + requestParameters.labelSelector, + requestParameters.fieldSelector, + options, + ) + .then((request) => request(this.axios, this.basePath)) + } + /** * Update current user profile, but password. * @param {ApiConsoleHaloRunV1alpha1UserApiUpdateCurrentUserRequest} requestParameters Request parameters. diff --git a/src/modules/system/users/UserList.vue b/src/modules/system/users/UserList.vue index 67fe3ed29..e59f0e0d0 100644 --- a/src/modules/system/users/UserList.vue +++ b/src/modules/system/users/UserList.vue @@ -17,20 +17,25 @@ import { VStatusDot, VLoading, Toast, + IconRefreshLine, + VEmpty, } from "@halo-dev/components"; import UserEditingModal from "./components/UserEditingModal.vue"; import UserPasswordChangeModal from "./components/UserPasswordChangeModal.vue"; import GrantPermissionModal from "./components/GrantPermissionModal.vue"; import { computed, onMounted, onUnmounted, ref, watch } from "vue"; import { apiClient } from "@/utils/api-client"; -import type { User, UserList } from "@halo-dev/api-client"; +import type { Role, User, UserList } from "@halo-dev/api-client"; import { rbacAnnotations } from "@/constants/annotations"; import { formatDatetime } from "@/utils/date"; import { useRouteQuery } from "@vueuse/router"; -import Fuse from "fuse.js"; import { usePermission } from "@/utils/permission"; import { useUserStore } from "@/stores/user"; import { useRoleStore } from "@/stores/role"; +import { getNode } from "@formkit/core"; +import FilterTag from "@/components/filter/FilterTag.vue"; +import { useFetchRole } from "../roles/composables/use-role"; +import FilterCleanButton from "@/components/filter/FilterCleanButton.vue"; const { currentUserHasPermission } = usePermission(); @@ -53,16 +58,18 @@ const users = ref({ const loading = ref(false); const selectedUserNames = ref([]); const selectedUser = ref(); +const keyword = ref(""); const refreshInterval = ref(); const userStore = useUserStore(); const roleStore = useRoleStore(); -let fuse: Fuse | undefined = undefined; - const ANONYMOUSUSER_NAME = "anonymousUser"; -const handleFetchUsers = async (options?: { mute?: boolean }) => { +const handleFetchUsers = async (options?: { + mute?: boolean; + page?: number; +}) => { try { clearInterval(refreshInterval.value); @@ -70,18 +77,22 @@ const handleFetchUsers = async (options?: { mute?: boolean }) => { loading.value = true; } - const { data } = await apiClient.extension.user.listv1alpha1User({ + if (options?.page) { + users.value.page = options.page; + } + + const { data } = await apiClient.user.listUsers({ page: users.value.page, size: users.value.size, + keyword: keyword.value, fieldSelector: [`name!=${ANONYMOUSUSER_NAME}`], + sort: [selectedSortItem.value?.value].filter( + (item) => !!item + ) as string[], + role: selectedRole.value?.metadata.name, }); - users.value = data; - fuse = new Fuse(data.items, { - keys: ["spec.displayName", "metadata.name", "spec.email"], - useExtendedSearch: true, - threshold: 0.2, - }); + users.value = data; const deletedUsers = users.value.items.filter( (user) => !!user.metadata.deletionTimestamp @@ -100,16 +111,6 @@ const handleFetchUsers = async (options?: { mute?: boolean }) => { } }; -const keyword = ref(""); - -const searchResults = computed(() => { - if (!fuse || !keyword.value) { - return users.value.items; - } - - return fuse?.search(keyword.value).map((item) => item.item); -}); - const handlePaginationChange = async ({ page, size, @@ -239,6 +240,62 @@ onMounted(() => { editingModal.value = true; } }); + +// Filters +function handleKeywordChange() { + const keywordNode = getNode("keywordInput"); + if (keywordNode) { + keyword.value = keywordNode._value as string; + } + handleFetchUsers({ page: 1 }); +} + +function handleClearKeyword() { + keyword.value = ""; + handleFetchUsers({ page: 1 }); +} + +interface SortItem { + label: string; + value: string; +} + +const SortItems: SortItem[] = [ + { + label: "较近创建", + value: "creationTimestamp,desc", + }, + { + label: "较早创建", + value: "creationTimestamp,asc", + }, +]; + +const selectedSortItem = ref(); + +function handleSortItemChange(sortItem?: SortItem) { + selectedSortItem.value = sortItem; + handleFetchUsers({ page: 1 }); +} + +const { roles } = useFetchRole(); +const selectedRole = ref(); + +function handleRoleChange(role?: Role) { + selectedRole.value = role; + handleFetchUsers({ page: 1 }); +} + +function handleClearFilters() { + selectedRole.value = undefined; + selectedSortItem.value = undefined; + keyword.value = ""; + handleFetchUsers({ page: 1 }); +} + +const hasFilters = computed(() => { + return selectedRole.value || selectedSortItem.value || keyword.value; +}); +
+
+ +
+
+ + + + + + + +
    -
  • +