From e8ce7de71852dd7d5dc6dd52bd4623f315d7e28c Mon Sep 17 00:00:00 2001 From: NFish Date: Tue, 8 Apr 2025 18:00:55 +0800 Subject: [PATCH] wip: support add groups and members --- .../access-control-item.tsx | 15 ++-- .../access-control-store.ts | 28 +++++++ ...dialog.tsx => add-member-or-group-pop.tsx} | 28 +++++-- .../app/app-access-control/index.tsx | 26 ++++-- .../specific-groups-or-members.tsx | 83 ++++++++++++++----- web/i18n/en-US/app.ts | 7 ++ web/i18n/zh-Hans/app.ts | 7 ++ 7 files changed, 149 insertions(+), 45 deletions(-) create mode 100644 web/app/components/app/app-access-control/access-control-store.ts rename web/app/components/app/app-access-control/{add-member-or-group-dialog.tsx => add-member-or-group-pop.tsx} (80%) 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 793e942517..fe38b99a57 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,15 +1,20 @@ 'use client' import type { FC, PropsWithChildren } from 'react' +import type { AccessControlType } from './access-control-store' +import useAccessControlStore from './access-control-store' type AccessControlItemProps = PropsWithChildren<{ - active: boolean + type: AccessControlType }> -const AccessControlItem: FC = ({ active, children }) => { - if (!active) { - return
+ hover:border-components-option-card-option-border-hover hover:bg-components-option-card-option-bg-hover" + onClick={() => setCurrentMenu(type)} > {children}
} diff --git a/web/app/components/app/app-access-control/access-control-store.ts b/web/app/components/app/app-access-control/access-control-store.ts new file mode 100644 index 0000000000..e14307caba --- /dev/null +++ b/web/app/components/app/app-access-control/access-control-store.ts @@ -0,0 +1,28 @@ +import { create } from 'zustand' +export enum AccessControlType { + PUBLIC = 'PUBLIC', + SPECIFIC_GROUPS_MEMBERS = 'SPECIFIC_GROUPS_MEMBERS', + ORGANIZATION = 'ORGANIZATION', +} + +type AccessControlStore = { + specificGroups: [] + setSpecificGroups: (specificGroups: []) => void + specificMembers: [] + setSpecificMembers: (specificMembers: []) => void + currentMenu: AccessControlType + setCurrentMenu: (currentMenu: AccessControlType) => void +} + +const useAccessControlStore = create((set) => { + return { + specificGroups: [], + setSpecificGroups: specificGroups => set({ specificGroups }), + specificMembers: [], + setSpecificMembers: specificMembers => set({ specificMembers }), + currentMenu: AccessControlType.SPECIFIC_GROUPS_MEMBERS, + setCurrentMenu: currentMenu => set({ currentMenu }), + } +}) + +export default useAccessControlStore diff --git a/web/app/components/app/app-access-control/add-member-or-group-dialog.tsx b/web/app/components/app/app-access-control/add-member-or-group-pop.tsx similarity index 80% rename from web/app/components/app/app-access-control/add-member-or-group-dialog.tsx rename to web/app/components/app/app-access-control/add-member-or-group-pop.tsx index a19bacdd4b..950519e02b 100644 --- a/web/app/components/app/app-access-control/add-member-or-group-dialog.tsx +++ b/web/app/components/app/app-access-control/add-member-or-group-pop.tsx @@ -23,21 +23,33 @@ export default function AddMemberOrGroupDialog() {
- +
- All Members -
-
- - + {t('app.accessControlDialog.operateGroupAndMember.allMembers')}
+
} +type RenderGroupOrMemberProps = { + data: any[] +} + +function RenderGroupOrMember({ data }: RenderGroupOrMemberProps) { + return
+ {data.map((item, index) => { + if (item.type === 'group') + return + return + })} +
+} + function GroupItem() { + const { t } = useTranslation() return
@@ -49,8 +61,8 @@ function GroupItem() {

Name

5

-
diff --git a/web/app/components/app/app-access-control/index.tsx b/web/app/components/app/app-access-control/index.tsx index 66109a0083..db9b876fd0 100644 --- a/web/app/components/app/app-access-control/index.tsx +++ b/web/app/components/app/app-access-control/index.tsx @@ -5,7 +5,9 @@ import { useTranslation } from 'react-i18next' import Button from '../../base/button' import AccessControlDialog from './access-control-dialog' import AccessControlItem from './access-control-item' -import SpecificGroupsOrMembers from './specific-groups-or-members' +import SpecificGroupsOrMembers, { WebAppSSONotEnabledTip } from './specific-groups-or-members' +import { AccessControlType } from './access-control-store' +import { useGlobalPublicStore } from '@/context/global-public-context' type AccessControlProps = { onClose: () => void @@ -13,6 +15,9 @@ type AccessControlProps = { export default function AccessControl(props: AccessControlProps) { const { t } = useTranslation() + const systemFeatures = useGlobalPublicStore(s => s.systemFeatures) + const hideTip = systemFeatures.enable_web_sso_switch_component && systemFeatures.sso_enforced_for_web + return
@@ -23,17 +28,20 @@ export default function AccessControl(props: AccessControlProps) {

{t('app.accessControlDialog.accessLabel')}

- -
- -

{t('app.accessControlDialog.accessItems.organization')}

+ +
+
+ +

{t('app.accessControlDialog.accessItems.organization')}

+
+ {!hideTip && }
- - + + - -
+ +

{t('app.accessControlDialog.accessItems.anyone')}

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 21d4d1a802..42fd384d7a 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 @@ -1,20 +1,26 @@ 'use client' -import { RiCloseCircleFill, RiLockLine, RiOrganizationChart } from '@remixicon/react' +import { RiAlertFill, RiCloseCircleFill, RiLockLine, RiOrganizationChart } from '@remixicon/react' import { useTranslation } from 'react-i18next' import Avatar from '../../base/avatar' -import AddMemberOrGroupDialog from './add-member-or-group-dialog' +import Divider from '../../base/divider' +import Tooltip from '../../base/tooltip' +import AddMemberOrGroupDialog from './add-member-or-group-pop' +import useAccessControlStore, { AccessControlType } from './access-control-store' +import { useGlobalPublicStore } from '@/context/global-public-context' -type SpecificGroupsOrMembersProps = { - active: boolean -} - -export default function SpecificGroupsOrMembers(props: SpecificGroupsOrMembersProps) { - const { active } = props +export default function SpecificGroupsOrMembers() { + const currentMenu = useAccessControlStore(s => s.currentMenu) const { t } = useTranslation() - if (!active) { - return
- -

{t('app.accessControlDialog.accessItems.specific')}

+ const systemFeatures = useGlobalPublicStore(s => s.systemFeatures) + const hideTip = systemFeatures.enable_web_sso_switch_component && systemFeatures.sso_enforced_for_web + + if (currentMenu !== AccessControlType.SPECIFIC_GROUPS_MEMBERS) { + return
+
+ +

{t('app.accessControlDialog.accessItems.specific')}

+
+ {!hideTip && }
} @@ -24,30 +30,54 @@ export default function SpecificGroupsOrMembers(props: SpecificGroupsOrMembersPr

{t('app.accessControlDialog.accessItems.specific')}

- +
+ {!hideTip && <> + + + } + +
-

{t('app.accessControlDialog.groups', { count: 1 })}

-
- -
-

{t('app.accessControlDialog.members', { count: 4 })}

-
- -
+
} -function GroupItem() { + +function RenderGroupsAndMembers() { + const { t } = useTranslation() + const specificGroups = useAccessControlStore(s => s.specificGroups) + const specificMembers = useAccessControlStore(s => s.specificMembers) + if (specificGroups.length <= 0 && specificMembers.length <= 0) + return

{t('app.accessControlDialog.noGroupsOrMembers')}

+ return <> +

{t('app.accessControlDialog.groups', { count: specificGroups.length ?? 0 })}

+
+ {specificGroups.map((group, index) => )} +
+

{t('app.accessControlDialog.members', { count: specificMembers.length ?? 0 })}

+
+ {specificMembers.map((member, index) => )} +
+ +} + +type GroupItemProps = { + group: string +} +function GroupItem({ group }: GroupItemProps) { return }>

Group Name

7

} -function MemberItem() { +type MemberItemProps = { + member: string +} +function MemberItem({ member }: MemberItemProps) { return }>

Member Name

@@ -70,3 +100,10 @@ function BaseItem({ icon, children }: BaseItemProps) {
} + +export function WebAppSSONotEnabledTip() { + const { t } = useTranslation() + return + + +} diff --git a/web/i18n/en-US/app.ts b/web/i18n/en-US/app.ts index 93c79c8ad8..dac0fb245c 100644 --- a/web/i18n/en-US/app.ts +++ b/web/i18n/en-US/app.ts @@ -188,6 +188,13 @@ const translation = { groups_other: '{{count}} GROUPS', members_one: '{{count}} MEMBER', members_other: '{{count}} MEMBERS', + noGroupsOrMembers: 'No access members have been added yet', + webAppSSONotEnabledTip: 'Please contact the administrator to enable the WebApp identity authentication method.', + operateGroupAndMember: { + searchPlaceholder: 'Search groups and members', + allMembers: 'All members', + expand: 'Expand', + }, }, } diff --git a/web/i18n/zh-Hans/app.ts b/web/i18n/zh-Hans/app.ts index f44a97fc18..ddb731357c 100644 --- a/web/i18n/zh-Hans/app.ts +++ b/web/i18n/zh-Hans/app.ts @@ -189,6 +189,13 @@ const translation = { groups_other: '{{count}} 个组', members_one: '{{count}} 个人', members_other: '{{count}} 个人', + noGroupsOrMembers: '没有添加组或成员', + webAppSSONotEnabledTip: '请联系管理员启用 WebApp SSO 身份验证方式。', + operateGroupAndMember: { + searchPlaceholder: '搜索组或成员', + allMembers: '所有成员', + expand: '展开', + }, }, }