From aa409a462349da2b239b517663d00e5f9e09f11d Mon Sep 17 00:00:00 2001 From: Rohit Kumar Date: Mon, 6 Apr 2026 21:40:01 +0530 Subject: [PATCH 1/3] [Community][Admin] Member Management Page Fixes #94 --- .../member-add-modal.container.graphql | 23 + .../components/member-add-modal.container.tsx | 52 +++ .../components/member-add-modal.stories.tsx | 32 ++ .../admin/components/member-add-modal.tsx | 90 ++++ .../components/member-list.container.graphql | 37 ++ .../components/member-list.container.tsx | 72 +++ .../admin/components/member-list.stories.tsx | 101 +++++ .../layouts/admin/components/member-list.tsx | 180 ++++++++ .../src/components/layouts/admin/index.tsx | 14 +- .../layouts/admin/pages/members.tsx | 19 + .../contexts/community/member/add-member.ts | 44 ++ .../src/contexts/community/member/index.ts | 12 + .../community/member/query-by-community-id.ts | 12 + .../community/member/remove-member.ts | 21 + .../community/member/update-member-role.ts | 25 ++ .../community/member/features/member.feature | 15 + .../contexts/community/member/member.test.ts | 46 ++ .../contexts/community/member/member.ts | 12 + .../domain/src/domain/events/types/index.ts | 2 + .../src/domain/events/types/member-added.ts | 9 + .../src/domain/events/types/member-removed.ts | 8 + .../types/features/member.resolvers.feature | 47 ++ .../graphql/src/schema/types/member.graphql | 30 +- .../src/schema/types/member.resolvers.test.ts | 415 ++++++++++++++++++ .../src/schema/types/member.resolvers.ts | 65 ++- 25 files changed, 1380 insertions(+), 3 deletions(-) create mode 100644 apps/ui-community/src/components/layouts/admin/components/member-add-modal.container.graphql create mode 100644 apps/ui-community/src/components/layouts/admin/components/member-add-modal.container.tsx create mode 100644 apps/ui-community/src/components/layouts/admin/components/member-add-modal.stories.tsx create mode 100644 apps/ui-community/src/components/layouts/admin/components/member-add-modal.tsx create mode 100644 apps/ui-community/src/components/layouts/admin/components/member-list.container.graphql create mode 100644 apps/ui-community/src/components/layouts/admin/components/member-list.container.tsx create mode 100644 apps/ui-community/src/components/layouts/admin/components/member-list.stories.tsx create mode 100644 apps/ui-community/src/components/layouts/admin/components/member-list.tsx create mode 100644 apps/ui-community/src/components/layouts/admin/pages/members.tsx create mode 100644 packages/ocom/application-services/src/contexts/community/member/add-member.ts create mode 100644 packages/ocom/application-services/src/contexts/community/member/query-by-community-id.ts create mode 100644 packages/ocom/application-services/src/contexts/community/member/remove-member.ts create mode 100644 packages/ocom/application-services/src/contexts/community/member/update-member-role.ts create mode 100644 packages/ocom/domain/src/domain/events/types/member-added.ts create mode 100644 packages/ocom/domain/src/domain/events/types/member-removed.ts diff --git a/apps/ui-community/src/components/layouts/admin/components/member-add-modal.container.graphql b/apps/ui-community/src/components/layouts/admin/components/member-add-modal.container.graphql new file mode 100644 index 000000000..2e8c581c4 --- /dev/null +++ b/apps/ui-community/src/components/layouts/admin/components/member-add-modal.container.graphql @@ -0,0 +1,23 @@ +mutation AdminMemberAddContainerMemberAdd($input: MemberAddInput!) { + memberAdd(input: $input) { + status { + success + errorMessage + } + member { + ...AdminMemberAddContainerMemberFields + } + } +} + +fragment AdminMemberAddContainerMemberFields on Member { + id + memberName + accounts { + id + firstName + lastName + statusCode + } + createdAt +} diff --git a/apps/ui-community/src/components/layouts/admin/components/member-add-modal.container.tsx b/apps/ui-community/src/components/layouts/admin/components/member-add-modal.container.tsx new file mode 100644 index 000000000..3b7ceb00d --- /dev/null +++ b/apps/ui-community/src/components/layouts/admin/components/member-add-modal.container.tsx @@ -0,0 +1,52 @@ +import { App } from 'antd'; +import { useMutation } from '@apollo/client'; +import { AdminMemberAddContainerMemberAddDocument, AdminMemberListContainerMembersByCommunityIdDocument } from '../../../../generated.tsx'; +import { MemberAddModal } from './member-add-modal.tsx'; + +export interface MemberAddModalContainerProps { + communityId: string; + open: boolean; + onClose: () => void; +} + +export const MemberAddModalContainer: React.FC = ({ communityId, open, onClose }) => { + const { message } = App.useApp(); + + const [addMember, { loading }] = useMutation(AdminMemberAddContainerMemberAddDocument, { + refetchQueries: [{ query: AdminMemberListContainerMembersByCommunityIdDocument, variables: { communityId } }], + }); + + const handleAdd = async (values: { memberName: string; firstName: string; lastName?: string; userExternalId: string }) => { + try { + const result = await addMember({ + variables: { + input: { + communityId, + memberName: values.memberName, + firstName: values.firstName, + lastName: values.lastName, + userExternalId: values.userExternalId, + }, + }, + }); + if (result.data?.memberAdd?.status?.success) { + void message.success('Member added successfully'); + onClose(); + } else { + void message.error(result.data?.memberAdd?.status?.errorMessage ?? 'Failed to add member'); + } + } catch (error) { + void message.error((error as Error).message ?? 'Failed to add member'); + } + }; + + return ( + + ); +}; diff --git a/apps/ui-community/src/components/layouts/admin/components/member-add-modal.stories.tsx b/apps/ui-community/src/components/layouts/admin/components/member-add-modal.stories.tsx new file mode 100644 index 000000000..a58a66fd6 --- /dev/null +++ b/apps/ui-community/src/components/layouts/admin/components/member-add-modal.stories.tsx @@ -0,0 +1,32 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import { fn } from 'storybook/test'; +import { MemberAddModal } from './member-add-modal.tsx'; + +const meta: Meta = { + title: 'Admin/MemberAddModal', + component: MemberAddModal, + args: { + communityId: 'community-123', + open: true, + loading: false, + onAdd: fn(), + onCancel: fn(), + }, +}; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; + +export const Loading: Story = { + args: { + loading: true, + }, +}; + +export const Closed: Story = { + args: { + open: false, + }, +}; diff --git a/apps/ui-community/src/components/layouts/admin/components/member-add-modal.tsx b/apps/ui-community/src/components/layouts/admin/components/member-add-modal.tsx new file mode 100644 index 000000000..5ee072e8c --- /dev/null +++ b/apps/ui-community/src/components/layouts/admin/components/member-add-modal.tsx @@ -0,0 +1,90 @@ +import { Button, Form, Input, Modal } from 'antd'; + +export interface MemberAddModalProps { + communityId: string; + open: boolean; + loading?: boolean; + onAdd: (values: { memberName: string; firstName: string; lastName?: string; userExternalId: string }) => void; + onCancel: () => void; +} + +interface MemberAddFormValues { + memberName: string; + firstName: string; + lastName?: string; + userExternalId: string; +} + +export const MemberAddModal: React.FC = ({ open, loading, onAdd, onCancel }) => { + const [form] = Form.useForm(); + + const handleOk = () => { + form.validateFields().then((values) => { + onAdd(values); + form.resetFields(); + }); + }; + + const handleCancel = () => { + form.resetFields(); + onCancel(); + }; + + return ( + + Cancel + , + , + ]} + > +
+ + + + + + + + + + + + +
+
+ ); +}; diff --git a/apps/ui-community/src/components/layouts/admin/components/member-list.container.graphql b/apps/ui-community/src/components/layouts/admin/components/member-list.container.graphql new file mode 100644 index 000000000..e31dec273 --- /dev/null +++ b/apps/ui-community/src/components/layouts/admin/components/member-list.container.graphql @@ -0,0 +1,37 @@ +query AdminMemberListContainerMembersByCommunityId($communityId: ObjectID!) { + membersByCommunityId(communityId: $communityId) { + ...AdminMemberListContainerMemberFields + } +} + +mutation AdminMemberListContainerMemberRemove($input: MemberRemoveInput!) { + memberRemove(input: $input) { + status { + success + errorMessage + } + member { + ...AdminMemberListContainerMemberFields + } + } +} + +fragment AdminMemberListContainerMemberFields on Member { + id + memberName + isAdmin + createdAt + updatedAt + profile { + name + email + avatarDocumentId + } + accounts { + id + firstName + lastName + statusCode + createdAt + } +} diff --git a/apps/ui-community/src/components/layouts/admin/components/member-list.container.tsx b/apps/ui-community/src/components/layouts/admin/components/member-list.container.tsx new file mode 100644 index 000000000..95f799811 --- /dev/null +++ b/apps/ui-community/src/components/layouts/admin/components/member-list.container.tsx @@ -0,0 +1,72 @@ +import { App } from 'antd'; +import { useMutation, useQuery } from '@apollo/client'; +import { ComponentQueryLoader } from '@cellix/ui-core'; +import { useState } from 'react'; +import { useParams } from 'react-router-dom'; +import type { AdminMemberListContainerMemberFieldsFragment } from '../../../../generated.tsx'; +import { AdminMemberListContainerMemberRemoveDocument, AdminMemberListContainerMembersByCommunityIdDocument } from '../../../../generated.tsx'; +import { MemberList, type MemberListProps } from './member-list.tsx'; +import { MemberAddModalContainer } from './member-add-modal.container.tsx'; + +export const MemberListContainer: React.FC = () => { + const { message } = App.useApp(); + const params = useParams(); + // biome-ignore lint:useLiteralKeys + const communityId = params['communityId'] ?? ''; + const [addModalOpen, setAddModalOpen] = useState(false); + + const { + data: membersData, + loading: membersLoading, + error: membersError, + } = useQuery(AdminMemberListContainerMembersByCommunityIdDocument, { + variables: { communityId }, + skip: !communityId, + }); + + const [removeMember, { loading: removeLoading }] = useMutation(AdminMemberListContainerMemberRemoveDocument, { + refetchQueries: [{ query: AdminMemberListContainerMembersByCommunityIdDocument, variables: { communityId } }], + }); + + const handleRemove = async (memberId: string) => { + try { + const result = await removeMember({ variables: { input: { memberId } } }); + if (result.data?.memberRemove?.status?.success) { + void message.success('Member removed successfully'); + } else { + void message.error(result.data?.memberRemove?.status?.errorMessage ?? 'Failed to remove member'); + } + } catch (error) { + void message.error((error as Error).message ?? 'Failed to remove member'); + } + }; + + const memberListProps: MemberListProps = { + data: (membersData?.membersByCommunityId ?? []) as AdminMemberListContainerMemberFieldsFragment[], + onAdd: () => setAddModalOpen(true), + onRemove: handleRemove, + removeLoading, + }; + + return ( + <> + } + error={membersError} + noDataComponent={ + setAddModalOpen(true)} + /> + } + /> + setAddModalOpen(false)} + /> + + ); +}; diff --git a/apps/ui-community/src/components/layouts/admin/components/member-list.stories.tsx b/apps/ui-community/src/components/layouts/admin/components/member-list.stories.tsx new file mode 100644 index 000000000..b11353596 --- /dev/null +++ b/apps/ui-community/src/components/layouts/admin/components/member-list.stories.tsx @@ -0,0 +1,101 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import { fn } from 'storybook/test'; +import { expect, userEvent, within } from 'storybook/test'; +import type { AdminMemberListContainerMemberFieldsFragment } from '../../../../generated.tsx'; +import { MemberList } from './member-list.tsx'; + +const makeMember = (id: string, name: string, email: string, statusCode: string, isAdmin: boolean, createdAt = '2024-01-15T00:00:00.000Z'): AdminMemberListContainerMemberFieldsFragment => ({ + __typename: 'Member', + id, + memberName: name, + isAdmin, + createdAt, + updatedAt: createdAt, + profile: { __typename: 'MemberProfile', name, email, avatarDocumentId: null }, + accounts: [ + { + __typename: 'MemberAccount', + id: `${id}-account`, + firstName: name.split(' ')[0] ?? name, + lastName: name.split(' ')[1] ?? null, + statusCode, + createdAt, + }, + ], +}); + +const mockMembers: AdminMemberListContainerMemberFieldsFragment[] = [ + makeMember('m1', 'Alice Johnson', 'alice@example.com', 'active', true), + makeMember('m2', 'Bob Smith', 'bob@example.com', 'active', false), + makeMember('m3', 'Carol White', 'carol@example.com', 'inactive', false), + makeMember('m4', 'David Brown', 'david@example.com', 'active', false), +]; + +const meta = { + title: 'Components/Layouts/Admin/MemberList', + component: MemberList, + parameters: { + layout: 'padded', + }, + args: { + onAdd: fn(), + onRemove: fn(), + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + data: mockMembers, + }, + play: ({ canvasElement }) => { + const canvas = within(canvasElement); + expect(canvas.getAllByTestId('member-row')).toHaveLength(4); + expect(canvas.getByTestId('member-search')).toBeInTheDocument(); + expect(canvas.getByTestId('member-add-btn')).toBeInTheDocument(); + }, +}; + +export const Empty: Story = { + args: { + data: [], + }, + play: ({ canvasElement }) => { + const canvas = within(canvasElement); + expect(canvas.getByText('No members found')).toBeInTheDocument(); + }, +}; + +export const WithSearch: Story = { + args: { + data: mockMembers, + }, + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + const searchInput = canvas.getByTestId('member-search'); + await userEvent.type(searchInput, 'alice'); + expect(canvas.getAllByTestId('member-row')).toHaveLength(1); + }, +}; + +export const AdminOnly: Story = { + args: { + data: [makeMember('m1', 'Admin User', 'admin@example.com', 'active', true)], + }, + play: ({ canvasElement }) => { + const canvas = within(canvasElement); + expect(canvas.getByTestId('member-role')).toHaveTextContent('Admin'); + }, +}; + +export const WithRemoveAction: Story = { + args: { + data: mockMembers, + }, + play: ({ canvasElement }) => { + const canvas = within(canvasElement); + expect(canvas.getAllByTestId('member-remove-btn')).toHaveLength(4); + }, +}; diff --git a/apps/ui-community/src/components/layouts/admin/components/member-list.tsx b/apps/ui-community/src/components/layouts/admin/components/member-list.tsx new file mode 100644 index 000000000..57a6c7070 --- /dev/null +++ b/apps/ui-community/src/components/layouts/admin/components/member-list.tsx @@ -0,0 +1,180 @@ +import { CheckCircleOutlined, CloseCircleOutlined, DeleteOutlined, PlusOutlined, SearchOutlined, UserOutlined } from '@ant-design/icons'; +import { Avatar, Button, Input, Popconfirm, Table, type TableProps, Tag, Typography, theme } from 'antd'; +import { useMemo, useState } from 'react'; +import type { AdminMemberListContainerMemberFieldsFragment } from '../../../../generated.tsx'; + +const { Text } = Typography; + +export interface MemberListProps { + data: AdminMemberListContainerMemberFieldsFragment[]; + onAdd?: () => void; + onRemove?: (memberId: string) => void; + removeLoading?: boolean; +} + +type MemberRow = AdminMemberListContainerMemberFieldsFragment & { key: string }; + +export const MemberList: React.FC = (props) => { + const [searchText, setSearchText] = useState(''); + const { + token: { colorTextSecondary }, + } = theme.useToken(); + + const filteredData = useMemo((): MemberRow[] => { + const lower = searchText.toLowerCase(); + return props.data + .filter((m) => { + const name = (m.memberName ?? '').toLowerCase(); + const email = (m.profile?.email ?? '').toLowerCase(); + return name.includes(lower) || email.includes(lower); + }) + .map((m) => ({ ...m, key: m.id })); + }, [props.data, searchText]); + + const primaryAccount = (member: AdminMemberListContainerMemberFieldsFragment) => member.accounts[0]; + + const columns: TableProps['columns'] = [ + { + title: 'Member', + key: 'member', + render: (_: unknown, record: MemberRow) => { + const account = primaryAccount(record); + const displayName = record.memberName ?? (account ? `${account.firstName} ${account.lastName ?? ''}`.trim() : '—'); + return ( +
+ } + size="small" + /> + {displayName} +
+ ); + }, + }, + { + title: 'Email', + key: 'email', + render: (_: unknown, record: MemberRow) => ( + + {record.profile?.email ?? '—'} + + ), + }, + { + title: 'Status', + key: 'status', + render: (_: unknown, record: MemberRow) => { + const statusCode = primaryAccount(record)?.statusCode; + if (!statusCode) return ; + const isActive = statusCode.toLowerCase() === 'active'; + return ( + : } + color={isActive ? 'success' : 'default'} + data-testid="member-status" + > + {statusCode} + + ); + }, + }, + { + title: 'Role', + key: 'isAdmin', + render: (_: unknown, record: MemberRow) => + record.isAdmin ? ( + + Admin + + ) : ( + + Member + + ), + }, + { + title: 'Joined', + key: 'createdAt', + render: (_: unknown, record: MemberRow) => ( + + {record.createdAt ? new Date(record.createdAt as string).toLocaleDateString() : '—'} + + ), + }, + ...(props.onRemove + ? [ + { + title: 'Actions', + key: 'actions', + render: (_: unknown, record: MemberRow) => ( + props.onRemove?.(record.id)} + okText="Remove" + cancelText="Cancel" + okButtonProps={{ danger: true, loading: props.removeLoading }} + > + + + ), + }, + ] + : []), + ]; + + return ( +
+
+ } + value={searchText} + onChange={(e) => setSearchText(e.target.value)} + allowClear + data-testid="member-search" + className="max-w-xs" + /> + {props.onAdd && ( + + )} +
+ + + ); +}; diff --git a/apps/ui-community/src/components/layouts/admin/index.tsx b/apps/ui-community/src/components/layouts/admin/index.tsx index 07b046e10..f18af0f3a 100644 --- a/apps/ui-community/src/components/layouts/admin/index.tsx +++ b/apps/ui-community/src/components/layouts/admin/index.tsx @@ -1,7 +1,8 @@ -import { HomeOutlined, SettingOutlined } from '@ant-design/icons'; +import { HomeOutlined, SettingOutlined, TeamOutlined } from '@ant-design/icons'; import { Route, Routes } from 'react-router-dom'; import type { Member } from '../../../generated.tsx'; import { Home } from './pages/home.tsx'; +import { Members } from './pages/members.tsx'; import { Settings } from './pages/settings.tsx'; import { SectionLayoutContainer } from './section-layout.container.tsx'; @@ -22,6 +23,13 @@ export const Admin: React.FC = () => { icon: , id: 'ROOT', }, + { + path: '/community/:communityId/admin/:memberId/members', + title: 'Members', + icon: , + id: 3, + parent: 'ROOT', + }, { path: '/community/:communityId/admin/:memberId/settings/*', title: 'Settings', @@ -44,6 +52,10 @@ export const Admin: React.FC = () => { path="" element={} /> + } + /> } diff --git a/apps/ui-community/src/components/layouts/admin/pages/members.tsx b/apps/ui-community/src/components/layouts/admin/pages/members.tsx new file mode 100644 index 000000000..8dac9a873 --- /dev/null +++ b/apps/ui-community/src/components/layouts/admin/pages/members.tsx @@ -0,0 +1,19 @@ +import { PageHeader } from '@ant-design/pro-layout'; +import { theme } from 'antd'; +import { MemberListContainer } from '../components/member-list.container.tsx'; +import { SubPageLayout } from '../sub-page-layout.tsx'; + +export const Members: React.FC = () => { + const { + token: { colorTextBase }, + } = theme.useToken(); + + return ( + Members} />} + > + + + ); +}; diff --git a/packages/ocom/application-services/src/contexts/community/member/add-member.ts b/packages/ocom/application-services/src/contexts/community/member/add-member.ts new file mode 100644 index 000000000..dbb3b02c9 --- /dev/null +++ b/packages/ocom/application-services/src/contexts/community/member/add-member.ts @@ -0,0 +1,44 @@ +import type { Domain } from '@ocom/domain'; +import type { DataSources } from '@ocom/persistence'; + +export interface MemberAddCommand { + communityId: string; + memberName: string; + firstName: string; + lastName?: string; + userExternalId: string; + createdByExternalId: string; +} + +export const addMember = (dataSources: DataSources) => { + return async (command: MemberAddCommand): Promise => { + const user = await dataSources.readonlyDataSource.User.EndUser.EndUserReadRepo.getByExternalId(command.userExternalId); + if (!user) { + throw new Error(`End user not found for external id ${command.userExternalId}`); + } + const createdBy = await dataSources.readonlyDataSource.User.EndUser.EndUserReadRepo.getByExternalId(command.createdByExternalId); + if (!createdBy) { + throw new Error(`Admin user not found for external id ${command.createdByExternalId}`); + } + const community = await dataSources.readonlyDataSource.Community.Community.CommunityReadRepo.getById(command.communityId); + if (!community) { + throw new Error(`Community not found for id ${command.communityId}`); + } + + let memberToReturn: Domain.Contexts.Community.Member.MemberEntityReference | undefined; + await dataSources.domainDataSource.Community.Member.MemberUnitOfWork.withScopedTransaction(async (repo) => { + const newMember = await repo.getNewInstance(command.memberName, community as Domain.Contexts.Community.Community.CommunityEntityReference); + const newAccount = newMember.requestNewAccount(); + newAccount.createdBy = createdBy; + newAccount.firstName = command.firstName; + newAccount.lastName = command.lastName ?? ''; + newAccount.statusCode = 'CREATED'; + newAccount.user = user; + memberToReturn = await repo.save(newMember); + }); + if (!memberToReturn) { + throw new Error('Member not created'); + } + return memberToReturn; + }; +}; diff --git a/packages/ocom/application-services/src/contexts/community/member/index.ts b/packages/ocom/application-services/src/contexts/community/member/index.ts index 7360e1f40..4833f6ea0 100644 --- a/packages/ocom/application-services/src/contexts/community/member/index.ts +++ b/packages/ocom/application-services/src/contexts/community/member/index.ts @@ -2,15 +2,27 @@ import type { Domain } from '@ocom/domain'; import type { DataSources } from '@ocom/persistence'; import { type MemberQueryByEndUserExternalIdCommand, queryByEndUserExternalId } from './query-by-end-user-external-id.ts'; import { determineIfAdmin, type MemberDetermineIfAdminCommand } from './determine-if-admin.ts'; +import { type MemberQueryByCommunityIdCommand, queryByCommunityId } from './query-by-community-id.ts'; +import { addMember, type MemberAddCommand } from './add-member.ts'; +import { removeMember, type MemberRemoveCommand } from './remove-member.ts'; +import { updateMemberRole, type MemberRoleUpdateCommand } from './update-member-role.ts'; export interface MemberApplicationService { determineIfAdmin: (command: MemberDetermineIfAdminCommand) => Promise; queryByEndUserExternalId: (command: MemberQueryByEndUserExternalIdCommand) => Promise; + queryByCommunityId: (command: MemberQueryByCommunityIdCommand) => Promise; + addMember: (command: MemberAddCommand) => Promise; + removeMember: (command: MemberRemoveCommand) => Promise; + updateMemberRole: (command: MemberRoleUpdateCommand) => Promise; } export const Member = (dataSources: DataSources): MemberApplicationService => { return { determineIfAdmin: determineIfAdmin(dataSources), queryByEndUserExternalId: queryByEndUserExternalId(dataSources), + queryByCommunityId: queryByCommunityId(dataSources), + addMember: addMember(dataSources), + removeMember: removeMember(dataSources), + updateMemberRole: updateMemberRole(dataSources), }; }; diff --git a/packages/ocom/application-services/src/contexts/community/member/query-by-community-id.ts b/packages/ocom/application-services/src/contexts/community/member/query-by-community-id.ts new file mode 100644 index 000000000..e65025263 --- /dev/null +++ b/packages/ocom/application-services/src/contexts/community/member/query-by-community-id.ts @@ -0,0 +1,12 @@ +import type { Domain } from '@ocom/domain'; +import type { DataSources } from '@ocom/persistence'; + +export interface MemberQueryByCommunityIdCommand { + communityId: string; +} + +export const queryByCommunityId = (dataSources: DataSources) => { + return async (command: MemberQueryByCommunityIdCommand): Promise => { + return await dataSources.readonlyDataSource.Community.Member.MemberReadRepo.getByCommunityId(command.communityId); + }; +}; diff --git a/packages/ocom/application-services/src/contexts/community/member/remove-member.ts b/packages/ocom/application-services/src/contexts/community/member/remove-member.ts new file mode 100644 index 000000000..357289b09 --- /dev/null +++ b/packages/ocom/application-services/src/contexts/community/member/remove-member.ts @@ -0,0 +1,21 @@ +import type { Domain } from '@ocom/domain'; +import type { DataSources } from '@ocom/persistence'; + +export interface MemberRemoveCommand { + memberId: string; +} + +export const removeMember = (dataSources: DataSources) => { + return async (command: MemberRemoveCommand): Promise => { + let memberToReturn: Domain.Contexts.Community.Member.MemberEntityReference | undefined; + await dataSources.domainDataSource.Community.Member.MemberUnitOfWork.withScopedTransaction(async (repo) => { + const member = await repo.getById(command.memberId); + member.requestDelete(); + memberToReturn = await repo.save(member); + }); + if (!memberToReturn) { + throw new Error('Member not found'); + } + return memberToReturn; + }; +}; diff --git a/packages/ocom/application-services/src/contexts/community/member/update-member-role.ts b/packages/ocom/application-services/src/contexts/community/member/update-member-role.ts new file mode 100644 index 000000000..9a648ea18 --- /dev/null +++ b/packages/ocom/application-services/src/contexts/community/member/update-member-role.ts @@ -0,0 +1,25 @@ +import type { Domain } from '@ocom/domain'; +import type { DataSources } from '@ocom/persistence'; + +export interface MemberRoleUpdateCommand { + memberId: string; + roleId: string; +} + +export const updateMemberRole = (dataSources: DataSources) => { + return async (command: MemberRoleUpdateCommand): Promise => { + let memberToReturn: Domain.Contexts.Community.Member.MemberEntityReference | undefined; + await dataSources.domainDataSource.Community.Role.EndUserRole.EndUserRoleUnitOfWork.withScopedTransaction(async (roleRepo) => { + const role = await roleRepo.getById(command.roleId); + await dataSources.domainDataSource.Community.Member.MemberUnitOfWork.withScopedTransaction(async (memberRepo) => { + const member = await memberRepo.getById(command.memberId); + member.role = role as Domain.Contexts.Community.Role.EndUserRole.EndUserRoleEntityReference; + memberToReturn = await memberRepo.save(member); + }); + }); + if (!memberToReturn) { + throw new Error('Member not found'); + } + return memberToReturn; + }; +}; diff --git a/packages/ocom/domain/src/domain/contexts/community/member/features/member.feature b/packages/ocom/domain/src/domain/contexts/community/member/features/member.feature index 6fd619bc8..76f4bd5fa 100644 --- a/packages/ocom/domain/src/domain/contexts/community/member/features/member.feature +++ b/packages/ocom/domain/src/domain/contexts/community/member/features/member.feature @@ -152,6 +152,21 @@ Feature: Member When I try to call requestRemoveCustomView with a valid MemberCustomView Then a PermissionError should be thrown + Scenario: Deleting a member with permission to manage members + Given a Member aggregate with permission to manage members + When I call requestDelete + Then the member should be marked as deleted + + Scenario: Deleting a member with system account permission + Given a Member aggregate with system account permission + When I call requestDelete + Then the member should be marked as deleted + + Scenario: Deleting a member without permission + Given a Member aggregate without permission to manage members or system account + When I try to call requestDelete + Then a PermissionError should be thrown + Scenario: Getting profile, accounts, customViews, createdAt, updatedAt, and schemaVersion Given a Member aggregate Then the profile property should return a MemberProfile entity diff --git a/packages/ocom/domain/src/domain/contexts/community/member/member.test.ts b/packages/ocom/domain/src/domain/contexts/community/member/member.test.ts index 95d0fe438..846eb1cc6 100644 --- a/packages/ocom/domain/src/domain/contexts/community/member/member.test.ts +++ b/packages/ocom/domain/src/domain/contexts/community/member/member.test.ts @@ -659,6 +659,52 @@ test.for(feature, ({ Scenario, Background, BeforeEachScenario }) => { }); }); + Scenario('Deleting a member with permission to manage members', ({ Given, When, Then }) => { + Given('a Member aggregate with permission to manage members', () => { + passport = makePassport({ canManageMembers: true }); + baseProps = makeBaseProps(); + member = new Member(baseProps, passport); + }); + When('I call requestDelete', () => { + member.requestDelete(); + }); + Then('the member should be marked as deleted', () => { + expect(member.isDeleted).toBe(true); + }); + }); + + Scenario('Deleting a member with system account permission', ({ Given, When, Then }) => { + Given('a Member aggregate with system account permission', () => { + passport = makePassport({ isSystemAccount: true }); + baseProps = makeBaseProps(); + member = new Member(baseProps, passport); + }); + When('I call requestDelete', () => { + member.requestDelete(); + }); + Then('the member should be marked as deleted', () => { + expect(member.isDeleted).toBe(true); + }); + }); + + Scenario('Deleting a member without permission', ({ Given, When, Then }) => { + let requestDelete: () => void; + Given('a Member aggregate without permission to manage members or system account', () => { + passport = makePassport({ canManageMembers: false, isSystemAccount: false }); + baseProps = makeBaseProps(); + member = new Member(baseProps, passport); + }); + When('I try to call requestDelete', () => { + requestDelete = () => { + member.requestDelete(); + }; + }); + Then('a PermissionError should be thrown', () => { + expect(requestDelete).toThrow(PermissionError); + expect(requestDelete).toThrow('Cannot delete member'); + }); + }); + Scenario('Getting profile, accounts, customViews, createdAt, updatedAt, and schemaVersion', ({ Given, Then, And }) => { Given('a Member aggregate', () => { passport = makePassport(); diff --git a/packages/ocom/domain/src/domain/contexts/community/member/member.ts b/packages/ocom/domain/src/domain/contexts/community/member/member.ts index 8affa6b76..c70948d27 100644 --- a/packages/ocom/domain/src/domain/contexts/community/member/member.ts +++ b/packages/ocom/domain/src/domain/contexts/community/member/member.ts @@ -10,6 +10,7 @@ import * as ValueObjects from './member.value-objects.ts'; import { MemberAccount, type MemberAccountEntityReference, type MemberAccountProps } from './member-account.ts'; import { MemberCustomView, type MemberCustomViewEntityReference, type MemberCustomViewProps } from './member-custom-view.ts'; import { MemberProfile, type MemberProfileEntityReference, type MemberProfileProps } from './member-profile.ts'; +import { MemberRemovedEvent, type MemberRemovedProps } from '../../../events/types/member-removed.ts'; export interface MemberProps extends DomainEntityProps { memberName: string; @@ -93,6 +94,17 @@ export class Member extends AggregateRoot domainPermissions.canManageMembers || domainPermissions.isSystemAccount)) { + throw new PermissionError('Cannot delete member'); + } + super.isDeleted = true; + this.addIntegrationEvent(MemberRemovedEvent, { + memberId: this.props.id, + communityId: this.communityId, + }); + } + async loadCommunity(): Promise { return await this.props.loadCommunity(); } diff --git a/packages/ocom/domain/src/domain/events/types/index.ts b/packages/ocom/domain/src/domain/events/types/index.ts index 67ce2df01..b587b1a71 100644 --- a/packages/ocom/domain/src/domain/events/types/index.ts +++ b/packages/ocom/domain/src/domain/events/types/index.ts @@ -1 +1,3 @@ export { CommunityCreatedEvent } from './community-created.ts'; +export { MemberAddedEvent, type MemberAddedProps } from './member-added.ts'; +export { MemberRemovedEvent, type MemberRemovedProps } from './member-removed.ts'; diff --git a/packages/ocom/domain/src/domain/events/types/member-added.ts b/packages/ocom/domain/src/domain/events/types/member-added.ts new file mode 100644 index 000000000..7d46a13f5 --- /dev/null +++ b/packages/ocom/domain/src/domain/events/types/member-added.ts @@ -0,0 +1,9 @@ +import { CustomDomainEventImpl } from '@cellix/domain-seedwork/domain-event'; + +export interface MemberAddedProps { + memberId: string; + communityId: string; + memberName: string; +} + +export class MemberAddedEvent extends CustomDomainEventImpl {} diff --git a/packages/ocom/domain/src/domain/events/types/member-removed.ts b/packages/ocom/domain/src/domain/events/types/member-removed.ts new file mode 100644 index 000000000..e3f209474 --- /dev/null +++ b/packages/ocom/domain/src/domain/events/types/member-removed.ts @@ -0,0 +1,8 @@ +import { CustomDomainEventImpl } from '@cellix/domain-seedwork/domain-event'; + +export interface MemberRemovedProps { + memberId: string; + communityId: string; +} + +export class MemberRemovedEvent extends CustomDomainEventImpl {} diff --git a/packages/ocom/graphql/src/schema/types/features/member.resolvers.feature b/packages/ocom/graphql/src/schema/types/features/member.resolvers.feature index 4847f7bcc..b1c157a05 100644 --- a/packages/ocom/graphql/src/schema/types/features/member.resolvers.feature +++ b/packages/ocom/graphql/src/schema/types/features/member.resolvers.feature @@ -25,3 +25,50 @@ Feature: Member resolvers Given a user without a verified JWT When the membersForCurrentEndUser query is executed Then it should throw an "Unauthorized" error + + Scenario: Querying members by community ID + Given a signed in user with subject "user-sub-123" + And the member service can return members for community "community-456" + When the membersByCommunityId query is executed with communityId "community-456" + Then it should call Community.Member.queryByCommunityId with the communityId + And it should return the list of members for that community + + Scenario: Querying members by community ID without authentication + Given a user without a verified JWT + When the membersByCommunityId query is executed with communityId "community-456" + Then it should throw an "Unauthorized" error + + Scenario: Adding a member to a community + Given a signed in user with subject "admin-sub-456" + And the member add service returns a new member + When the memberAdd mutation is executed + Then it should return a MemberMutationResult with success true and the new member + + Scenario: Adding a member to a community fails + Given a signed in user with subject "admin-sub-456" + And the member add service throws an error "Cannot add member" + When the memberAdd mutation is executed + Then it should return a MemberMutationResult with success false and the error message + + Scenario: Removing a member from a community + Given a signed in user with subject "admin-sub-456" + And the member remove service returns the removed member + When the memberRemove mutation is executed + Then it should return a MemberMutationResult with success true + + Scenario: Removing a member from a community fails + Given a signed in user with subject "admin-sub-456" + And the member remove service throws an error "Cannot remove member" + When the memberRemove mutation is executed + Then it should return a MemberMutationResult with success false and the error message + + Scenario: Updating a member's role + Given a signed in user with subject "admin-sub-456" + And the member role update service returns the updated member + When the memberRoleUpdate mutation is executed + Then it should return a MemberMutationResult with success true + + Scenario: Adding a member without authentication + Given a user without a verified JWT + When the memberAdd mutation is executed unauthenticated + Then it should return a MemberMutationResult with success false and the error message diff --git a/packages/ocom/graphql/src/schema/types/member.graphql b/packages/ocom/graphql/src/schema/types/member.graphql index 364eb0bd6..6e921f0ac 100644 --- a/packages/ocom/graphql/src/schema/types/member.graphql +++ b/packages/ocom/graphql/src/schema/types/member.graphql @@ -41,7 +41,35 @@ type MemberProfile { extend type Query { # member(id: ObjectID!): Member! - # membersByCommunityId(communityId: ObjectID!): [Member!]! + membersByCommunityId(communityId: ObjectID!): [Member!]! # memberForCurrentCommunity: Member! membersForCurrentEndUser: [Member!]! } + +type MemberMutationResult implements MutationResult { + status: MutationStatus! + member: Member +} + +input MemberAddInput { + communityId: ObjectID! + memberName: String! + firstName: String! + lastName: String + userExternalId: String! +} + +input MemberRemoveInput { + memberId: ObjectID! +} + +input MemberRoleUpdateInput { + memberId: ObjectID! + roleId: ObjectID! +} + +extend type Mutation { + memberAdd(input: MemberAddInput!): MemberMutationResult! + memberRemove(input: MemberRemoveInput!): MemberMutationResult! + memberRoleUpdate(input: MemberRoleUpdateInput!): MemberMutationResult! +} diff --git a/packages/ocom/graphql/src/schema/types/member.resolvers.test.ts b/packages/ocom/graphql/src/schema/types/member.resolvers.test.ts index f6ba987b9..243c020d7 100644 --- a/packages/ocom/graphql/src/schema/types/member.resolvers.test.ts +++ b/packages/ocom/graphql/src/schema/types/member.resolvers.test.ts @@ -14,6 +14,7 @@ type CommunityEntity = { id: string; name: string }; type MemberEntity = { id: string; communityId: string }; type CommunityReference = Domain.Contexts.Community.Community.CommunityEntityReference; type MemberReference = Domain.Contexts.Community.Member.MemberEntityReference; +type MutationResult = { status: { success: boolean; errorMessage?: string }; member?: MemberReference }; function createMockCommunity(overrides: Partial = {}): CommunityEntity { return { @@ -41,6 +42,10 @@ function makeMockGraphContext(overrides: Partial = {}): GraphConte Member: { determineIfAdmin: vi.fn(), queryByEndUserExternalId: vi.fn(), + queryByCommunityId: vi.fn(), + addMember: vi.fn(), + removeMember: vi.fn(), + updateMemberRole: vi.fn(), }, }, verifiedUser: { @@ -56,12 +61,17 @@ function makeMockGraphContext(overrides: Partial = {}): GraphConte return context; } +type MemberAddInput = { communityId: string; memberName: string; firstName: string; lastName?: string; userExternalId: string }; +type MemberRemoveInput = { memberId: string }; +type MemberRoleUpdateInput = { memberId: string; roleId: string }; + test.for(feature, ({ Scenario, BeforeEachScenario }) => { let context: GraphContext; let member: MemberEntity; let communityResult: unknown; let booleanResult: boolean | null; let membersResult: unknown; + let mutationResult: MutationResult | null; BeforeEachScenario(() => { context = makeMockGraphContext(); @@ -69,6 +79,7 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { communityResult = null; booleanResult = null; membersResult = null; + mutationResult = null; vi.clearAllMocks(); }); @@ -179,4 +190,408 @@ test.for(feature, ({ Scenario, BeforeEachScenario }) => { // Assertion performed in When step }); }); + + Scenario('Querying members by community ID', ({ Given, And, When, Then }) => { + const resolvedMembers = [createMockMember({ id: 'member-10', communityId: 'community-456' })]; + const domainMembers = resolvedMembers as unknown as MemberReference[]; + + Given('a signed in user with subject "user-sub-123"', () => { + if (context.applicationServices.verifiedUser?.verifiedJwt) { + context.applicationServices.verifiedUser.verifiedJwt.sub = 'user-sub-123'; + } + }); + + And('the member service can return members for community "community-456"', () => { + vi.mocked(context.applicationServices.Community.Member.queryByCommunityId).mockResolvedValue(domainMembers); + }); + + When('the membersByCommunityId query is executed with communityId "community-456"', async () => { + membersResult = await (memberResolvers.Query?.membersByCommunityId as unknown as (parent: unknown, args: { communityId: string }, graphContext: GraphContext, info: unknown) => Promise)( + null, + { communityId: 'community-456' }, + context, + {}, + ); + }); + + Then('it should call Community.Member.queryByCommunityId with the communityId', () => { + expect(context.applicationServices.Community.Member.queryByCommunityId).toHaveBeenCalledWith({ + communityId: 'community-456', + }); + }); + + And('it should return the list of members for that community', () => { + expect(membersResult as MemberEntity[]).toEqual(resolvedMembers); + }); + }); + + Scenario('Querying members by community ID without authentication', ({ Given, When, Then }) => { + Given('a user without a verified JWT', () => { + if (context.applicationServices.verifiedUser) { + context.applicationServices.verifiedUser.verifiedJwt = undefined; + } + }); + + When('the membersByCommunityId query is executed with communityId "community-456"', async () => { + await expect( + (memberResolvers.Query?.membersByCommunityId as unknown as (parent: unknown, args: { communityId: string }, graphContext: GraphContext, info: unknown) => Promise)( + null, + { communityId: 'community-456' }, + context, + {}, + ), + ).rejects.toThrow('Unauthorized'); + }); + + Then('it should throw an "Unauthorized" error', () => { + // Assertion performed in When step + }); + }); + + Scenario('Adding a member to a community', ({ Given, And, When, Then }) => { + const newMember = createMockMember({ id: 'new-member-1' }); + const domainMember = newMember as unknown as MemberReference; + + Given('a signed in user with subject "admin-sub-456"', () => { + if (context.applicationServices.verifiedUser?.verifiedJwt) { + context.applicationServices.verifiedUser.verifiedJwt.sub = 'admin-sub-456'; + } + }); + + And('the member add service returns a new member', () => { + vi.mocked(context.applicationServices.Community.Member.addMember).mockResolvedValue(domainMember); + }); + + When('the memberAdd mutation is executed', async () => { + const input: MemberAddInput = { communityId: 'community-123', memberName: 'Jane Doe', firstName: 'Jane', lastName: 'Doe', userExternalId: 'user-ext-1' }; + mutationResult = await (memberResolvers.Mutation?.memberAdd as unknown as (parent: unknown, args: { input: MemberAddInput }, graphContext: GraphContext, info: unknown) => Promise)( + null, + { input }, + context, + {}, + ); + }); + + Then('it should return a MemberMutationResult with success true and the new member', () => { + expect(mutationResult?.status.success).toBe(true); + expect(mutationResult?.member).toEqual(newMember); + }); + }); + + Scenario('Adding a member to a community fails', ({ Given, And, When, Then }) => { + Given('a signed in user with subject "admin-sub-456"', () => { + if (context.applicationServices.verifiedUser?.verifiedJwt) { + context.applicationServices.verifiedUser.verifiedJwt.sub = 'admin-sub-456'; + } + }); + + And('the member add service throws an error "Cannot add member"', () => { + vi.mocked(context.applicationServices.Community.Member.addMember).mockRejectedValue(new Error('Cannot add member')); + }); + + When('the memberAdd mutation is executed', async () => { + const input: MemberAddInput = { communityId: 'community-123', memberName: 'Jane Doe', firstName: 'Jane', lastName: 'Doe', userExternalId: 'user-ext-1' }; + mutationResult = await (memberResolvers.Mutation?.memberAdd as unknown as (parent: unknown, args: { input: MemberAddInput }, graphContext: GraphContext, info: unknown) => Promise)( + null, + { input }, + context, + {}, + ); + }); + + Then('it should return a MemberMutationResult with success false and the error message', () => { + expect(mutationResult?.status.success).toBe(false); + expect(mutationResult?.status.errorMessage).toBe('Cannot add member'); + }); + }); + + Scenario('Removing a member from a community', ({ Given, And, When, Then }) => { + const removedMember = createMockMember({ id: 'member-to-remove' }); + const domainMember = removedMember as unknown as MemberReference; + + Given('a signed in user with subject "admin-sub-456"', () => { + if (context.applicationServices.verifiedUser?.verifiedJwt) { + context.applicationServices.verifiedUser.verifiedJwt.sub = 'admin-sub-456'; + } + }); + + And('the member remove service returns the removed member', () => { + vi.mocked(context.applicationServices.Community.Member.removeMember).mockResolvedValue(domainMember); + }); + + When('the memberRemove mutation is executed', async () => { + const input: MemberRemoveInput = { memberId: 'member-to-remove' }; + mutationResult = await (memberResolvers.Mutation?.memberRemove as unknown as (parent: unknown, args: { input: MemberRemoveInput }, graphContext: GraphContext, info: unknown) => Promise)( + null, + { input }, + context, + {}, + ); + }); + + Then('it should return a MemberMutationResult with success true', () => { + expect(mutationResult?.status.success).toBe(true); + }); + }); + + Scenario('Removing a member from a community fails', ({ Given, And, When, Then }) => { + Given('a signed in user with subject "admin-sub-456"', () => { + if (context.applicationServices.verifiedUser?.verifiedJwt) { + context.applicationServices.verifiedUser.verifiedJwt.sub = 'admin-sub-456'; + } + }); + + And('the member remove service throws an error "Cannot remove member"', () => { + vi.mocked(context.applicationServices.Community.Member.removeMember).mockRejectedValue(new Error('Cannot remove member')); + }); + + When('the memberRemove mutation is executed', async () => { + const input: MemberRemoveInput = { memberId: 'member-to-remove' }; + mutationResult = await (memberResolvers.Mutation?.memberRemove as unknown as (parent: unknown, args: { input: MemberRemoveInput }, graphContext: GraphContext, info: unknown) => Promise)( + null, + { input }, + context, + {}, + ); + }); + + Then('it should return a MemberMutationResult with success false and the error message', () => { + expect(mutationResult?.status.success).toBe(false); + expect(mutationResult?.status.errorMessage).toBe('Cannot remove member'); + }); + }); + + Scenario("Updating a member's role", ({ Given, And, When, Then }) => { + const updatedMember = createMockMember({ id: 'member-to-update' }); + const domainMember = updatedMember as unknown as MemberReference; + + Given('a signed in user with subject "admin-sub-456"', () => { + if (context.applicationServices.verifiedUser?.verifiedJwt) { + context.applicationServices.verifiedUser.verifiedJwt.sub = 'admin-sub-456'; + } + }); + + And('the member role update service returns the updated member', () => { + vi.mocked(context.applicationServices.Community.Member.updateMemberRole).mockResolvedValue(domainMember); + }); + + When('the memberRoleUpdate mutation is executed', async () => { + const input: MemberRoleUpdateInput = { memberId: 'member-to-update', roleId: 'role-123' }; + mutationResult = await (memberResolvers.Mutation?.memberRoleUpdate as unknown as (parent: unknown, args: { input: MemberRoleUpdateInput }, graphContext: GraphContext, info: unknown) => Promise)( + null, + { input }, + context, + {}, + ); + }); + + Then('it should return a MemberMutationResult with success true', () => { + expect(mutationResult?.status.success).toBe(true); + }); + }); + + Scenario('Adding a member without authentication', ({ Given, When, Then }) => { + Given('a user without a verified JWT', () => { + if (context.applicationServices.verifiedUser) { + context.applicationServices.verifiedUser.verifiedJwt = undefined; + } + }); + + When('the memberAdd mutation is executed unauthenticated', async () => { + const input: MemberAddInput = { communityId: 'community-123', memberName: 'Jane', firstName: 'Jane', userExternalId: 'user-ext-1' }; + mutationResult = await (memberResolvers.Mutation?.memberAdd as unknown as (parent: unknown, args: { input: MemberAddInput }, graphContext: GraphContext, info: unknown) => Promise)( + null, + { input }, + context, + {}, + ); + }); + + Then('it should return a MemberMutationResult with success false and the error message', () => { + expect(mutationResult?.status.success).toBe(false); + expect(mutationResult?.status.errorMessage).toBe('Unauthorized'); + }); + }); +}); + +test.for(feature, ({ Scenario, BeforeEachScenario }) => { + let context: GraphContext; + let member: MemberEntity; + let communityResult: unknown; + let booleanResult: boolean | null; + let membersResult: unknown; + + BeforeEachScenario(() => { + context = makeMockGraphContext(); + member = createMockMember(); + communityResult = null; + booleanResult = null; + membersResult = null; + vi.clearAllMocks(); + }); + + Scenario('Resolving the community for a member', ({ Given, And, When, Then }) => { + const resolvedCommunity = createMockCommunity(); + const domainCommunity = resolvedCommunity as unknown as CommunityReference; + + Given('a member with communityId "community-123"', () => { + member = createMockMember({ communityId: 'community-123' }); + }); + + And('the community service can return that community', () => { + vi.mocked(context.applicationServices.Community.Community.queryById).mockResolvedValue(domainCommunity); + }); + + When('the Member.community resolver is executed', async () => { + communityResult = await (memberResolvers.Member?.community as unknown as (parent: MemberEntity, args: Record, graphContext: GraphContext, info: unknown) => Promise)( + member, + {}, + context, + {}, + ); + }); + + Then("it should call Community.Community.queryById with the member's communityId", () => { + expect(context.applicationServices.Community.Community.queryById).toHaveBeenCalledWith({ + id: 'community-123', + }); + }); + + And('it should return the resolved community', () => { + expect(communityResult as CommunityEntity).toEqual(resolvedCommunity); + }); + }); + + Scenario('Checking if a member is an administrator', ({ Given, And, When, Then }) => { + Given('a member with id "member-1"', () => { + member = createMockMember({ id: 'member-1' }); + }); + + And('the member service indicates the member is an admin', () => { + vi.mocked(context.applicationServices.Community.Member.determineIfAdmin).mockResolvedValue(true); + }); + + When('the Member.isAdmin resolver is executed', async () => { + booleanResult = await (memberResolvers.Member?.isAdmin as unknown as (parent: MemberEntity, args: Record, graphContext: GraphContext, info: unknown) => Promise)(member, {}, context, {}); + }); + + Then("it should call Community.Member.determineIfAdmin with the member's id", () => { + expect(context.applicationServices.Community.Member.determineIfAdmin).toHaveBeenCalledWith({ + memberId: 'member-1', + }); + }); + + And('it should return true', () => { + expect(booleanResult).toBe(true); + }); + }); + + Scenario('Querying members for the current end user', ({ Given, And, When, Then }) => { + const resolvedMembers = [createMockMember({ id: 'member-42' })]; + const domainMembers = resolvedMembers as unknown as MemberReference[]; + + Given('a signed in user with subject "user-sub-123"', () => { + if (context.applicationServices.verifiedUser?.verifiedJwt) { + context.applicationServices.verifiedUser.verifiedJwt.sub = 'user-sub-123'; + } + }); + + And('the member service can return members for that subject', () => { + vi.mocked(context.applicationServices.Community.Member.queryByEndUserExternalId).mockResolvedValue(domainMembers); + }); + + When('the membersForCurrentEndUser query is executed', async () => { + membersResult = await (memberResolvers.Query?.membersForCurrentEndUser as unknown as (parent: unknown, args: Record, graphContext: GraphContext, info: unknown) => Promise)( + null, + {}, + context, + {}, + ); + }); + + Then('it should call Community.Member.queryByEndUserExternalId with the subject', () => { + expect(context.applicationServices.Community.Member.queryByEndUserExternalId).toHaveBeenCalledWith({ + externalId: 'user-sub-123', + }); + }); + + And('it should return the list of members', () => { + expect(membersResult as MemberEntity[]).toEqual(resolvedMembers); + }); + }); + + Scenario('Querying members for the current end user without authentication', ({ Given, When, Then }) => { + Given('a user without a verified JWT', () => { + if (context.applicationServices.verifiedUser) { + context.applicationServices.verifiedUser.verifiedJwt = undefined; + } + }); + + When('the membersForCurrentEndUser query is executed', async () => { + await expect( + (memberResolvers.Query?.membersForCurrentEndUser as unknown as (parent: unknown, args: Record, graphContext: GraphContext, info: unknown) => Promise)(null, {}, context, {}), + ).rejects.toThrow('Unauthorized'); + }); + + Then('it should throw an "Unauthorized" error', () => { + // Assertion performed in When step + }); + }); + + Scenario('Querying members by community ID', ({ Given, And, When, Then }) => { + const resolvedMembers = [createMockMember({ id: 'member-10', communityId: 'community-456' })]; + const domainMembers = resolvedMembers as unknown as MemberReference[]; + + Given('a signed in user with subject "user-sub-123"', () => { + if (context.applicationServices.verifiedUser?.verifiedJwt) { + context.applicationServices.verifiedUser.verifiedJwt.sub = 'user-sub-123'; + } + }); + + And('the member service can return members for community "community-456"', () => { + vi.mocked(context.applicationServices.Community.Member.queryByCommunityId).mockResolvedValue(domainMembers); + }); + + When('the membersByCommunityId query is executed with communityId "community-456"', async () => { + membersResult = await (memberResolvers.Query?.membersByCommunityId as unknown as (parent: unknown, args: { communityId: string }, graphContext: GraphContext, info: unknown) => Promise)( + null, + { communityId: 'community-456' }, + context, + {}, + ); + }); + + Then('it should call Community.Member.queryByCommunityId with the communityId', () => { + expect(context.applicationServices.Community.Member.queryByCommunityId).toHaveBeenCalledWith({ + communityId: 'community-456', + }); + }); + + And('it should return the list of members for that community', () => { + expect(membersResult as MemberEntity[]).toEqual(resolvedMembers); + }); + }); + + Scenario('Querying members by community ID without authentication', ({ Given, When, Then }) => { + Given('a user without a verified JWT', () => { + if (context.applicationServices.verifiedUser) { + context.applicationServices.verifiedUser.verifiedJwt = undefined; + } + }); + + When('the membersByCommunityId query is executed with communityId "community-456"', async () => { + await expect( + (memberResolvers.Query?.membersByCommunityId as unknown as (parent: unknown, args: { communityId: string }, graphContext: GraphContext, info: unknown) => Promise)( + null, + { communityId: 'community-456' }, + context, + {}, + ), + ).rejects.toThrow('Unauthorized'); + }); + + Then('it should throw an "Unauthorized" error', () => { + // Assertion performed in When step + }); + }); }); diff --git a/packages/ocom/graphql/src/schema/types/member.resolvers.ts b/packages/ocom/graphql/src/schema/types/member.resolvers.ts index e640d6c1b..e5639f988 100644 --- a/packages/ocom/graphql/src/schema/types/member.resolvers.ts +++ b/packages/ocom/graphql/src/schema/types/member.resolvers.ts @@ -1,6 +1,22 @@ import type { GraphQLResolveInfo } from 'graphql'; +import type { Domain } from '@ocom/domain'; import type { GraphContext } from '../context.ts'; -import type { Resolvers } from '../builder/generated.ts'; +import type { MemberAddInput, MemberRemoveInput, MemberRoleUpdateInput, Resolvers } from '../builder/generated.ts'; + +const MemberMutationResolver = async (getMember: Promise) => { + try { + return { + status: { success: true }, + member: await getMember, + }; + } catch (error) { + console.error('Member > Mutation: ', error); + const { message } = error as Error; + return { + status: { success: false, errorMessage: message }, + }; + } +}; const member: Resolvers = { Member: { @@ -28,6 +44,53 @@ const member: Resolvers = { externalId, }); }, + membersByCommunityId: async (_parent, args: { communityId: string }, context: GraphContext, _info: GraphQLResolveInfo) => { + if (!context.applicationServices.verifiedUser?.verifiedJwt) { + throw new Error('Unauthorized'); + } + return await context.applicationServices.Community.Member.queryByCommunityId({ + communityId: args.communityId, + }); + }, + }, + Mutation: { + memberAdd: (_parent, args: { input: MemberAddInput }, context: GraphContext, _info: GraphQLResolveInfo) => { + if (!context.applicationServices.verifiedUser?.verifiedJwt) { + return MemberMutationResolver(Promise.reject(new Error('Unauthorized'))); + } + const createdByExternalId = context.applicationServices.verifiedUser.verifiedJwt.sub; + return MemberMutationResolver( + context.applicationServices.Community.Member.addMember({ + communityId: args.input.communityId, + memberName: args.input.memberName, + firstName: args.input.firstName, + ...(args.input.lastName ? { lastName: args.input.lastName } : {}), + userExternalId: args.input.userExternalId, + createdByExternalId, + }), + ); + }, + memberRemove: (_parent, args: { input: MemberRemoveInput }, context: GraphContext, _info: GraphQLResolveInfo) => { + if (!context.applicationServices.verifiedUser?.verifiedJwt) { + return MemberMutationResolver(Promise.reject(new Error('Unauthorized'))); + } + return MemberMutationResolver( + context.applicationServices.Community.Member.removeMember({ + memberId: args.input.memberId, + }), + ); + }, + memberRoleUpdate: (_parent, args: { input: MemberRoleUpdateInput }, context: GraphContext, _info: GraphQLResolveInfo) => { + if (!context.applicationServices.verifiedUser?.verifiedJwt) { + return MemberMutationResolver(Promise.reject(new Error('Unauthorized'))); + } + return MemberMutationResolver( + context.applicationServices.Community.Member.updateMemberRole({ + memberId: args.input.memberId, + roleId: args.input.roleId, + }), + ); + }, }, }; From 1f70604252354af93380f52cc460485c0c28cb22 Mon Sep 17 00:00:00 2001 From: Rohit Kumar Date: Mon, 6 Apr 2026 23:04:38 +0530 Subject: [PATCH 2/3] Fix: Knip Issues --- apps/ui-community/package.json | 2 +- .../components/member-add-modal.container.tsx | 9 +- .../admin/components/member-add-modal.tsx | 10 +- package.json | 2 - pnpm-lock.yaml | 1047 ++++++++++++----- 5 files changed, 779 insertions(+), 291 deletions(-) diff --git a/apps/ui-community/package.json b/apps/ui-community/package.json index 6d5a16b36..6e9cb3fce 100644 --- a/apps/ui-community/package.json +++ b/apps/ui-community/package.json @@ -25,7 +25,7 @@ "@dr.pogodin/react-helmet": "^3.0.2", "@graphql-typed-document-node/core": "^3.2.0", "@ocom/ui-components": "workspace:*", - "antd": "^5.27.0", + "antd": "^6.0.0", "apollo-link-rest": "^0.9.0", "dayjs": "^1.11.19", "less": "^4.4.0", diff --git a/apps/ui-community/src/components/layouts/admin/components/member-add-modal.container.tsx b/apps/ui-community/src/components/layouts/admin/components/member-add-modal.container.tsx index 3b7ceb00d..ddcafde5d 100644 --- a/apps/ui-community/src/components/layouts/admin/components/member-add-modal.container.tsx +++ b/apps/ui-community/src/components/layouts/admin/components/member-add-modal.container.tsx @@ -3,13 +3,7 @@ import { useMutation } from '@apollo/client'; import { AdminMemberAddContainerMemberAddDocument, AdminMemberListContainerMembersByCommunityIdDocument } from '../../../../generated.tsx'; import { MemberAddModal } from './member-add-modal.tsx'; -export interface MemberAddModalContainerProps { - communityId: string; - open: boolean; - onClose: () => void; -} - -export const MemberAddModalContainer: React.FC = ({ communityId, open, onClose }) => { +export const MemberAddModalContainer: React.FC<{ communityId: string; open: boolean; onClose: () => void }> = ({ communityId, open, onClose }) => { const { message } = App.useApp(); const [addMember, { loading }] = useMutation(AdminMemberAddContainerMemberAddDocument, { @@ -42,7 +36,6 @@ export const MemberAddModalContainer: React.FC = ( return ( void; - onCancel: () => void; -} - interface MemberAddFormValues { memberName: string; firstName: string; @@ -15,7 +7,7 @@ interface MemberAddFormValues { userExternalId: string; } -export const MemberAddModal: React.FC = ({ open, loading, onAdd, onCancel }) => { +export const MemberAddModal: React.FC<{ open: boolean; loading?: boolean; onAdd: (values: MemberAddFormValues) => void; onCancel: () => void }> = ({ open, loading, onAdd, onCancel }) => { const [form] = Form.useForm(); const handleOk = () => { diff --git a/package.json b/package.json index 8c0bd827c..0ab9ba282 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,6 @@ "license": "MIT", "packageManager": "pnpm@10.30.1", "scripts": { - "antd": "antd", "audit": "(pnpm audit --audit-level=high --prod) && (pnpm audit --audit-level=critical --dev)", "build": "turbo run build", "test": "turbo run test", @@ -53,7 +52,6 @@ }, "devDependencies": { "@amiceli/vitest-cucumber": "^6.3.0", - "@ant-design/cli": "^6.3.5", "@biomejs/biome": "2.4.10", "@cellix/graphql-codegen": "workspace:*", "@graphql-codegen/cli": "^5.0.7", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index aa4bcabc4..4d0f55dc3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -86,9 +86,6 @@ importers: '@amiceli/vitest-cucumber': specifier: ^6.3.0 version: 6.3.0(vitest@4.1.2) - '@ant-design/cli': - specifier: ^6.3.5 - version: 6.3.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1) '@biomejs/biome': specifier: 2.4.10 version: 2.4.10 @@ -359,7 +356,7 @@ importers: version: 6.1.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@ant-design/pro-layout': specifier: ^7.22.7 - version: 7.22.7(antd@5.29.1(luxon@3.6.1)(moment@2.30.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 7.22.7(antd@6.3.5(luxon@3.6.1)(moment@2.30.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@apollo/client': specifier: ^3.13.9 version: 3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.20.0))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -376,8 +373,8 @@ importers: specifier: workspace:* version: link:../../packages/ocom/ui-components antd: - specifier: ^5.27.0 - version: 5.29.1(luxon@3.6.1)(moment@2.30.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + specifier: ^6.0.0 + version: 6.3.5(luxon@3.6.1)(moment@2.30.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) apollo-link-rest: specifier: ^0.9.0 version: 0.9.0(@apollo/client@3.14.0(@types/react@19.2.7)(graphql-ws@6.0.6(graphql@16.12.0)(ws@8.20.0))(graphql@16.12.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(graphql@16.12.0)(qs@6.15.0) @@ -1506,29 +1503,39 @@ packages: peerDependencies: vitest: ^4.0.4 - '@ant-design/cli@6.3.5': - resolution: {integrity: sha512-d4goa6b9910ovOS46G1qcm2DAV10QcZf37Ady1tiHU5Exc0ZGD88k75FDadDDwEzks87S0k3NCXHQXmlSXoRDA==} - engines: {node: '>=18.0.0'} - hasBin: true - '@ant-design/colors@7.2.1': resolution: {integrity: sha512-lCHDcEzieu4GA3n8ELeZ5VQ8pKQAWcGGLRTQ50aQM2iqPpq2evTxER84jfdPvsPAtEcZ7m44NI45edFMo8oOYQ==} '@ant-design/colors@8.0.0': resolution: {integrity: sha512-6YzkKCw30EI/E9kHOIXsQDHmMvTllT8STzjMb4K2qzit33RW2pqCJP0sk+hidBntXxE+Vz4n1+RvCTfBw6OErw==} + '@ant-design/colors@8.0.1': + resolution: {integrity: sha512-foPVl0+SWIslGUtD/xBr1p9U4AKzPhNYEseXYRRo5QSzGACYZrQbe11AYJbYfAWnWSpGBx6JjBmSeugUsD9vqQ==} + '@ant-design/cssinjs-utils@1.1.3': resolution: {integrity: sha512-nOoQMLW1l+xR1Co8NFVYiP8pZp3VjIIzqV6D6ShYF2ljtdwWJn5WSsH+7kvCktXL/yhEtWURKOfH5Xz/gzlwsg==} peerDependencies: react: '>=16.9.0' react-dom: '>=16.9.0' + '@ant-design/cssinjs-utils@2.1.2': + resolution: {integrity: sha512-5fTHQ158jJJ5dC/ECeyIdZUzKxE/mpEMRZxthyG1sw/AKRHKgJBg00Yi6ACVXgycdje7KahRNvNET/uBccwCnA==} + peerDependencies: + react: '>=18' + react-dom: '>=18' + '@ant-design/cssinjs@1.24.0': resolution: {integrity: sha512-K4cYrJBsgvL+IoozUXYjbT6LHHNt+19a9zkvpBPxLjFHas1UpPM2A5MlhROb0BT8N8WoavM5VsP9MeSeNK/3mg==} peerDependencies: react: '>=16.0.0' react-dom: '>=16.0.0' + '@ant-design/cssinjs@2.1.2': + resolution: {integrity: sha512-2Hy8BnCEH31xPeSLbhhB2ctCPXE2ZnASdi+KbSeS79BNbUhL9hAEe20SkUk+BR8aKTmqb6+FKFruk7w8z0VoRQ==} + peerDependencies: + react: '>=16.0.0' + react-dom: '>=16.0.0' + '@ant-design/fast-color@2.0.6': resolution: {integrity: sha512-y2217gk4NqL35giHl72o6Zzqji9O7vHh9YmhUVkPtAOpoTCH4uWxo/pr4VE8t0+ChEPs0qo4eJRC5Q1eXWo3vA==} engines: {node: '>=8.x'} @@ -1537,6 +1544,10 @@ packages: resolution: {integrity: sha512-eqvpP7xEDm2S7dUzl5srEQCBTXZMmY3ekf97zI+M2DHOYyKdJGH0qua0JACHTqbkRnD/KHFQP9J1uMJ/XWVzzA==} engines: {node: '>=8.x'} + '@ant-design/fast-color@3.0.1': + resolution: {integrity: sha512-esKJegpW4nckh0o6kV3Tkb7NPIZYbPnnFxmQDUmL08ukXZAvV85TZBr70eGuke/CIArLaP6aw8lt9KILjnWuOw==} + engines: {node: '>=8.x'} + '@ant-design/icons-svg@4.4.2': resolution: {integrity: sha512-vHbT+zJEVzllwP+CM+ul7reTEfBR0vgxFe7+lREAsAA7YGsYpboiq2sQNeQeRvh09GfQgs/GyFEvZpJ9cLXpXA==} @@ -1554,6 +1565,13 @@ packages: react: '>=16.0.0' react-dom: '>=16.0.0' + '@ant-design/icons@6.1.1': + resolution: {integrity: sha512-AMT4N2y++TZETNHiM77fs4a0uPVCJGuL5MTonk13Pvv7UN7sID1cNEZOc1qNqx6zLKAOilTEFAdAoAFKa0U//Q==} + engines: {node: '>=8'} + peerDependencies: + react: '>=16.0.0' + react-dom: '>=16.0.0' + '@ant-design/pro-layout@7.22.7': resolution: {integrity: sha512-fvmtNA1r9SaasVIQIQt611VSlNxtVxDbQ3e+1GhYQza3tVJi/3gCZuDyfMfTnbLmf3PaW/YvLkn7MqDbzAzoLA==} peerDependencies: @@ -1580,6 +1598,12 @@ packages: peerDependencies: react: '>=16.9.0' + '@ant-design/react-slick@2.0.0': + resolution: {integrity: sha512-HMS9sRoEmZey8LsE/Yo6+klhlzU12PisjrVcydW3So7RdklyEd2qehyU6a7Yp+OYN72mgsYs3NFCyP2lCPFVqg==} + peerDependencies: + react: ^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + '@apollo/cache-control-types@1.0.3': resolution: {integrity: sha512-F17/vCp7QVwom9eG7ToauIKdAxpSoadsJnqIfyryLFSkLSOEqu+eC5Z3N8OXcUVStuOMcNHlyraRsA6rRICu4g==} peerDependencies: @@ -4051,139 +4075,9 @@ packages: resolution: {integrity: sha512-kocjix+/sSggfJhwXqClZ3i9Y/MI0fp7b+g7kCRm6psy2dsf8uApTRclwG18h8Avm7C9+fnt+O36PspJ/OzoWg==} engines: {node: '>=14'} - '@oxc-parser/binding-android-arm-eabi@0.121.0': - resolution: {integrity: sha512-n07FQcySwOlzap424/PLMtOkbS7xOu8nsJduKL8P3COGHKgKoDYXwoAHCbChfgFpHnviehrLWIPX0lKGtbEk/A==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [android] - - '@oxc-parser/binding-android-arm64@0.121.0': - resolution: {integrity: sha512-/Dd1xIXboYAicw+twT2utxPD7bL8qh7d3ej0qvaYIMj3/EgIrGR+tSnjCUkiCT6g6uTC0neSS4JY8LxhdSU/sA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [android] - - '@oxc-parser/binding-darwin-arm64@0.121.0': - resolution: {integrity: sha512-A0jNEvv7QMtCO1yk205t3DWU9sWUjQ2KNF0hSVO5W9R9r/R1BIvzG01UQAfmtC0dQm7sCrs5puixurKSfr2bRQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [darwin] - - '@oxc-parser/binding-darwin-x64@0.121.0': - resolution: {integrity: sha512-SsHzipdxTKUs3I9EOAPmnIimEeJOemqRlRDOp9LIj+96wtxZejF51gNibmoGq8KoqbT1ssAI5po/E3J+vEtXGA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [darwin] - - '@oxc-parser/binding-freebsd-x64@0.121.0': - resolution: {integrity: sha512-v1APOTkCp+RWOIDAHRoaeW/UoaHF15a60E8eUL6kUQXh+i4K7PBwq2Wi7jm8p0ymID5/m/oC1w3W31Z/+r7HQw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [freebsd] - - '@oxc-parser/binding-linux-arm-gnueabihf@0.121.0': - resolution: {integrity: sha512-PmqPQuqHZyFVWA4ycr0eu4VnTMmq9laOHZd+8R359w6kzuNZPvmmunmNJ8ybkm769A0nCoVp3TJ6dUz7B3FYIQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [linux] - - '@oxc-parser/binding-linux-arm-musleabihf@0.121.0': - resolution: {integrity: sha512-vF24htj+MOH+Q7y9A8NuC6pUZu8t/C2Fr/kDOi2OcNf28oogr2xadBPXAbml802E8wRAVfbta6YLDQTearz+jw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [linux] - - '@oxc-parser/binding-linux-arm64-gnu@0.121.0': - resolution: {integrity: sha512-wjH8cIG2Lu/3d64iZpbYr73hREMgKAfu7fqpXjgM2S16y2zhTfDIp8EQjxO8vlDtKP5Rc7waZW72lh8nZtWrpA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@oxc-parser/binding-linux-arm64-musl@0.121.0': - resolution: {integrity: sha512-qT663J/W8yQFw3dtscbEi9LKJevr20V7uWs2MPGTnvNZ3rm8anhhE16gXGpxDOHeg9raySaSHKhd4IGa3YZvuw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@oxc-parser/binding-linux-ppc64-gnu@0.121.0': - resolution: {integrity: sha512-mYNe4NhVvDBbPkAP8JaVS8lC1dsoJZWH5WCjpw5E+sjhk1R08wt3NnXYUzum7tIiWPfgQxbCMcoxgeemFASbRw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [ppc64] - os: [linux] - libc: [glibc] - - '@oxc-parser/binding-linux-riscv64-gnu@0.121.0': - resolution: {integrity: sha512-+QiFoGxhAbaI/amqX567784cDyyuZIpinBrJNxUzb+/L2aBRX67mN6Jv40pqduHf15yYByI+K5gUEygCuv0z9w==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [riscv64] - os: [linux] - libc: [glibc] - - '@oxc-parser/binding-linux-riscv64-musl@0.121.0': - resolution: {integrity: sha512-9ykEgyTa5JD/Uhv2sttbKnCfl2PieUfOjyxJC/oDL2UO0qtXOtjPLl7H8Kaj5G7p3hIvFgu3YWvAxvE0sqY+hQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [riscv64] - os: [linux] - libc: [musl] - - '@oxc-parser/binding-linux-s390x-gnu@0.121.0': - resolution: {integrity: sha512-DB1EW5VHZdc1lIRjOI3bW/wV6R6y0xlfvdVrqj6kKi7Ayu2U3UqUBdq9KviVkcUGd5Oq+dROqvUEEFRXGAM7EQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [s390x] - os: [linux] - libc: [glibc] - - '@oxc-parser/binding-linux-x64-gnu@0.121.0': - resolution: {integrity: sha512-s4lfobX9p4kPTclvMiH3gcQUd88VlnkMTF6n2MTMDAyX5FPNRhhRSFZK05Ykhf8Zy5NibV4PbGR6DnK7FGNN6A==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@oxc-parser/binding-linux-x64-musl@0.121.0': - resolution: {integrity: sha512-P9KlyTpuBuMi3NRGpJO8MicuGZfOoqZVRP1WjOecwx8yk4L/+mrCRNc5egSi0byhuReblBF2oVoDSMgV9Bj4Hw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - libc: [musl] - - '@oxc-parser/binding-openharmony-arm64@0.121.0': - resolution: {integrity: sha512-R+4jrWOfF2OAPPhj3Eb3U5CaKNAH9/btMveMULIrcNW/hjfysFQlF8wE0GaVBr81dWz8JLgQlsxwctoL78JwXw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [openharmony] - - '@oxc-parser/binding-wasm32-wasi@0.121.0': - resolution: {integrity: sha512-5TFISkPTymKvsmIlKasPVTPuWxzCcrT8pM+p77+mtQbIZDd1UC8zww4CJcRI46kolmgrEX6QpKO8AvWMVZ+ifw==} - engines: {node: '>=14.0.0'} - cpu: [wasm32] - - '@oxc-parser/binding-win32-arm64-msvc@0.121.0': - resolution: {integrity: sha512-V0pxh4mql4XTt3aiEtRNUeBAUFOw5jzZNxPABLaOKAWrVzSr9+XUaB095lY7jqMf5t8vkfh8NManGB28zanYKw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [win32] - - '@oxc-parser/binding-win32-ia32-msvc@0.121.0': - resolution: {integrity: sha512-4Ob1qvYMPnlF2N9rdmKdkQFdrq16QVcQwBsO8yiPZXof0fHKFF+LmQV501XFbi7lHyrKm8rlJRfQ/M8bZZPVLw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [ia32] - os: [win32] - - '@oxc-parser/binding-win32-x64-msvc@0.121.0': - resolution: {integrity: sha512-BOp1KCzdboB1tPqoCPXgntgFs0jjeSyOXHzgxVFR7B/qfr3F8r4YDacHkTOUNXtDgM8YwKnkf3rE5gwALYX7NA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [win32] - '@oxc-project/types@0.103.0': resolution: {integrity: sha512-bkiYX5kaXWwUessFRSoXFkGIQTmc6dLGdxuRTrC+h8PSnIdZyuXHHlLAeTmOue5Br/a0/a7dHH0Gca6eXn9MKg==} - '@oxc-project/types@0.121.0': - resolution: {integrity: sha512-CGtOARQb9tyv7ECgdAlFxi0Fv7lmzvmlm2rpD/RdijOO9rfk/JvB1CjT8EnoD+tjna/IYgKKw3IV7objRb+aYw==} - '@oxc-project/types@0.122.0': resolution: {integrity: sha512-oLAl5kBpV4w69UtFZ9xqcmTi+GENWOcPF7FCrczTiBbmC0ibXxCwyvZGbO39rCVEuLGAZM84DH0pUIyyv/YJzA==} @@ -4439,22 +4333,117 @@ packages: resolution: {integrity: sha512-qgGdcVIF604M9EqjNF0hbUTz42bz/RDtxWdWuU5EQe3hi7M8ob54B6B35rOsvX5eSvIHIzT9iH1R3n+hk3CGfg==} engines: {node: '>=14.x'} + '@rc-component/async-validator@5.1.0': + resolution: {integrity: sha512-n4HcR5siNUXRX23nDizbZBQPO0ZM/5oTtmKZ6/eqL0L2bo747cklFdZGRN2f+c9qWGICwDzrhW0H7tE9PptdcA==} + engines: {node: '>=14.x'} + + '@rc-component/cascader@1.14.0': + resolution: {integrity: sha512-Ip9356xwZUR2nbW5PRVGif4B/bDve4pLa/N+PGbvBaTnjbvmN4PFMBGQSmlDlzKP1ovxaYMvwF/dI9lXNLT4iQ==} + peerDependencies: + react: '>=18.0.0' + react-dom: '>=18.0.0' + + '@rc-component/checkbox@2.0.0': + resolution: {integrity: sha512-3CXGPpAR9gsPKeO2N78HAPOzU30UdemD6HGJoWVJOpa6WleaGB5kzZj3v6bdTZab31YuWgY/RxV3VKPctn0DwQ==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/collapse@1.2.0': + resolution: {integrity: sha512-ZRYSKSS39qsFx93p26bde7JUZJshsUBEQRlRXPuJYlAiNX0vyYlF5TsAm8JZN3LcF8XvKikdzPbgAtXSbkLUkw==} + peerDependencies: + react: '>=18.0.0' + react-dom: '>=18.0.0' + '@rc-component/color-picker@2.0.1': resolution: {integrity: sha512-WcZYwAThV/b2GISQ8F+7650r5ZZJ043E57aVBFkQ+kSY4C6wdofXgB0hBx+GPGpIU0Z81eETNoDUJMr7oy/P8Q==} peerDependencies: react: '>=16.9.0' react-dom: '>=16.9.0' + '@rc-component/color-picker@3.1.1': + resolution: {integrity: sha512-OHaCHLHszCegdXmIq2ZRIZBN/EtpT6Wm8SG/gpzLATHbVKc/avvuKi+zlOuk05FTWvgaMmpxAko44uRJ3M+2pg==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + '@rc-component/context@1.4.0': resolution: {integrity: sha512-kFcNxg9oLRMoL3qki0OMxK+7g5mypjgaaJp/pkOis/6rVxma9nJBF/8kCIuTYHUQNr0ii7MxqE33wirPZLJQ2w==} peerDependencies: react: '>=16.9.0' react-dom: '>=16.9.0' + '@rc-component/context@2.0.1': + resolution: {integrity: sha512-HyZbYm47s/YqtP6pKXNMjPEMaukyg7P0qVfgMLzr7YiFNMHbK2fKTAGzms9ykfGHSfyf75nBbgWw+hHkp+VImw==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/dialog@1.8.4': + resolution: {integrity: sha512-Ay6PM7phkTkquplG8fWfUGFZ2GTLx9diTl4f0d8Eqxd7W1u1KjE9AQooFQHOHnhZf0Ya3z51+5EKCWHmt/dNEw==} + peerDependencies: + react: '>=18.0.0' + react-dom: '>=18.0.0' + + '@rc-component/drawer@1.4.2': + resolution: {integrity: sha512-1ib+fZEp6FBu+YvcIktm+nCQ+Q+qIpwpoaJH6opGr4ofh2QMq+qdr5DLC4oCf5qf3pcWX9lUWPYX652k4ini8Q==} + peerDependencies: + react: '>=18.0.0' + react-dom: '>=18.0.0' + + '@rc-component/dropdown@1.0.2': + resolution: {integrity: sha512-6PY2ecUSYhDPhkNHHb4wfeAya04WhpmUSKzdR60G+kMNVUCX2vjT/AgTS0Lz0I/K6xrPMJ3enQbwVpeN3sHCgg==} + peerDependencies: + react: '>=16.11.0' + react-dom: '>=16.11.0' + + '@rc-component/form@1.8.0': + resolution: {integrity: sha512-eUD5KKYnIZWmJwRA0vnyO/ovYUfHGU1svydY1OrqU5fw8Oz9Tdqvxvrlh0wl6xI/EW69dT7II49xpgOWzK3T5A==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/image@1.8.0': + resolution: {integrity: sha512-Dr41bFevLB5NgVaJhEUmNvbEf+ynAhim6W98ZW2xvCsdFISc2TYP4ZvCVdie3eaZdum2kieVcvpNHu+UrzAAHA==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/input-number@1.6.2': + resolution: {integrity: sha512-Gjcq7meZlCOiWN1t1xCC+7/s85humHVokTBI7PJgTfoyw5OWF74y3e6P8PHX104g9+b54jsodFIzyaj6p8LI9w==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/input@1.1.2': + resolution: {integrity: sha512-Q61IMR47piUBudgixJ30CciKIy9b1H95qe7GgEKOmSJVJXvFRWJllJfQry9tif+MX2cWFXWJf/RXz4kaCeq/Fg==} + peerDependencies: + react: '>=16.0.0' + react-dom: '>=16.0.0' + + '@rc-component/mentions@1.6.0': + resolution: {integrity: sha512-KIkQNP6habNuTsLhUv0UGEOwG67tlmE7KNIJoQZZNggEZl5lQJTytFDb69sl5CK3TDdISCTjKP3nGEBKgT61CQ==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/menu@1.2.0': + resolution: {integrity: sha512-VWwDuhvYHSnTGj4n6bV3ISrLACcPAzdPOq3d0BzkeiM5cve8BEYfvkEhNoM0PLzv51jpcejeyrLXeMVIJ+QJlg==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + '@rc-component/mini-decimal@1.1.0': resolution: {integrity: sha512-jS4E7T9Li2GuYwI6PyiVXmxTiM6b07rlD9Ge8uGZSCz3WlzcG5ZK7g5bbuKNeZ9pgUuPK/5guV781ujdVpm4HQ==} engines: {node: '>=8.x'} + '@rc-component/motion@1.3.2': + resolution: {integrity: sha512-itfd+GztzJYAb04Z4RkEub1TbJAfZc2Iuy8p44U44xD1F5+fNYFKI3897ijlbIyfvXkTmMm+KGcjkQQGMHywEQ==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + '@rc-component/mutate-observer@1.1.0': resolution: {integrity: sha512-QjrOsDXQusNwGZPf4/qRQasg7UFEj06XiCJ8iuiq/Io7CrHrgVi6Uuetw60WAMG1799v+aM8kyc+1L/GBbHSlw==} engines: {node: '>=8.x'} @@ -4462,6 +4451,52 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' + '@rc-component/mutate-observer@2.0.1': + resolution: {integrity: sha512-AyarjoLU5YlxuValRi+w8JRH2Z84TBbFO2RoGWz9d8bSu0FqT8DtugH3xC3BV7mUwlmROFauyWuXFuq4IFbH+w==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/notification@1.2.0': + resolution: {integrity: sha512-OX3J+zVU7rvoJCikjrfW7qOUp7zlDeFBK2eA3SFbGSkDqo63Sl4Ss8A04kFP+fxHSxMDIS9jYVEZtU1FNCFuBA==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/overflow@1.0.0': + resolution: {integrity: sha512-GSlBeoE0XTBi5cf3zl8Qh7Uqhn7v8RrlJ8ajeVpEkNe94HWy5l5BQ0Mwn2TVUq9gdgbfEMUmTX7tJFAg7mz0Rw==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/pagination@1.2.0': + resolution: {integrity: sha512-YcpUFE8dMLfSo6OARJlK6DbHHvrxz7pMGPGmC/caZSJJz6HRKHC1RPP001PRHCvG9Z/veD039uOQmazVuLJzlw==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/picker@1.9.1': + resolution: {integrity: sha512-9FBYYsvH3HMLICaPDA/1Th5FLaDkFa7qAtangIdlhKb3ZALaR745e9PsOhheJb6asS4QXc12ffiAcjdkZ4C5/g==} + engines: {node: '>=12.x'} + peerDependencies: + date-fns: '>= 2.x' + dayjs: '>= 1.x' + luxon: '>= 3.x' + moment: '>= 2.x' + react: '>=16.9.0' + react-dom: '>=16.9.0' + peerDependenciesMeta: + date-fns: + optional: true + dayjs: + optional: true + luxon: + optional: true + moment: + optional: true + '@rc-component/portal@1.1.2': resolution: {integrity: sha512-6f813C0IsasTZms08kfA8kPAGxbbkYToa8ALaiDIGGECU4i9hj8Plgbx0sNJDrey3EtHO30hmdaxtT0138xZcg==} engines: {node: '>=8.x'} @@ -4469,6 +4504,19 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' + '@rc-component/portal@2.2.0': + resolution: {integrity: sha512-oc6FlA+uXCMiwArHsJyHcIkX4q6uKyndrPol2eWX8YPkAnztHOPsFIRtmWG4BMlGE5h7YIRE3NiaJ5VS8Lb1QQ==} + engines: {node: '>=12.x'} + peerDependencies: + react: '>=18.0.0' + react-dom: '>=18.0.0' + + '@rc-component/progress@1.0.2': + resolution: {integrity: sha512-WZUnH9eGxH1+xodZKqdrHke59uyGZSWgj5HBM5Kwk5BrTMuAORO7VJ2IP5Qbm9aH3n9x3IcesqHHR0NWPBC7fQ==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + '@rc-component/qrcode@1.1.1': resolution: {integrity: sha512-LfLGNymzKdUPjXUbRP+xOhIWY4jQ+YMj5MmWAcgcAq1Ij8XP7tRmAXqyuv96XvLUBE/5cA8hLFl9eO1JQMujrA==} engines: {node: '>=8.x'} @@ -4476,6 +4524,78 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' + '@rc-component/rate@1.0.1': + resolution: {integrity: sha512-bkXxeBqDpl5IOC7yL7GcSYjQx9G8H+6kLYQnNZWeBYq2OYIv1MONd6mqKTjnnJYpV0cQIU2z3atdW0j1kttpTw==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/resize-observer@1.1.2': + resolution: {integrity: sha512-t/Bb0W8uvL4PYKAB3YcChC+DlHh0Wt5kM7q/J+0qpVEUMLe7Hk5zuvc9km0hMnTFPSx5Z7Wu/fzCLN6erVLE8Q==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/segmented@1.3.0': + resolution: {integrity: sha512-5J/bJ01mbDnoA6P/FW8SxUvKn+OgUSTZJPzCNnTBntG50tzoP7DydGhqxp7ggZXZls7me3mc2EQDXakU3iTVFg==} + peerDependencies: + react: '>=16.0.0' + react-dom: '>=16.0.0' + + '@rc-component/select@1.6.15': + resolution: {integrity: sha512-SyVCWnqxCQZZcQvQJ/CxSjx2bGma6ds/HtnpkIfZVnt6RoEgbqUmHgD6vrzNarNXwbLXerwVzWwq8F3d1sst7g==} + engines: {node: '>=8.x'} + peerDependencies: + react: '*' + react-dom: '*' + + '@rc-component/slider@1.0.1': + resolution: {integrity: sha512-uDhEPU1z3WDfCJhaL9jfd2ha/Eqpdfxsn0Zb0Xcq1NGQAman0TWaR37OWp2vVXEOdV2y0njSILTMpTfPV1454g==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/steps@1.2.2': + resolution: {integrity: sha512-/yVIZ00gDYYPHSY0JP+M+s3ZvuXLu2f9rEjQqiUDs7EcYsUYrpJ/1bLj9aI9R7MBR3fu/NGh6RM9u2qGfqp+Nw==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/switch@1.0.3': + resolution: {integrity: sha512-Jgi+EbOBquje/XNdofr7xbJQZPYJP+BlPfR0h+WN4zFkdtB2EWqEfvkXJWeipflwjWip0/17rNbxEAqs8hVHfw==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/table@1.9.1': + resolution: {integrity: sha512-FVI5ZS/GdB3BcgexfCYKi3iHhZS3Fr59EtsxORszYGrfpH1eWr33eDNSYkVfLI6tfJ7vftJDd9D5apfFWqkdJg==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=18.0.0' + react-dom: '>=18.0.0' + + '@rc-component/tabs@1.7.0': + resolution: {integrity: sha512-J48cs2iBi7Ho3nptBxxIqizEliUC+ExE23faspUQKGQ550vaBlv3aGF8Epv/UB1vFWeoJDTW/dNzgIU0Qj5i/w==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/textarea@1.1.2': + resolution: {integrity: sha512-9rMUEODWZDMovfScIEHXWlVZuPljZ2pd1LKNjslJVitn4SldEzq5vO1CL3yy3Dnib6zZal2r2DPtjy84VVpF6A==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/tooltip@1.4.0': + resolution: {integrity: sha512-8Rx5DCctIlLI4raR0I0xHjVTf1aF48+gKCNeAAo5bmF5VoR5YED+A/XEqzXv9KKqrJDRcd3Wndpxh2hyzrTtSg==} + peerDependencies: + react: '>=18.0.0' + react-dom: '>=18.0.0' + '@rc-component/tour@1.15.1': resolution: {integrity: sha512-Tr2t7J1DKZUpfJuDZWHxyxWpfmj8EZrqSgyMZ+BCdvKZ6r1UDsfU46M/iWAAFBy961Ssfom2kv5f3UcjIL2CmQ==} engines: {node: '>=8.x'} @@ -4483,6 +4603,26 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' + '@rc-component/tour@2.3.0': + resolution: {integrity: sha512-K04K9r32kUC+auBSQfr+Fss4SpSIS9JGe56oq/ALAX0p+i2ylYOI1MgR83yBY7v96eO6ZFXcM/igCQmubps0Ow==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/tree-select@1.8.0': + resolution: {integrity: sha512-iYsPq3nuLYvGqdvFAW+l+I9ASRIOVbMXyA8FGZg2lGym/GwkaWeJGzI4eJ7c9IOEhRj0oyfIN4S92Fl3J05mjQ==} + peerDependencies: + react: '*' + react-dom: '*' + + '@rc-component/tree@1.2.4': + resolution: {integrity: sha512-5Gli43+m4R7NhpYYz3Z61I6LOw9yI6CNChxgVtvrO6xB1qML7iE6QMLVMB3+FTjo2yF6uFdAHtqWPECz/zbX5w==} + engines: {node: '>=10.x'} + peerDependencies: + react: '*' + react-dom: '*' + '@rc-component/trigger@2.3.0': resolution: {integrity: sha512-iwaxZyzOuK0D7lS+0AQEtW52zUWxoGqTGkke3dRyb8pYiShmRpCjB/8TzPI4R6YySCH7Vm9BZj/31VPiiQTLBg==} engines: {node: '>=8.x'} @@ -4490,12 +4630,38 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' + '@rc-component/trigger@3.9.0': + resolution: {integrity: sha512-X8btpwfrT27AgrZVOz4swclhEHTZcqaHeQMXXBgveagOiakTa36uObXbdwerXffgV8G9dH1fAAE0DHtVQs8EHg==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=18.0.0' + react-dom: '>=18.0.0' + + '@rc-component/upload@1.1.0': + resolution: {integrity: sha512-LIBV90mAnUE6VK5N4QvForoxZc4XqEYZimcp7fk+lkE4XwHHyJWxpIXQQwMU8hJM+YwBbsoZkGksL1sISWHQxw==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/util@1.10.0': + resolution: {integrity: sha512-aY9GLBuiUdpyfIUpAWSYer4Tu3mVaZCo5A0q9NtXcazT3MRiI3/WNHCR+DUn5VAtR6iRRf0ynCqQUcHli5UdYw==} + peerDependencies: + react: '>=18.0.0' + react-dom: '>=18.0.0' + '@rc-component/util@1.4.0': resolution: {integrity: sha512-LQlShcJKu0p3JUTAenKrWtqVW0+c4PJKedOqEaef9gTVL70O3cG4xZJ7VXfm0blGzORKFEkd3oQGalaUBNZ3Lg==} peerDependencies: react: '>=18.0.0' react-dom: '>=18.0.0' + '@rc-component/virtual-list@1.0.2': + resolution: {integrity: sha512-uvTol/mH74FYsn5loDGJxo+7kjkO4i+y4j87Re1pxJBs0FaeuMuLRzQRGaXwnMcV1CxpZLi2Z56Rerj2M00fjQ==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + '@repeaterjs/repeater@3.0.6': resolution: {integrity: sha512-Javneu5lsuhwNCryN+pXH93VPQ8g0dBX7wItHFgYiwQmzE1sVdg5tWHiOgHywzL2W21XQopa7IwIEnNbmeUJYA==} @@ -5737,6 +5903,12 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' + antd@6.3.5: + resolution: {integrity: sha512-8BPz9lpZWQm42PTx7yL4KxWAotVuqINiKcoYRcLtdd5BFmAcAZicVyFTnBJyRDlzGZFZeRW3foGu6jXYFnej6Q==} + peerDependencies: + react: '>=18.0.0' + react-dom: '>=18.0.0' + any-promise@1.3.0: resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} @@ -9173,10 +9345,6 @@ packages: resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} engines: {node: '>= 0.4'} - oxc-parser@0.121.0: - resolution: {integrity: sha512-ek9o58+SCv6AV7nchiAcUJy1DNE2CC5WRdBcO0mF+W4oRjNQfPO7b3pLjTHSFECpHkKGOZSQxx3hk8viIL5YCg==} - engines: {node: ^20.19.0 || >=22.12.0} - oxc-resolver@11.14.0: resolution: {integrity: sha512-i4wNrqhOd+4YdHJfHglHtFiqqSxXuzFA+RUqmmWN1aMD3r1HqUSrIhw17tSO4jwKfhLs9uw1wzFPmvMsWacStg==} @@ -12230,13 +12398,6 @@ snapshots: ts-morph: 27.0.2 vitest: 4.1.2(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/browser-playwright@4.1.2)(jsdom@26.1.0)(vite@8.0.3(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)(@types/node@24.10.1)(esbuild@0.27.4)(jiti@2.6.1)(less@4.4.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)) - '@ant-design/cli@6.3.5(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)': - dependencies: - oxc-parser: 0.121.0(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1) - transitivePeerDependencies: - - '@emnapi/core' - - '@emnapi/runtime' - '@ant-design/colors@7.2.1': dependencies: '@ant-design/fast-color': 2.0.6 @@ -12245,6 +12406,10 @@ snapshots: dependencies: '@ant-design/fast-color': 3.0.0 + '@ant-design/colors@8.0.1': + dependencies: + '@ant-design/fast-color': 3.0.1 + '@ant-design/cssinjs-utils@1.1.3(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@ant-design/cssinjs': 1.24.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -12253,6 +12418,14 @@ snapshots: react: 19.2.0 react-dom: 19.2.0(react@19.2.0) + '@ant-design/cssinjs-utils@2.1.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@ant-design/cssinjs': 2.1.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@babel/runtime': 7.28.4 + '@rc-component/util': 1.10.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + '@ant-design/cssinjs@1.24.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@babel/runtime': 7.28.4 @@ -12265,12 +12438,26 @@ snapshots: react-dom: 19.2.0(react@19.2.0) stylis: 4.3.6 + '@ant-design/cssinjs@2.1.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@babel/runtime': 7.28.4 + '@emotion/hash': 0.8.0 + '@emotion/unitless': 0.7.5 + '@rc-component/util': 1.10.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + clsx: 2.1.1 + csstype: 3.2.3 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + stylis: 4.3.6 + '@ant-design/fast-color@2.0.6': dependencies: '@babel/runtime': 7.28.4 '@ant-design/fast-color@3.0.0': {} + '@ant-design/fast-color@3.0.1': {} + '@ant-design/icons-svg@4.4.2': {} '@ant-design/icons@5.6.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': @@ -12292,16 +12479,25 @@ snapshots: react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - '@ant-design/pro-layout@7.22.7(antd@5.29.1(luxon@3.6.1)(moment@2.30.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@ant-design/icons@6.1.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@ant-design/colors': 8.0.1 + '@ant-design/icons-svg': 4.4.2 + '@rc-component/util': 1.10.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + clsx: 2.1.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + '@ant-design/pro-layout@7.22.7(antd@6.3.5(luxon@3.6.1)(moment@2.30.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@ant-design/cssinjs': 1.24.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@ant-design/icons': 5.6.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@ant-design/pro-provider': 2.16.2(antd@5.29.1(luxon@3.6.1)(moment@2.30.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@ant-design/pro-utils': 2.18.0(antd@5.29.1(luxon@3.6.1)(moment@2.30.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@ant-design/pro-provider': 2.16.2(antd@6.3.5(luxon@3.6.1)(moment@2.30.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@ant-design/pro-utils': 2.18.0(antd@6.3.5(luxon@3.6.1)(moment@2.30.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@babel/runtime': 7.28.4 '@umijs/route-utils': 4.0.3 '@umijs/use-params': 1.0.9(react@19.2.0) - antd: 5.29.1(luxon@3.6.1)(moment@2.30.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + antd: 6.3.5(luxon@3.6.1)(moment@2.30.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) classnames: 2.5.1 lodash: 4.18.1 lodash-es: 4.18.1 @@ -12313,24 +12509,24 @@ snapshots: swr: 2.3.7(react@19.2.0) warning: 4.0.3 - '@ant-design/pro-provider@2.16.2(antd@5.29.1(luxon@3.6.1)(moment@2.30.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@ant-design/pro-provider@2.16.2(antd@6.3.5(luxon@3.6.1)(moment@2.30.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@ant-design/cssinjs': 1.24.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@babel/runtime': 7.28.4 '@ctrl/tinycolor': 3.6.1 - antd: 5.29.1(luxon@3.6.1)(moment@2.30.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + antd: 6.3.5(luxon@3.6.1)(moment@2.30.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) dayjs: 1.11.19 rc-util: 5.44.4(react-dom@19.2.0(react@19.2.0))(react@19.2.0) react: 19.2.0 react-dom: 19.2.0(react@19.2.0) swr: 2.3.7(react@19.2.0) - '@ant-design/pro-utils@2.18.0(antd@5.29.1(luxon@3.6.1)(moment@2.30.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@ant-design/pro-utils@2.18.0(antd@6.3.5(luxon@3.6.1)(moment@2.30.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@ant-design/icons': 5.6.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@ant-design/pro-provider': 2.16.2(antd@5.29.1(luxon@3.6.1)(moment@2.30.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@ant-design/pro-provider': 2.16.2(antd@6.3.5(luxon@3.6.1)(moment@2.30.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@babel/runtime': 7.28.4 - antd: 5.29.1(luxon@3.6.1)(moment@2.30.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + antd: 6.3.5(luxon@3.6.1)(moment@2.30.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) classnames: 2.5.1 dayjs: 1.11.19 lodash: 4.18.1 @@ -12350,6 +12546,15 @@ snapshots: resize-observer-polyfill: 1.5.1 throttle-debounce: 5.0.2 + '@ant-design/react-slick@2.0.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@babel/runtime': 7.28.4 + clsx: 2.1.1 + json2mq: 0.2.0 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + throttle-debounce: 5.0.2 + '@apollo/cache-control-types@1.0.3(graphql@16.12.0)': dependencies: graphql: 16.12.0 @@ -16025,94 +16230,27 @@ snapshots: '@opentelemetry/sdk-trace-node@1.30.1(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/context-async-hooks': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/propagator-b3': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/propagator-jaeger': 1.30.1(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-trace-base': 1.30.1(@opentelemetry/api@1.9.0) - semver: 7.7.3 - - '@opentelemetry/sdk-trace-web@2.2.0(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-trace-base': 2.2.0(@opentelemetry/api@1.9.0) - - '@opentelemetry/semantic-conventions@1.25.1': {} - - '@opentelemetry/semantic-conventions@1.28.0': {} - - '@opentelemetry/semantic-conventions@1.38.0': {} - - '@oxc-parser/binding-android-arm-eabi@0.121.0': - optional: true - - '@oxc-parser/binding-android-arm64@0.121.0': - optional: true - - '@oxc-parser/binding-darwin-arm64@0.121.0': - optional: true - - '@oxc-parser/binding-darwin-x64@0.121.0': - optional: true - - '@oxc-parser/binding-freebsd-x64@0.121.0': - optional: true - - '@oxc-parser/binding-linux-arm-gnueabihf@0.121.0': - optional: true - - '@oxc-parser/binding-linux-arm-musleabihf@0.121.0': - optional: true - - '@oxc-parser/binding-linux-arm64-gnu@0.121.0': - optional: true - - '@oxc-parser/binding-linux-arm64-musl@0.121.0': - optional: true - - '@oxc-parser/binding-linux-ppc64-gnu@0.121.0': - optional: true - - '@oxc-parser/binding-linux-riscv64-gnu@0.121.0': - optional: true - - '@oxc-parser/binding-linux-riscv64-musl@0.121.0': - optional: true - - '@oxc-parser/binding-linux-s390x-gnu@0.121.0': - optional: true - - '@oxc-parser/binding-linux-x64-gnu@0.121.0': - optional: true - - '@oxc-parser/binding-linux-x64-musl@0.121.0': - optional: true - - '@oxc-parser/binding-openharmony-arm64@0.121.0': - optional: true + '@opentelemetry/context-async-hooks': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/propagator-b3': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/propagator-jaeger': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 1.30.1(@opentelemetry/api@1.9.0) + semver: 7.7.3 - '@oxc-parser/binding-wasm32-wasi@0.121.0(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1)': + '@opentelemetry/sdk-trace-web@2.2.0(@opentelemetry/api@1.9.0)': dependencies: - '@napi-rs/wasm-runtime': 1.1.2(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1) - transitivePeerDependencies: - - '@emnapi/core' - - '@emnapi/runtime' - optional: true + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 2.2.0(@opentelemetry/api@1.9.0) - '@oxc-parser/binding-win32-arm64-msvc@0.121.0': - optional: true + '@opentelemetry/semantic-conventions@1.25.1': {} - '@oxc-parser/binding-win32-ia32-msvc@0.121.0': - optional: true + '@opentelemetry/semantic-conventions@1.28.0': {} - '@oxc-parser/binding-win32-x64-msvc@0.121.0': - optional: true + '@opentelemetry/semantic-conventions@1.38.0': {} '@oxc-project/types@0.103.0': {} - '@oxc-project/types@0.121.0': {} - '@oxc-project/types@0.122.0': {} '@oxc-resolver/binding-android-arm-eabi@11.14.0': @@ -16289,6 +16427,35 @@ snapshots: dependencies: '@babel/runtime': 7.28.4 + '@rc-component/async-validator@5.1.0': + dependencies: + '@babel/runtime': 7.28.4 + + '@rc-component/cascader@1.14.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@rc-component/select': 1.6.15(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/tree': 1.2.4(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/util': 1.10.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + clsx: 2.1.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + '@rc-component/checkbox@2.0.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@rc-component/util': 1.10.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + clsx: 2.1.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + '@rc-component/collapse@1.2.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@babel/runtime': 7.28.4 + '@rc-component/motion': 1.3.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/util': 1.10.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + clsx: 2.1.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + '@rc-component/color-picker@2.0.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@ant-design/fast-color': 2.0.6 @@ -16298,6 +16465,14 @@ snapshots: react: 19.2.0 react-dom: 19.2.0(react@19.2.0) + '@rc-component/color-picker@3.1.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@ant-design/fast-color': 3.0.1 + '@rc-component/util': 1.10.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + clsx: 2.1.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + '@rc-component/context@1.4.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@babel/runtime': 7.28.4 @@ -16305,10 +16480,102 @@ snapshots: react: 19.2.0 react-dom: 19.2.0(react@19.2.0) + '@rc-component/context@2.0.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@rc-component/util': 1.10.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + '@rc-component/dialog@1.8.4(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@rc-component/motion': 1.3.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/portal': 2.2.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/util': 1.10.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + clsx: 2.1.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + '@rc-component/drawer@1.4.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@rc-component/motion': 1.3.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/portal': 2.2.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/util': 1.10.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + clsx: 2.1.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + '@rc-component/dropdown@1.0.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@rc-component/trigger': 3.9.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/util': 1.10.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + clsx: 2.1.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + '@rc-component/form@1.8.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@rc-component/async-validator': 5.1.0 + '@rc-component/util': 1.10.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + clsx: 2.1.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + '@rc-component/image@1.8.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@rc-component/motion': 1.3.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/portal': 2.2.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/util': 1.10.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + clsx: 2.1.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + '@rc-component/input-number@1.6.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@rc-component/mini-decimal': 1.1.0 + '@rc-component/util': 1.10.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + clsx: 2.1.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + '@rc-component/input@1.1.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@rc-component/util': 1.10.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + clsx: 2.1.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + '@rc-component/mentions@1.6.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@rc-component/input': 1.1.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/menu': 1.2.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/textarea': 1.1.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/trigger': 3.9.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/util': 1.10.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + clsx: 2.1.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + '@rc-component/menu@1.2.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@rc-component/motion': 1.3.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/overflow': 1.0.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/trigger': 3.9.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/util': 1.10.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + clsx: 2.1.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + '@rc-component/mini-decimal@1.1.0': dependencies: '@babel/runtime': 7.28.4 + '@rc-component/motion@1.3.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@rc-component/util': 1.10.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + clsx: 2.1.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + '@rc-component/mutate-observer@1.1.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@babel/runtime': 7.28.4 @@ -16317,6 +16584,50 @@ snapshots: react: 19.2.0 react-dom: 19.2.0(react@19.2.0) + '@rc-component/mutate-observer@2.0.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@rc-component/util': 1.10.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + '@rc-component/notification@1.2.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@rc-component/motion': 1.3.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/util': 1.10.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + clsx: 2.1.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + '@rc-component/overflow@1.0.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@babel/runtime': 7.28.4 + '@rc-component/resize-observer': 1.1.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/util': 1.10.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + clsx: 2.1.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + '@rc-component/pagination@1.2.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@rc-component/util': 1.10.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + clsx: 2.1.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + '@rc-component/picker@1.9.1(dayjs@1.11.19)(luxon@3.6.1)(moment@2.30.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@rc-component/overflow': 1.0.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/resize-observer': 1.1.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/trigger': 3.9.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/util': 1.10.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + clsx: 2.1.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + dayjs: 1.11.19 + luxon: 3.6.1 + moment: 2.30.1 + '@rc-component/portal@1.1.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@babel/runtime': 7.28.4 @@ -16325,12 +16636,117 @@ snapshots: react: 19.2.0 react-dom: 19.2.0(react@19.2.0) + '@rc-component/portal@2.2.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@rc-component/util': 1.10.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + clsx: 2.1.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + '@rc-component/progress@1.0.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@rc-component/util': 1.10.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + clsx: 2.1.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + '@rc-component/qrcode@1.1.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@babel/runtime': 7.28.4 react: 19.2.0 react-dom: 19.2.0(react@19.2.0) + '@rc-component/rate@1.0.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@rc-component/util': 1.10.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + clsx: 2.1.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + '@rc-component/resize-observer@1.1.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@rc-component/util': 1.10.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + '@rc-component/segmented@1.3.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@babel/runtime': 7.28.4 + '@rc-component/motion': 1.3.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/util': 1.10.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + clsx: 2.1.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + '@rc-component/select@1.6.15(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@rc-component/overflow': 1.0.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/trigger': 3.9.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/util': 1.10.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/virtual-list': 1.0.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + clsx: 2.1.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + '@rc-component/slider@1.0.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@rc-component/util': 1.10.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + clsx: 2.1.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + '@rc-component/steps@1.2.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@rc-component/util': 1.10.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + clsx: 2.1.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + '@rc-component/switch@1.0.3(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@rc-component/util': 1.10.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + clsx: 2.1.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + '@rc-component/table@1.9.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@rc-component/context': 2.0.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/resize-observer': 1.1.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/util': 1.10.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/virtual-list': 1.0.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + clsx: 2.1.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + '@rc-component/tabs@1.7.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@rc-component/dropdown': 1.0.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/menu': 1.2.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/motion': 1.3.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/resize-observer': 1.1.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/util': 1.10.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + clsx: 2.1.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + '@rc-component/textarea@1.1.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@rc-component/input': 1.1.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/resize-observer': 1.1.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/util': 1.10.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + clsx: 2.1.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + '@rc-component/tooltip@1.4.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@rc-component/trigger': 3.9.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/util': 1.10.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + clsx: 2.1.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + '@rc-component/tour@1.15.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@babel/runtime': 7.28.4 @@ -16341,6 +16757,33 @@ snapshots: react: 19.2.0 react-dom: 19.2.0(react@19.2.0) + '@rc-component/tour@2.3.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@rc-component/portal': 2.2.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/trigger': 3.9.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/util': 1.10.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + clsx: 2.1.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + '@rc-component/tree-select@1.8.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@rc-component/select': 1.6.15(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/tree': 1.2.4(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/util': 1.10.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + clsx: 2.1.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + '@rc-component/tree@1.2.4(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@rc-component/motion': 1.3.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/util': 1.10.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/virtual-list': 1.0.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + clsx: 2.1.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + '@rc-component/trigger@2.3.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@babel/runtime': 7.28.4 @@ -16352,6 +16795,30 @@ snapshots: react: 19.2.0 react-dom: 19.2.0(react@19.2.0) + '@rc-component/trigger@3.9.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@rc-component/motion': 1.3.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/portal': 2.2.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/resize-observer': 1.1.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/util': 1.10.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + clsx: 2.1.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + '@rc-component/upload@1.1.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@rc-component/util': 1.10.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + clsx: 2.1.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + '@rc-component/util@1.10.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + is-mobile: 5.0.0 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + react-is: 18.3.1 + '@rc-component/util@1.4.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: is-mobile: 5.0.0 @@ -16359,6 +16826,15 @@ snapshots: react-dom: 19.2.0(react@19.2.0) react-is: 18.3.1 + '@rc-component/virtual-list@1.0.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@babel/runtime': 7.28.4 + '@rc-component/resize-observer': 1.1.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/util': 1.10.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + clsx: 2.1.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + '@repeaterjs/repeater@3.0.6': {} '@rolldown/binding-android-arm64@1.0.0-beta.55': @@ -17722,6 +18198,63 @@ snapshots: - luxon - moment + antd@6.3.5(luxon@3.6.1)(moment@2.30.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + dependencies: + '@ant-design/colors': 8.0.1 + '@ant-design/cssinjs': 2.1.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@ant-design/cssinjs-utils': 2.1.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@ant-design/fast-color': 3.0.1 + '@ant-design/icons': 6.1.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@ant-design/react-slick': 2.0.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@babel/runtime': 7.28.4 + '@rc-component/cascader': 1.14.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/checkbox': 2.0.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/collapse': 1.2.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/color-picker': 3.1.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/dialog': 1.8.4(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/drawer': 1.4.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/dropdown': 1.0.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/form': 1.8.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/image': 1.8.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/input': 1.1.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/input-number': 1.6.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/mentions': 1.6.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/menu': 1.2.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/motion': 1.3.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/mutate-observer': 2.0.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/notification': 1.2.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/pagination': 1.2.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/picker': 1.9.1(dayjs@1.11.19)(luxon@3.6.1)(moment@2.30.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/progress': 1.0.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/qrcode': 1.1.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/rate': 1.0.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/resize-observer': 1.1.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/segmented': 1.3.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/select': 1.6.15(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/slider': 1.0.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/steps': 1.2.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/switch': 1.0.3(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/table': 1.9.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/tabs': 1.7.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/textarea': 1.1.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/tooltip': 1.4.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/tour': 2.3.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/tree': 1.2.4(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/tree-select': 1.8.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/trigger': 3.9.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/upload': 1.1.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@rc-component/util': 1.10.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + clsx: 2.1.1 + dayjs: 1.11.19 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + scroll-into-view-if-needed: 3.1.0 + throttle-debounce: 5.0.2 + transitivePeerDependencies: + - date-fns + - luxon + - moment + any-promise@1.3.0: {} anymatch@3.1.3: @@ -20478,7 +21011,7 @@ snapshots: whatwg-encoding: 3.1.1 whatwg-mimetype: 4.0.0 whatwg-url: 14.2.0 - ws: 8.18.3 + ws: 8.20.0 xml-name-validator: 5.0.0 transitivePeerDependencies: - bufferutil @@ -21578,7 +22111,7 @@ snapshots: needle@3.3.1: dependencies: iconv-lite: 0.6.3 - sax: 1.4.3 + sax: 1.5.0 optional: true negotiator@0.6.3: {} @@ -21760,34 +22293,6 @@ snapshots: object-keys: 1.1.1 safe-push-apply: 1.0.0 - oxc-parser@0.121.0(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1): - dependencies: - '@oxc-project/types': 0.121.0 - optionalDependencies: - '@oxc-parser/binding-android-arm-eabi': 0.121.0 - '@oxc-parser/binding-android-arm64': 0.121.0 - '@oxc-parser/binding-darwin-arm64': 0.121.0 - '@oxc-parser/binding-darwin-x64': 0.121.0 - '@oxc-parser/binding-freebsd-x64': 0.121.0 - '@oxc-parser/binding-linux-arm-gnueabihf': 0.121.0 - '@oxc-parser/binding-linux-arm-musleabihf': 0.121.0 - '@oxc-parser/binding-linux-arm64-gnu': 0.121.0 - '@oxc-parser/binding-linux-arm64-musl': 0.121.0 - '@oxc-parser/binding-linux-ppc64-gnu': 0.121.0 - '@oxc-parser/binding-linux-riscv64-gnu': 0.121.0 - '@oxc-parser/binding-linux-riscv64-musl': 0.121.0 - '@oxc-parser/binding-linux-s390x-gnu': 0.121.0 - '@oxc-parser/binding-linux-x64-gnu': 0.121.0 - '@oxc-parser/binding-linux-x64-musl': 0.121.0 - '@oxc-parser/binding-openharmony-arm64': 0.121.0 - '@oxc-parser/binding-wasm32-wasi': 0.121.0(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1) - '@oxc-parser/binding-win32-arm64-msvc': 0.121.0 - '@oxc-parser/binding-win32-ia32-msvc': 0.121.0 - '@oxc-parser/binding-win32-x64-msvc': 0.121.0 - transitivePeerDependencies: - - '@emnapi/core' - - '@emnapi/runtime' - oxc-resolver@11.14.0(@emnapi/core@1.7.1)(@emnapi/runtime@1.7.1): optionalDependencies: '@oxc-resolver/binding-android-arm-eabi': 11.14.0 From 1d26c0348957b786b827d8888442a2e4ed65612e Mon Sep 17 00:00:00 2001 From: Rohit Kumar Date: Mon, 6 Apr 2026 23:33:56 +0530 Subject: [PATCH 3/3] Fix: Stories issue --- .../layouts/admin/components/member-add-modal.stories.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/ui-community/src/components/layouts/admin/components/member-add-modal.stories.tsx b/apps/ui-community/src/components/layouts/admin/components/member-add-modal.stories.tsx index a58a66fd6..371569802 100644 --- a/apps/ui-community/src/components/layouts/admin/components/member-add-modal.stories.tsx +++ b/apps/ui-community/src/components/layouts/admin/components/member-add-modal.stories.tsx @@ -6,7 +6,6 @@ const meta: Meta = { title: 'Admin/MemberAddModal', component: MemberAddModal, args: { - communityId: 'community-123', open: true, loading: false, onAdd: fn(),