Skip to content

Commit

Permalink
feat: org manage UI
Browse files Browse the repository at this point in the history
  • Loading branch information
I-Info committed Dec 19, 2024
1 parent c10ef86 commit c8865de
Show file tree
Hide file tree
Showing 8 changed files with 202 additions and 32 deletions.
5 changes: 3 additions & 2 deletions packages/global/support/user/team/org/type.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,17 @@ type OrgSchemaType = {
path: string;
name: string;
avatar: string;
description: string | undefined;
updateTime: Date;
};

type OrgMemberSchemaType = {
orgId: string | undefined;
orgId: string;
tmbId: string;
role: `${OrgMemberRole}`;
};

type OrgType = OrgSchemaType & {
members: OrgMemberSchemaType[] | undefined;
members: OrgMemberSchemaType[];
permission: TeamPermission | undefined;
};
4 changes: 4 additions & 0 deletions packages/service/support/permission/org/orgSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ export const OrgSchema = new Schema(
required: true
},
avatar: {
type: String,
default: ''
},
description: {
type: String
},
updateTime: {
Expand Down
1 change: 1 addition & 0 deletions packages/web/i18n/en/account_team.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"edit_info": "Edit information",
"group": "group",
"group_name": "Group name",
"org": "organization",
"label_sync": "Tag sync",
"leave_team_failed": "Leaving the team exception",
"manage_member": "Managing members",
Expand Down
59 changes: 30 additions & 29 deletions packages/web/i18n/zh-CN/account_team.json
Original file line number Diff line number Diff line change
@@ -1,29 +1,30 @@
{
"total_team_members": "共 {{amount}} 名成员",
"member": "成员",
"group": "群组",
"permission": "权限",
"user_name": "用户名",
"member_group": "所属成员组",
"action": "操作",
"waiting": "待接受",
"remove_tip": "确认将 {{username}} 移出团队?",

"confirm_leave_team": "确认离开该团队? \n 退出后,您在该团队所有的资源( 应用、知识库、文件夹、管理的群组等)均转让给团队所有者。",
"leave_team_failed": "离开团队异常",
"label_sync": "标签同步",
"user_team_invite_member": "邀请成员",
"user_team_leave_team": "离开团队",
"user_team_leave_team_failed": "离开团队失败",
"create_group": "创建群组",
"search_member_group_name": "搜索成员/群组名称",
"confirm_delete_group": "确认删除群组?",
"group_name": "群组名称",
"owner": "所有者",
"manage_member": "管理成员",
"edit_info": "编辑信息",

"transfer_ownership": "转让所有者",
"delete": "删除",
"retain_admin_permissions": "保留管理员权限"
}
{
"total_team_members": "共 {{amount}} 名成员",
"member": "成员",
"group": "群组",
"org": "组织",
"permission": "权限",
"user_name": "用户名",
"member_group": "所属成员组",
"action": "操作",
"waiting": "待接受",
"remove_tip": "确认将 {{username}} 移出团队?",

"confirm_leave_team": "确认离开该团队? \n 退出后,您在该团队所有的资源( 应用、知识库、文件夹、管理的群组等)均转让给团队所有者。",
"leave_team_failed": "离开团队异常",
"label_sync": "标签同步",
"user_team_invite_member": "邀请成员",
"user_team_leave_team": "离开团队",
"user_team_leave_team_failed": "离开团队失败",
"create_group": "创建群组",
"search_member_group_name": "搜索成员/群组名称",
"confirm_delete_group": "确认删除群组?",
"group_name": "群组名称",
"owner": "所有者",
"manage_member": "管理成员",
"edit_info": "编辑信息",

"transfer_ownership": "转让所有者",
"delete": "删除",
"retain_admin_permissions": "保留管理员权限"
}
1 change: 1 addition & 0 deletions packages/web/i18n/zh-Hant/account_team.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"edit_info": "編輯訊息",
"group": "群組",
"group_name": "群組名稱",
"org": "組織",
"label_sync": "標籤同步",
"leave_team_failed": "離開團隊異常",
"manage_member": "管理成員",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ function MemberTable() {
type: 'delete'
});

const { members, groups, orgs, refetchMembers, refetchGroups, refetchOrgs } = useContextSelector(
const { members, groups, refetchMembers, refetchGroups } = useContextSelector(
TeamContext,
(v) => v
);
Expand Down
158 changes: 158 additions & 0 deletions projects/app/src/pages/account/team/components/OrgManage/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
import AvatarGroup from '@fastgpt/web/components/common/Avatar/AvatarGroup';
import {
Box,
Breadcrumb,
BreadcrumbItem,
BreadcrumbLink,
Button,
HStack,
Icon,
Table,
TableContainer,
Tbody,
Td,
Text,
Th,
Thead,
Tr,
useDisclosure,
VStack
} from '@chakra-ui/react';
import { useTranslation } from 'next-i18next';
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
import MyBox from '@fastgpt/web/components/common/MyBox';
import { useContextSelector } from 'use-context-selector';
import { TeamContext } from '../context';
import MyMenu, { MenuItemType } from '@fastgpt/web/components/common/MyMenu';
import MyIcon from '@fastgpt/web/components/common/Icon';
import { useUserStore } from '@/web/support/user/useUserStore';
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
import MemberTag from '../../../../../components/support/user/team/Info/MemberTag';
import dynamic from 'next/dynamic';
import { useEffect, useMemo, useState } from 'react';
import { OrgType } from '@fastgpt/global/support/user/team/org/type';

function MoreIconButton({ onClick }: { onClick: () => void }) {
return (
<MyIcon
name="more"
w={'1rem'}
transition={'background 0.1s'}
cursor={'pointer'}
p="1"
rounded={'sm'}
_hover={{
bg: 'myGray.05',
color: 'primary.600'
}}
onClick={onClick}
/>
);
}

function MemberTable() {
const { t } = useTranslation();
const { userInfo } = useUserStore();

const { orgs, refetchOrgs, members, refetchMembers } = useContextSelector(TeamContext, (v) => v);
const [currentOrg, setCurrentOrg] = useState<OrgType | undefined>();

useEffect(() => {
setCurrentOrg(orgs[0]);
}, [setCurrentOrg, orgs]);

const currentPath = useMemo<{ path: string; parents: OrgType[] }>(
() => ({
path: currentOrg ? currentOrg.path + '/' + currentOrg._id : '',
parents: currentOrg
? currentOrg.path
.split('/')
.filter(Boolean)
.map((orgId) => orgs.find((org) => org._id === orgId)!)
: []
}),
[orgs, currentOrg]
);

return (
<VStack>
<Breadcrumb mr={'auto'}>
{currentPath.parents.map((parent) => (
<BreadcrumbItem key={parent._id}>
<BreadcrumbLink onClick={() => setCurrentOrg(parent)}>
{parent.path === '' ? userInfo?.team.teamName : parent.name}
</BreadcrumbLink>
</BreadcrumbItem>
))}
<BreadcrumbItem isCurrentPage>
<BreadcrumbLink>
{currentOrg?.path === '' ? userInfo?.team.teamName : currentOrg?.name}
</BreadcrumbLink>
</BreadcrumbItem>
</Breadcrumb>
<HStack w={'100%'} gap={'16px'}>
<TableContainer overflow={'unset'} fontSize={'sm'} flexGrow={1}>
<Table overflow={'unset'}>
<Thead>
<Tr bg={'white !important'}>
<Th bg="myGray.100" borderLeftRadius="6px">
{t('common:Name')}
</Th>
<Th bg="myGray.100" borderRightRadius="6px">
{t('common:common.Action')}
</Th>
</Tr>
</Thead>
<Tbody>
{orgs
.filter((org) => org.path === currentPath.path)
.map((org) => (
<Tr key={org._id} overflow={'unset'}>
<Td>
<HStack cursor={'pointer'} onClick={() => setCurrentOrg(org)}>
<MemberTag name={org.name} avatar={org.avatar} />
<Box>({org.members.length})</Box>
</HStack>
</Td>

<Td w={'8rem'}>
<MoreIconButton
onClick={() => {
// TODO
console.log(org._id);
}}
/>
</Td>
</Tr>
))}
{currentOrg?.members.map((member) => {
const memberInfo = members.find((m) => m.tmbId === member.tmbId);
if (!memberInfo) return null;
return (
<Tr key={member.tmbId} overflow={'unset'}>
<Td>
<MemberTag name={memberInfo.memberName} avatar={memberInfo.avatar} />
</Td>
<Td w={'8rem'}>
<MoreIconButton
onClick={() => {
// TODO
console.log(member.tmbId);
}}
/>
</Td>
</Tr>
);
})}
</Tbody>
</Table>
</TableContainer>
<VStack>
<Text>Org Metadata</Text>
</VStack>
</HStack>
</VStack>
);
}

export default MemberTable;
4 changes: 4 additions & 0 deletions projects/app/src/pages/account/team/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,13 @@ import MemberTable from './components/MemberTable';
const InviteModal = dynamic(() => import('./components/InviteModal'));
const PermissionManage = dynamic(() => import('./components/PermissionManage/index'));
const GroupManage = dynamic(() => import('./components/GroupManage/index'));
const OrgManage = dynamic(() => import('./components/OrgManage/index'));
const GroupInfoModal = dynamic(() => import('./components/GroupManage/GroupInfoModal'));
const ManageGroupMemberModal = dynamic(() => import('./components/GroupManage/GroupManageMember'));

export enum TeamTabEnum {
member = 'member',
org = 'org',
group = 'group',
permission = 'permission'
}
Expand Down Expand Up @@ -172,6 +174,7 @@ const Team = () => {
<FillRowTabs
list={[
{ label: t('account_team:member'), value: TeamTabEnum.member },
{ label: t('account_team:org'), value: TeamTabEnum.org },
{ label: t('account_team:group'), value: TeamTabEnum.group },
{ label: t('account_team:permission'), value: TeamTabEnum.permission }
]}
Expand Down Expand Up @@ -274,6 +277,7 @@ const Team = () => {
{teamTab === TeamTabEnum.group && (
<GroupManage onEditGroup={onEditGroup} onManageMember={onManageMember} />
)}
{teamTab === TeamTabEnum.org && <OrgManage />}
{teamTab === TeamTabEnum.permission && <PermissionManage />}
</Box>
</Box>
Expand Down

0 comments on commit c8865de

Please sign in to comment.