From a3bb48bf9887d887e5450af2b790b7861e8fee99 Mon Sep 17 00:00:00 2001 From: NFish Date: Tue, 15 Apr 2025 14:31:10 +0800 Subject: [PATCH] fix: web app access-control setting supports filter by group --- web/app/(shareLayout)/webapp-signin/page.tsx | 8 ---- .../access-control-item.tsx | 2 +- .../add-member-or-group-pop.tsx | 40 +++++++++++++++++-- .../app/app-access-control/index.tsx | 2 +- .../specific-groups-or-members.tsx | 2 +- .../access-control-store.ts | 4 ++ web/i18n/en-US/common.ts | 2 +- web/i18n/ja-JP/common.ts | 1 + web/service/access-control.ts | 10 ++++- 9 files changed, 53 insertions(+), 18 deletions(-) rename web/{app/components/app/app-access-control => context}/access-control-store.ts (78%) diff --git a/web/app/(shareLayout)/webapp-signin/page.tsx b/web/app/(shareLayout)/webapp-signin/page.tsx index a485cb6caa..6c00b46e90 100644 --- a/web/app/(shareLayout)/webapp-signin/page.tsx +++ b/web/app/(shareLayout)/webapp-signin/page.tsx @@ -76,14 +76,6 @@ const WebSSOForm: FC = () => { } } - const goWebApp = () => { - if (!redirectUrl) { - showErrorToast('redirect url is invalid.') - return - } - router.push(redirectUrl) - } - useEffect(() => { const init = async () => { if (message) { diff --git a/web/app/components/app/app-access-control/access-control-item.tsx b/web/app/components/app/app-access-control/access-control-item.tsx index 178e6e196b..9e5c7ca5a7 100644 --- a/web/app/components/app/app-access-control/access-control-item.tsx +++ b/web/app/components/app/app-access-control/access-control-item.tsx @@ -1,6 +1,6 @@ 'use client' import type { FC, PropsWithChildren } from 'react' -import useAccessControlStore from './access-control-store' +import useAccessControlStore from '../../../../context/access-control-store' import type { AccessMode } from '@/models/access-control' type AccessControlItemProps = PropsWithChildren<{ diff --git a/web/app/components/app/app-access-control/add-member-or-group-pop.tsx b/web/app/components/app/app-access-control/add-member-or-group-pop.tsx index ad61ef814e..892747d328 100644 --- a/web/app/components/app/app-access-control/add-member-or-group-pop.tsx +++ b/web/app/components/app/app-access-control/add-member-or-group-pop.tsx @@ -9,7 +9,7 @@ import Checkbox from '../../base/checkbox' import Input from '../../base/input' import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger } from '../../base/portal-to-follow-elem' import Loading from '../../base/loading' -import useAccessControlStore from './access-control-store' +import useAccessControlStore from '../../../../context/access-control-store' import classNames from '@/utils/classnames' import { useSearchForWhiteListCandidates } from '@/service/access-control' import type { AccessControlAccount, AccessControlGroup, Subject, SubjectAccount, SubjectGroup } from '@/models/access-control' @@ -20,9 +20,11 @@ export default function AddMemberOrGroupDialog() { const { t } = useTranslation() const [open, setOpen] = useState(false) const [keyword, setKeyword] = useState('') + const selectedGroupsForBreadcrumb = useAccessControlStore(s => s.selectedGroupsForBreadcrumb) const debouncedKeyword = useDebounce(keyword, { wait: 500 }) - const { isPending, isFetchingNextPage, fetchNextPage, data } = useSearchForWhiteListCandidates({ keyword: debouncedKeyword, resultsPerPage: 10 }, open) + const lastAvailableGroup = selectedGroupsForBreadcrumb[selectedGroupsForBreadcrumb.length - 1] + const { isPending, isFetchingNextPage, fetchNextPage, data } = useSearchForWhiteListCandidates({ keyword: debouncedKeyword, groupId: lastAvailableGroup?.id, resultsPerPage: 10 }, open) const handleKeywordChange = (e: React.ChangeEvent) => { setKeyword(e.target.value) } @@ -59,7 +61,7 @@ export default function AddMemberOrGroupDialog() { : (data?.pages?.length ?? 0) > 0 ? <>
- {t('app.accessControlDialog.operateGroupAndMember.allMembers')} +
{renderGroupOrMember(data?.pages ?? [])} {isFetchingNextPage &&
} @@ -87,6 +89,29 @@ function renderGroupOrMember(data: GroupOrMemberData) { }) ?? null } +function SelectedGroupsBreadCrumb() { + const selectedGroupsForBreadcrumb = useAccessControlStore(s => s.selectedGroupsForBreadcrumb) + const setSelectedGroupsForBreadcrumb = useAccessControlStore(s => s.setSelectedGroupsForBreadcrumb) + const { t } = useTranslation() + + const handleBreadCrumbClick = useCallback((index: number) => { + const newGroups = selectedGroupsForBreadcrumb.slice(0, index + 1) + setSelectedGroupsForBreadcrumb(newGroups) + }, [setSelectedGroupsForBreadcrumb, selectedGroupsForBreadcrumb]) + const handleReset = useCallback(() => { + setSelectedGroupsForBreadcrumb([]) + }, [setSelectedGroupsForBreadcrumb]) + return
+ 0 && 'text-text-accent cursor-pointer')} onClick={handleReset}>{t('app.accessControlDialog.operateGroupAndMember.allMembers')} + {selectedGroupsForBreadcrumb.map((group, index) => { + return
+ / + handleBreadCrumbClick(index)}>{group.name} +
+ })} +
+} + type GroupItemProps = { group: AccessControlGroup } @@ -94,6 +119,8 @@ function GroupItem({ group }: GroupItemProps) { const { t } = useTranslation() const specificGroups = useAccessControlStore(s => s.specificGroups) const setSpecificGroups = useAccessControlStore(s => s.setSpecificGroups) + const selectedGroupsForBreadcrumb = useAccessControlStore(s => s.selectedGroupsForBreadcrumb) + const setSelectedGroupsForBreadcrumb = useAccessControlStore(s => s.setSelectedGroupsForBreadcrumb) const isChecked = specificGroups.some(g => g.id === group.id) const handleCheckChange = useCallback(() => { if (!isChecked) { @@ -105,6 +132,10 @@ function GroupItem({ group }: GroupItemProps) { setSpecificGroups(newGroups) } }, [specificGroups, setSpecificGroups, group, isChecked]) + + const handleExpandClick = useCallback(() => { + setSelectedGroupsForBreadcrumb([...selectedGroupsForBreadcrumb, group]) + }, [selectedGroupsForBreadcrumb, setSelectedGroupsForBreadcrumb, group]) return
@@ -116,7 +147,8 @@ function GroupItem({ group }: GroupItemProps) {

{group.name}

{group.groupSize}

- diff --git a/web/app/components/app/app-access-control/index.tsx b/web/app/components/app/app-access-control/index.tsx index 8d965561a7..a5f0aa9b2c 100644 --- a/web/app/components/app/app-access-control/index.tsx +++ b/web/app/components/app/app-access-control/index.tsx @@ -5,10 +5,10 @@ import { useTranslation } from 'react-i18next' import { useCallback, useEffect } from 'react' import Button from '../../base/button' import Toast from '../../base/toast' +import useAccessControlStore from '../../../../context/access-control-store' import AccessControlDialog from './access-control-dialog' import AccessControlItem from './access-control-item' import SpecificGroupsOrMembers, { WebAppSSONotEnabledTip } from './specific-groups-or-members' -import useAccessControlStore from './access-control-store' import { useGlobalPublicStore } from '@/context/global-public-context' import type { App } from '@/types/app' import type { Subject } from '@/models/access-control' diff --git a/web/app/components/app/app-access-control/specific-groups-or-members.tsx b/web/app/components/app/app-access-control/specific-groups-or-members.tsx index a8961eda5d..272fb3b9cb 100644 --- a/web/app/components/app/app-access-control/specific-groups-or-members.tsx +++ b/web/app/components/app/app-access-control/specific-groups-or-members.tsx @@ -6,8 +6,8 @@ import Avatar from '../../base/avatar' import Divider from '../../base/divider' import Tooltip from '../../base/tooltip' import Loading from '../../base/loading' +import useAccessControlStore from '../../../../context/access-control-store' import AddMemberOrGroupDialog from './add-member-or-group-pop' -import useAccessControlStore from './access-control-store' import { useGlobalPublicStore } from '@/context/global-public-context' import type { AccessControlAccount, AccessControlGroup } from '@/models/access-control' import { AccessMode } from '@/models/access-control' diff --git a/web/app/components/app/app-access-control/access-control-store.ts b/web/context/access-control-store.ts similarity index 78% rename from web/app/components/app/app-access-control/access-control-store.ts rename to web/context/access-control-store.ts index ebf78670e0..3a80d7c865 100644 --- a/web/app/components/app/app-access-control/access-control-store.ts +++ b/web/context/access-control-store.ts @@ -12,6 +12,8 @@ type AccessControlStore = { setSpecificMembers: (specificMembers: AccessControlAccount[]) => void currentMenu: AccessMode setCurrentMenu: (currentMenu: AccessMode) => void + selectedGroupsForBreadcrumb: AccessControlGroup[] + setSelectedGroupsForBreadcrumb: (selectedGroupsForBreadcrumb: AccessControlGroup[]) => void } const useAccessControlStore = create((set) => { @@ -24,6 +26,8 @@ const useAccessControlStore = create((set) => { setSpecificMembers: specificMembers => set({ specificMembers }), currentMenu: AccessMode.SPECIFIC_GROUPS_MEMBERS, setCurrentMenu: currentMenu => set({ currentMenu }), + selectedGroupsForBreadcrumb: [], + setSelectedGroupsForBreadcrumb: selectedGroupsForBreadcrumb => set({ selectedGroupsForBreadcrumb }), } }) diff --git a/web/i18n/en-US/common.ts b/web/i18n/en-US/common.ts index 71173e2449..8e3b4c6d21 100644 --- a/web/i18n/en-US/common.ts +++ b/web/i18n/en-US/common.ts @@ -621,7 +621,7 @@ const translation = { pagination: { perPage: 'Items per page', }, - your: 'You', + you: 'You', } export default translation diff --git a/web/i18n/ja-JP/common.ts b/web/i18n/ja-JP/common.ts index 0d66228b07..4d379b510e 100644 --- a/web/i18n/ja-JP/common.ts +++ b/web/i18n/ja-JP/common.ts @@ -622,6 +622,7 @@ const translation = { pagination: { perPage: 'ページあたりのアイテム数', }, + you: 'あなた', } export default translation diff --git a/web/service/access-control.ts b/web/service/access-control.ts index dbb72a3ae7..94b827f3d3 100644 --- a/web/service/access-control.ts +++ b/web/service/access-control.ts @@ -1,4 +1,4 @@ -import { useInfiniteQuery, useMutation, useQuery } from '@tanstack/react-query' +import { useInfiniteQuery, useMutation, useQuery, useQueryClient } from '@tanstack/react-query' import { get, post } from './base' import type { AccessControlAccount, AccessControlGroup, AccessMode, Subject } from '@/models/access-control' import type { App } from '@/types/app' @@ -20,7 +20,7 @@ type SearchResults = { hasMore: boolean } -export const useSearchForWhiteListCandidates = (query: { keyword?: string; resultsPerPage?: number }, enabled: boolean) => { +export const useSearchForWhiteListCandidates = (query: { keyword?: string; groupId?: AccessControlGroup['id']; resultsPerPage?: number }, enabled: boolean) => { return useInfiniteQuery({ queryKey: [NAME_SPACE, 'app-whitelist-candidates', query], queryFn: ({ pageParam }) => { @@ -50,10 +50,16 @@ type UpdateAccessModeParams = { } export const useUpdateAccessMode = () => { + const queryClient = useQueryClient() return useMutation({ mutationKey: [NAME_SPACE, 'update-access-mode'], mutationFn: (params: UpdateAccessModeParams) => { return post('/enterprise/webapp/app/access-mode', { body: params }) }, + onSuccess: () => { + queryClient.invalidateQueries({ + queryKey: [NAME_SPACE, 'app-whitelist-subjects'], + }) + }, }) }