From 7707708f33970fe9988939ac68510d0acbf7c129 Mon Sep 17 00:00:00 2001 From: Meetul Rathore Date: Sat, 2 Nov 2024 17:59:18 +0530 Subject: [PATCH 1/2] feat: Add filtering and sorting on userTag screens (GSoC) (#2398) * add people to tag functaionality * minor change * more translations * minor change * add a variable for page size * add tag actions * add tests * translations * change to infinite scroll * add subtags infinite scroll * extract common variables to utils * minor correction * more design adjustments * add tests * add scrollbar for infinite scroll * extract infinite scroll loader * minor adjustment * refactoring * exclude ManageTag from countline check * fix linting * fix linting * fix linting * make coderabbit suggested changes * more changes * more changes * minor correction * add error component for tagNode subtags query * fix translation * fix translation * remove unused css classes * refactor ManageTag file to reduce its size * update pull-request check * minor adjustments * minor correction * minor change * correction * minor changes * minor change * coderabbitai changes * more changes * fix dataGrid classes * remove getUserTagAncestors query * add search and sort * add tests * error toast on no seletion tag/user * minor correction * fix test * minor change * add useEffect * exclude TagActionsMocks from countlines check * coderabbitai suggested changes * show sort order --- .github/workflows/pull-request.yml | 2 +- public/locales/en/translation.json | 7 +- public/locales/fr/translation.json | 7 +- public/locales/hi/translation.json | 7 +- public/locales/sp/translation.json | 7 +- public/locales/zh/translation.json | 7 +- src/GraphQl/Queries/OrganizationQueries.ts | 18 +- src/GraphQl/Queries/userTagQueries.ts | 45 ++- .../AddPeopleToTag/AddPeopleToTag.module.css | 9 +- .../AddPeopleToTag/AddPeopleToTag.test.tsx | 123 +++++- .../AddPeopleToTag/AddPeopleToTag.tsx | 120 ++++-- .../AddPeopleToTag/AddPeopleToTagsMocks.ts | 106 ++++++ .../TagActions/TagActions.module.css | 10 +- src/components/TagActions/TagActions.test.tsx | 36 ++ src/components/TagActions/TagActions.tsx | 162 ++++---- src/components/TagActions/TagActionsMocks.ts | 173 +++++++++ src/components/TagActions/TagNode.tsx | 2 +- src/screens/ManageTag/ManageTag.test.tsx | 95 ++++- src/screens/ManageTag/ManageTag.tsx | 357 +++++++++--------- src/screens/ManageTag/ManageTagMocks.ts | 163 +++++--- .../OrganizationTags.test.tsx | 88 ++++- .../OrganizationTags/OrganizationTags.tsx | 198 ++++++---- .../OrganizationTags/OrganizationTagsMocks.ts | 178 +++++++++ src/screens/SubTags/SubTags.test.tsx | 142 +++++-- src/screens/SubTags/SubTags.tsx | 237 ++++++------ src/screens/SubTags/SubTagsMocks.ts | 298 +++++++++++---- src/utils/interfaces.ts | 18 +- src/utils/organizationTagsUtils.ts | 3 + 28 files changed, 1888 insertions(+), 730 deletions(-) diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index a0a542f3cf..27f18e28ab 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -38,7 +38,7 @@ jobs: - name: Count number of lines run: | chmod +x ./.github/workflows/countline.py - ./.github/workflows/countline.py --lines 600 --exclude_files src/screens/LoginPage/LoginPage.tsx src/GraphQl/Queries/Queries.ts src/screens/OrgList/OrgList.tsx src/GraphQl/Mutations/mutations.ts src/components/EventListCard/EventListCardModals.tsx + ./.github/workflows/countline.py --lines 600 --exclude_files src/screens/LoginPage/LoginPage.tsx src/GraphQl/Queries/Queries.ts src/screens/OrgList/OrgList.tsx src/GraphQl/Mutations/mutations.ts src/components/EventListCard/EventListCardModals.tsx src/components/TagActions/TagActionsMocks.ts - name: Get changed TypeScript files id: changed-files diff --git a/public/locales/en/translation.json b/public/locales/en/translation.json index 7d2108bc06..55865167d5 100644 --- a/public/locales/en/translation.json +++ b/public/locales/en/translation.json @@ -320,7 +320,8 @@ "noTagsFound": "No tags found", "removeUserTag": "Delete Tag", "removeUserTagMessage": "Do you want to delete this tag?", - "addChildTag": "Add a Sub Tag" + "addChildTag": "Add a Sub Tag", + "enterTagName": "Enter Tag Name" }, "manageTag": { "title": "Tag Details", @@ -333,7 +334,6 @@ "addPeople": "Add People", "add": "Add", "subTags": "Sub Tags", - "assignedToAll": "Tag Assigned to All", "successfullyAssignedToPeople": "Tag assigned successfully", "errorOccurredWhileLoadingMembers": "Error occured while loading members", "userName": "User Name", @@ -359,7 +359,8 @@ "collapse": "Collapse", "expand": "Expand", "tagNamePlaceholder": "Write the name of the tag", - "allTags": "All Tags" + "allTags": "All Tags", + "noMoreMembersFound": "No more members found" }, "userListCard": { "addAdmin": "Add Admin", diff --git a/public/locales/fr/translation.json b/public/locales/fr/translation.json index 7f74826272..8bdb3e854a 100644 --- a/public/locales/fr/translation.json +++ b/public/locales/fr/translation.json @@ -320,7 +320,8 @@ "noTagsFound": "Aucune étiquette trouvée", "removeUserTag": "Supprimer l'Étiquette", "removeUserTagMessage": "Voulez-vous supprimer cette étiquette ?", - "addChildTag": "Ajouter une Sous-Étiquette" + "addChildTag": "Ajouter une Sous-Étiquette", + "enterTagName": "Entrez le nom de l'étiquette" }, "manageTag": { "title": "Détails de l'étiquette", @@ -333,7 +334,6 @@ "addPeople": "Ajouter des personnes", "add": "Ajouter", "subTags": "Sous-étiquettes", - "assignedToAll": "Étiquette attribuée à tous", "successfullyAssignedToPeople": "Étiquette attribuée avec succès", "errorOccurredWhileLoadingMembers": "Erreur survenue lors du chargement des membres", "userName": "Nom d'utilisateur", @@ -359,7 +359,8 @@ "collapse": "Réduire", "expand": "Développer", "tagNamePlaceholder": "Écrire le nom de l'étiquette", - "allTags": "Toutes les étiquettes" + "allTags": "Toutes les étiquettes", + "noMoreMembersFound": "Aucun autre membre trouvé" }, "userListCard": { "addAdmin": "Ajouter un administrateur", diff --git a/public/locales/hi/translation.json b/public/locales/hi/translation.json index 4384648ca3..b3b00bd989 100644 --- a/public/locales/hi/translation.json +++ b/public/locales/hi/translation.json @@ -320,7 +320,8 @@ "noTagsFound": "कोई टैग नहीं मिला", "removeUserTag": "टैग हटाएँ", "removeUserTagMessage": "क्या आप इस टैग को हटाना चाहते हैं?", - "addChildTag": "उप-टैग जोड़ें" + "addChildTag": "उप-टैग जोड़ें", + "enterTagName": "टैग का नाम दर्ज करें" }, "manageTag": { "title": "टैग विवरण", @@ -333,7 +334,6 @@ "addPeople": "लोगों को जोड़ें", "add": "जोड़ें", "subTags": "उप-टैग्स", - "assignedToAll": "सभी को टैग असाइन किया गया", "successfullyAssignedToPeople": "टैग सफलतापूर्वक असाइन किया गया", "errorOccurredWhileLoadingMembers": "सदस्यों को लोड करते समय त्रुटि हुई", "userName": "उपयोगकर्ता नाम", @@ -359,7 +359,8 @@ "collapse": "संक्षिप्त करें", "expand": "विस्तारित करें", "tagNamePlaceholder": "टैग का नाम लिखें", - "allTags": "सभी टैग" + "allTags": "सभी टैग", + "noMoreMembersFound": "कोई और सदस्य नहीं मिला" }, "userListCard": { "addAdmin": "व्यवस्थापक जोड़ें", diff --git a/public/locales/sp/translation.json b/public/locales/sp/translation.json index 24ce0dbdec..f698238e56 100644 --- a/public/locales/sp/translation.json +++ b/public/locales/sp/translation.json @@ -320,7 +320,8 @@ "noTagsFound": "No se encontraron etiquetas", "removeUserTag": "Eliminar Etiqueta", "removeUserTagMessage": "¿Desea eliminar esta etiqueta?", - "addChildTag": "Agregar una Sub Etiqueta" + "addChildTag": "Agregar una Sub Etiqueta", + "enterTagName": "Ingrese el nombre de la etiqueta" }, "manageTag": { "title": "Detalles de la Etiqueta", @@ -333,7 +334,6 @@ "addPeople": "Agregar Personas", "add": "Agregar", "subTags": "Subetiquetas", - "assignedToAll": "Etiqueta asignada a todos", "successfullyAssignedToPeople": "Etiqueta asignada con éxito", "errorOccurredWhileLoadingMembers": "Error al cargar los miembros", "userName": "Nombre de usuario", @@ -359,7 +359,8 @@ "collapse": "Colapsar", "expand": "Expandir", "tagNamePlaceholder": "Escribe el nombre de la etiqueta", - "allTags": "Todas las etiquetas" + "allTags": "Todas las etiquetas", + "noMoreMembersFound": "No se encontraron más miembros" }, "userListCard": { "joined": "Unido", diff --git a/public/locales/zh/translation.json b/public/locales/zh/translation.json index 0c070bcf8b..5d8cfc4826 100644 --- a/public/locales/zh/translation.json +++ b/public/locales/zh/translation.json @@ -320,7 +320,8 @@ "noTagsFound": "未找到标签", "removeUserTag": "删除标签", "removeUserTagMessage": "您确定要删除此标签吗?", - "addChildTag": "添加子标签" + "addChildTag": "添加子标签", + "enterTagName": "输入标签名称" }, "manageTag": { "title": "标签详情", @@ -333,7 +334,6 @@ "addPeople": "添加人员", "add": "添加", "subTags": "子标签", - "assignedToAll": "标签分配给所有人", "successfullyAssignedToPeople": "标签分配成功", "errorOccurredWhileLoadingMembers": "加载成员时出错", "userName": "用户名", @@ -359,7 +359,8 @@ "collapse": "收起", "expand": "展开", "tagNamePlaceholder": "输入标签名称", - "allTags": "所有标签" + "allTags": "所有标签", + "noMoreMembersFound": "未找到更多成员" }, "userListCard": { "addAdmin": "添加管理员", diff --git a/src/GraphQl/Queries/OrganizationQueries.ts b/src/GraphQl/Queries/OrganizationQueries.ts index 315c50ebf4..4dc7dd7a09 100644 --- a/src/GraphQl/Queries/OrganizationQueries.ts +++ b/src/GraphQl/Queries/OrganizationQueries.ts @@ -89,19 +89,35 @@ export const ORGANIZATION_USER_TAGS_LIST = gql` $before: String $first: PositiveInt $last: PositiveInt + $where: UserTagWhereInput + $sortedBy: UserTagSortedByInput ) { organizations(id: $id) { - userTags(after: $after, before: $before, first: $first, last: $last) { + userTags( + after: $after + before: $before + first: $first + last: $last + where: $where + sortedBy: $sortedBy + ) { edges { node { _id name + parentTag { + _id + } usersAssignedTo(first: $first, last: $last) { totalCount } childTags(first: $first, last: $last) { totalCount } + ancestorTags { + _id + name + } } cursor } diff --git a/src/GraphQl/Queries/userTagQueries.ts b/src/GraphQl/Queries/userTagQueries.ts index 33a9b63174..d58da19e1b 100644 --- a/src/GraphQl/Queries/userTagQueries.ts +++ b/src/GraphQl/Queries/userTagQueries.ts @@ -14,6 +14,8 @@ export const USER_TAGS_ASSIGNED_MEMBERS = gql` $before: String $first: PositiveInt $last: PositiveInt + $where: UserTagUsersAssignedToWhereInput + $sortedBy: UserTagUsersAssignedToSortedByInput ) { getAssignedUsers: getUserTag(id: $id) { name @@ -22,6 +24,8 @@ export const USER_TAGS_ASSIGNED_MEMBERS = gql` before: $before first: $first last: $last + where: $where + sortedBy: $sortedBy ) { edges { node { @@ -38,6 +42,10 @@ export const USER_TAGS_ASSIGNED_MEMBERS = gql` } totalCount } + ancestorTags { + _id + name + } } } `; @@ -56,10 +64,19 @@ export const USER_TAG_SUB_TAGS = gql` $before: String $first: PositiveInt $last: PositiveInt + $where: UserTagWhereInput + $sortedBy: UserTagSortedByInput ) { getChildTags: getUserTag(id: $id) { name - childTags(after: $after, before: $before, first: $first, last: $last) { + childTags( + after: $after + before: $before + first: $first + last: $last + where: $where + sortedBy: $sortedBy + ) { edges { node { _id @@ -70,6 +87,10 @@ export const USER_TAG_SUB_TAGS = gql` childTags(first: $first, last: $last) { totalCount } + ancestorTags { + _id + name + } } } pageInfo { @@ -80,6 +101,10 @@ export const USER_TAG_SUB_TAGS = gql` } totalCount } + ancestorTags { + _id + name + } } } `; @@ -98,6 +123,7 @@ export const USER_TAGS_MEMBERS_TO_ASSIGN_TO = gql` $before: String $first: PositiveInt $last: PositiveInt + $where: UserTagUsersToAssignToWhereInput ) { getUsersToAssignTo: getUserTag(id: $id) { name @@ -106,6 +132,7 @@ export const USER_TAGS_MEMBERS_TO_ASSIGN_TO = gql` before: $before first: $first last: $last + where: $where ) { edges { node { @@ -125,19 +152,3 @@ export const USER_TAGS_MEMBERS_TO_ASSIGN_TO = gql` } } `; - -/** - * GraphQL query to retrieve the ancestor tags of a certain tag. - * - * @param id - The ID of the current tag. - * @returns The list of ancestor tags. - */ - -export const USER_TAG_ANCESTORS = gql` - query GetUserTagAncestors($id: ID!) { - getUserTagAncestors(id: $id) { - _id - name - } - } -`; diff --git a/src/components/AddPeopleToTag/AddPeopleToTag.module.css b/src/components/AddPeopleToTag/AddPeopleToTag.module.css index c7c5c4582b..5dd04ffed5 100644 --- a/src/components/AddPeopleToTag/AddPeopleToTag.module.css +++ b/src/components/AddPeopleToTag/AddPeopleToTag.module.css @@ -28,7 +28,7 @@ } .scrollContainer { - max-height: 100px; + height: 100px; overflow-y: auto; margin-bottom: 1rem; } @@ -45,3 +45,10 @@ .removeFilterIcon { cursor: pointer; } + +.loadingDiv { + min-height: 300px; + display: flex; + justify-content: center; + align-items: center; +} diff --git a/src/components/AddPeopleToTag/AddPeopleToTag.test.tsx b/src/components/AddPeopleToTag/AddPeopleToTag.test.tsx index e21ccd1a52..824bc25654 100644 --- a/src/components/AddPeopleToTag/AddPeopleToTag.test.tsx +++ b/src/components/AddPeopleToTag/AddPeopleToTag.test.tsx @@ -17,7 +17,7 @@ import { store } from 'state/store'; import userEvent from '@testing-library/user-event'; import { StaticMockLink } from 'utils/StaticMockLink'; import { toast } from 'react-toastify'; -import type { ApolloLink } from '@apollo/client'; +import { InMemoryCache, type ApolloLink } from '@apollo/client'; import type { InterfaceAddPeopleToTagProps } from './AddPeopleToTag'; import AddPeopleToTag from './AddPeopleToTag'; import i18n from 'utils/i18nForTest'; @@ -63,12 +63,39 @@ const props: InterfaceAddPeopleToTagProps = { >, }; +const cache = new InMemoryCache({ + typePolicies: { + Query: { + fields: { + getUserTag: { + merge(existing = {}, incoming) { + const merged = { + ...existing, + ...incoming, + usersToAssignTo: { + ...existing.usersToAssignTo, + ...incoming.usersToAssignTo, + edges: [ + ...(existing.usersToAssignTo?.edges || []), + ...(incoming.usersToAssignTo?.edges || []), + ], + }, + }; + + return merged; + }, + }, + }, + }, + }, +}); + const renderAddPeopleToTagModal = ( props: InterfaceAddPeopleToTagProps, link: ApolloLink, ): RenderResult => { return render( - + @@ -91,7 +118,7 @@ describe('Organisation Tags Page', () => { ...jest.requireActual('react-router-dom'), useParams: () => ({ orgId: 'orgId' }), })); - // cache.reset(); + cache.reset(); }); afterEach(() => { @@ -147,6 +174,72 @@ describe('Organisation Tags Page', () => { userEvent.click(screen.getAllByTestId('deselectMemberBtn')[0]); }); + test('searchs for tags where the firstName matches the provided firstName search input', async () => { + renderAddPeopleToTagModal(props, link); + + await wait(); + + await waitFor(() => { + expect( + screen.getByPlaceholderText(translations.firstName), + ).toBeInTheDocument(); + }); + const input = screen.getByPlaceholderText(translations.firstName); + fireEvent.change(input, { target: { value: 'usersToAssignTo' } }); + + // should render the two users from the mock data + // where firstName starts with "usersToAssignTo" + await waitFor(() => { + const members = screen.getAllByTestId('memberName'); + expect(members.length).toEqual(2); + }); + + await waitFor(() => { + expect(screen.getAllByTestId('memberName')[0]).toHaveTextContent( + 'usersToAssignTo user1', + ); + }); + + await waitFor(() => { + expect(screen.getAllByTestId('memberName')[1]).toHaveTextContent( + 'usersToAssignTo user2', + ); + }); + }); + + test('searchs for tags where the lastName matches the provided lastName search input', async () => { + renderAddPeopleToTagModal(props, link); + + await wait(); + + await waitFor(() => { + expect( + screen.getByPlaceholderText(translations.lastName), + ).toBeInTheDocument(); + }); + const input = screen.getByPlaceholderText(translations.lastName); + fireEvent.change(input, { target: { value: 'userToAssignTo' } }); + + // should render the two users from the mock data + // where lastName starts with "usersToAssignTo" + await waitFor(() => { + const members = screen.getAllByTestId('memberName'); + expect(members.length).toEqual(2); + }); + + await waitFor(() => { + expect(screen.getAllByTestId('memberName')[0]).toHaveTextContent( + 'first userToAssignTo', + ); + }); + + await waitFor(() => { + expect(screen.getAllByTestId('memberName')[1]).toHaveTextContent( + 'second userToAssignTo', + ); + }); + }); + test('Renders more members with infinite scroll', async () => { const { getByText } = renderAddPeopleToTagModal(props, link); @@ -157,13 +250,15 @@ describe('Organisation Tags Page', () => { }); // Find the infinite scroll div by test ID or another selector - const scrollableDiv = screen.getByTestId('scrollableDiv'); + const addPeopleToTagScrollableDiv = screen.getByTestId( + 'addPeopleToTagScrollableDiv', + ); const initialMemberDataLength = screen.getAllByTestId('memberName').length; // Set scroll position to the bottom - fireEvent.scroll(scrollableDiv, { - target: { scrollY: scrollableDiv.scrollHeight }, + fireEvent.scroll(addPeopleToTagScrollableDiv, { + target: { scrollY: addPeopleToTagScrollableDiv.scrollHeight }, }); await waitFor(() => { @@ -174,11 +269,27 @@ describe('Organisation Tags Page', () => { }); }); + test('Toasts error when no one is selected while assigning', async () => { + renderAddPeopleToTagModal(props, link); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('assignPeopleBtn')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('assignPeopleBtn')); + + await waitFor(() => { + expect(toast.error).toHaveBeenCalledWith(translations.noOneSelected); + }); + }); + test('Assigns tag to multiple people', async () => { renderAddPeopleToTagModal(props, link); await wait(); + // select members and assign them await waitFor(() => { expect(screen.getAllByTestId('selectMemberBtn')[0]).toBeInTheDocument(); }); diff --git a/src/components/AddPeopleToTag/AddPeopleToTag.tsx b/src/components/AddPeopleToTag/AddPeopleToTag.tsx index f5c90be096..51d21a6a1c 100644 --- a/src/components/AddPeopleToTag/AddPeopleToTag.tsx +++ b/src/components/AddPeopleToTag/AddPeopleToTag.tsx @@ -1,10 +1,9 @@ import { useMutation, useQuery } from '@apollo/client'; import type { GridCellParams, GridColDef } from '@mui/x-data-grid'; import { DataGrid } from '@mui/x-data-grid'; -import Loader from 'components/Loader/Loader'; import { USER_TAGS_MEMBERS_TO_ASSIGN_TO } from 'GraphQl/Queries/userTagQueries'; import type { ChangeEvent } from 'react'; -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { Modal, Form, Button } from 'react-bootstrap'; import { useParams } from 'react-router-dom'; import type { InterfaceQueryUserTagsMembersToAssignTo } from 'utils/interfaces'; @@ -55,10 +54,16 @@ const AddPeopleToTag: React.FC = ({ [], ); + const [memberToAssignToSearchFirstName, setMemberToAssignToSearchFirstName] = + useState(''); + const [memberToAssignToSearchLastName, setMemberToAssignToSearchLastName] = + useState(''); + const { data: userTagsMembersToAssignToData, loading: userTagsMembersToAssignToLoading, error: userTagsMembersToAssignToError, + refetch: userTagsMembersToAssignToRefetch, fetchMore: fetchMoreMembersToAssignTo, }: InterfaceTagUsersToAssignToQuery = useQuery( USER_TAGS_MEMBERS_TO_ASSIGN_TO, @@ -66,12 +71,21 @@ const AddPeopleToTag: React.FC = ({ variables: { id: currentTagId, first: TAGS_QUERY_DATA_CHUNK_SIZE, + where: { + firstName: { starts_with: memberToAssignToSearchFirstName }, + lastName: { starts_with: memberToAssignToSearchLastName }, + }, }, skip: !addPeopleToTagModalIsOpen, - fetchPolicy: 'no-cache', }, ); + useEffect(() => { + setMemberToAssignToSearchFirstName(''); + setMemberToAssignToSearchLastName(''); + userTagsMembersToAssignToRefetch(); + }, [addPeopleToTagModalIsOpen]); + const loadMoreMembersToAssignTo = (): void => { fetchMoreMembersToAssignTo({ variables: { @@ -92,7 +106,7 @@ const AddPeopleToTag: React.FC = ({ }; }, ) => { - if (!fetchMoreResult) return prevResult; + if (!fetchMoreResult) /* istanbul ignore next */ return prevResult; return { getUsersToAssignTo: { @@ -140,6 +154,11 @@ const AddPeopleToTag: React.FC = ({ ): Promise => { e.preventDefault(); + if (!assignToMembers.length) { + toast.error(t('noOneSelected')); + return; + } + try { const { data } = await addPeople({ variables: { @@ -252,39 +271,72 @@ const AddPeopleToTag: React.FC = ({
+
+ {assignToMembers.length === 0 ? ( +
+ {t('noOneSelected')} +
+ ) : ( + assignToMembers.map((member) => ( +
+ {member.firstName} {member.lastName} + removeMember(member._id)} + data-testid="clearSelectedMember" + /> +
+ )) + )} +
+ +
+
+ + + setMemberToAssignToSearchFirstName(e.target.value.trim()) + } + data-testid="searchByFirstName" + autoComplete="off" + /> +
+
+ + + setMemberToAssignToSearchLastName(e.target.value.trim()) + } + data-testid="searchByLastName" + autoComplete="off" + /> +
+
+ {userTagsMembersToAssignToLoading ? ( - +
+ +
) : ( <>
- {assignToMembers.length === 0 ? ( -
- {t('noOneSelected')} -
- ) : ( - assignToMembers.map((member) => ( -
- {member.firstName} {member.lastName} - removeMember(member._id)} - data-testid="clearSelectedMember" - /> -
- )) - )} -
- -
@@ -297,7 +349,7 @@ const AddPeopleToTag: React.FC = ({ /* istanbul ignore next */ false } loader={} - scrollableTarget="scrollableDiv" + scrollableTarget="addPeopleToTagScrollableDiv" > = ({ alignItems="center" justifyContent="center" > - {t('assignedToAll')} + {t('noMoreMembersFound')} ), }} diff --git a/src/components/AddPeopleToTag/AddPeopleToTagsMocks.ts b/src/components/AddPeopleToTag/AddPeopleToTagsMocks.ts index 223fcd3064..fbaf812186 100644 --- a/src/components/AddPeopleToTag/AddPeopleToTagsMocks.ts +++ b/src/components/AddPeopleToTag/AddPeopleToTagsMocks.ts @@ -9,6 +9,10 @@ export const MOCKS = [ variables: { id: '1', first: TAGS_QUERY_DATA_CHUNK_SIZE, + where: { + firstName: { starts_with: '' }, + lastName: { starts_with: '' }, + }, }, }, result: { @@ -117,6 +121,10 @@ export const MOCKS = [ id: '1', first: TAGS_QUERY_DATA_CHUNK_SIZE, after: '10', + where: { + firstName: { starts_with: '' }, + lastName: { starts_with: '' }, + }, }, }, result: { @@ -154,6 +162,100 @@ export const MOCKS = [ }, }, }, + { + request: { + query: USER_TAGS_MEMBERS_TO_ASSIGN_TO, + variables: { + id: '1', + first: TAGS_QUERY_DATA_CHUNK_SIZE, + where: { + firstName: { starts_with: 'usersToAssignTo' }, + lastName: { starts_with: '' }, + }, + }, + }, + result: { + data: { + getUsersToAssignTo: { + name: 'tag1', + usersToAssignTo: { + edges: [ + { + node: { + _id: '1', + firstName: 'usersToAssignTo', + lastName: 'user1', + }, + cursor: '1', + }, + { + node: { + _id: '2', + firstName: 'usersToAssignTo', + lastName: 'user2', + }, + cursor: '2', + }, + ], + pageInfo: { + startCursor: '1', + endCursor: '2', + hasNextPage: false, + hasPreviousPage: false, + }, + totalCount: 2, + }, + }, + }, + }, + }, + { + request: { + query: USER_TAGS_MEMBERS_TO_ASSIGN_TO, + variables: { + id: '1', + first: TAGS_QUERY_DATA_CHUNK_SIZE, + where: { + firstName: { starts_with: '' }, + lastName: { starts_with: 'userToAssignTo' }, + }, + }, + }, + result: { + data: { + getUsersToAssignTo: { + name: 'tag1', + usersToAssignTo: { + edges: [ + { + node: { + _id: '1', + firstName: 'first', + lastName: 'userToAssignTo', + }, + cursor: '1', + }, + { + node: { + _id: '2', + firstName: 'second', + lastName: 'userToAssignTo', + }, + cursor: '2', + }, + ], + pageInfo: { + startCursor: '1', + endCursor: '2', + hasNextPage: false, + hasPreviousPage: false, + }, + totalCount: 2, + }, + }, + }, + }, + }, { request: { query: ADD_PEOPLE_TO_TAG, @@ -179,6 +281,10 @@ export const MOCKS_ERROR = [ variables: { id: '1', first: TAGS_QUERY_DATA_CHUNK_SIZE, + where: { + firstName: { starts_with: '' }, + lastName: { starts_with: '' }, + }, }, }, error: new Error('Mock Graphql Error'), diff --git a/src/components/TagActions/TagActions.module.css b/src/components/TagActions/TagActions.module.css index 62c5855981..079dffea65 100644 --- a/src/components/TagActions/TagActions.module.css +++ b/src/components/TagActions/TagActions.module.css @@ -17,9 +17,8 @@ } .scrollContainer { - max-height: 100px; + height: 100px; overflow-y: auto; - margin-bottom: 1rem; } .tagBadge { @@ -34,3 +33,10 @@ .removeFilterIcon { cursor: pointer; } + +.loadingDiv { + min-height: 300px; + display: flex; + justify-content: center; + align-items: center; +} diff --git a/src/components/TagActions/TagActions.test.tsx b/src/components/TagActions/TagActions.test.tsx index 140504d044..d27f177ebe 100644 --- a/src/components/TagActions/TagActions.test.tsx +++ b/src/components/TagActions/TagActions.test.tsx @@ -199,6 +199,27 @@ describe('Organisation Tags Page', () => { }); }); + test('searchs for tags where the name matches the provided search input', async () => { + renderTagActionsModal(props[0], link); + + await wait(); + + await waitFor(() => { + expect( + screen.getByPlaceholderText(translations.searchByName), + ).toBeInTheDocument(); + }); + const input = screen.getByPlaceholderText(translations.searchByName); + fireEvent.change(input, { target: { value: 'searchUserTag' } }); + + // should render the two searched tags from the mock data + // where name starts with "searchUserTag" + await waitFor(() => { + const tags = screen.getAllByTestId('orgUserTag'); + expect(tags.length).toEqual(2); + }); + }); + test('Renders more members with infinite scroll', async () => { const { getByText } = renderTagActionsModal(props[0], link); @@ -317,6 +338,21 @@ describe('Organisation Tags Page', () => { userEvent.click(screen.getByTestId('expandSubTags1')); }); + test('Toasts error when no tag is selected while assigning', async () => { + renderTagActionsModal(props[0], link); + + await wait(); + + await waitFor(() => { + expect(screen.getByTestId('tagActionSubmitBtn')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('tagActionSubmitBtn')); + + await waitFor(() => { + expect(toast.error).toHaveBeenCalledWith(translations.noTagSelected); + }); + }); + test('Successfully assigns to tags', async () => { renderTagActionsModal(props[0], link); diff --git a/src/components/TagActions/TagActions.tsx b/src/components/TagActions/TagActions.tsx index 60099e855d..083341372f 100644 --- a/src/components/TagActions/TagActions.tsx +++ b/src/components/TagActions/TagActions.tsx @@ -1,6 +1,4 @@ import { useMutation, useQuery } from '@apollo/client'; -import Loader from 'components/Loader/Loader'; -import { USER_TAG_ANCESTORS } from 'GraphQl/Queries/userTagQueries'; import type { FormEvent } from 'react'; import React, { useEffect, useState } from 'react'; import { Modal, Form, Button } from 'react-bootstrap'; @@ -52,6 +50,8 @@ const TagActions: React.FC = ({ }) => { const { orgId, tagId: currentTagId } = useParams(); + const [tagSearchName, setTagSearchName] = useState(''); + const { data: orgUserTagsData, loading: orgUserTagsLoading, @@ -61,6 +61,7 @@ const TagActions: React.FC = ({ variables: { id: orgId, first: TAGS_QUERY_DATA_CHUNK_SIZE, + where: { name: { starts_with: tagSearchName } }, }, skip: !tagActionsModalIsOpen, }); @@ -81,7 +82,7 @@ const TagActions: React.FC = ({ }; }, ) => { - if (!fetchMoreResult) return prevResult; + if (!fetchMoreResult) /* istanbul ignore next */ return prevResult; return { organizations: [ @@ -107,9 +108,6 @@ const TagActions: React.FC = ({ (edge) => edge.node, ) ?? /* istanbul ignore next */ []; - const [checkedTagId, setCheckedTagId] = useState(null); - const [uncheckedTagId, setUncheckedTagId] = useState(null); - // tags that we have selected to assigned const [selectedTags, setSelectedTags] = useState([]); @@ -167,22 +165,13 @@ const TagActions: React.FC = ({ setAncestorTagsDataMap(newAncestorTagsDataMap); }, [removeAncestorTagsData]); - const addAncestorTags = (tagId: string): void => { - setCheckedTagId(tagId); - setUncheckedTagId(null); - }; - - const removeAncestorTags = (tagId: string): void => { - setUncheckedTagId(tagId); - setCheckedTagId(null); - }; - const selectTag = (tag: InterfaceTagData): void => { const newCheckedTags = new Set(checkedTags); setSelectedTags((selectedTags) => [...selectedTags, tag]); newCheckedTags.add(tag._id); - addAncestorTags(tag._id); + + setAddAncestorTagsData(new Set(tag.ancestorTags)); setCheckedTags(newCheckedTags); }; @@ -199,7 +188,8 @@ const TagActions: React.FC = ({ selectedTags.filter((selectedTag) => selectedTag._id !== tag._id), ); newCheckedTags.delete(tag._id); - removeAncestorTags(tag._id); + + setRemoveAncestorTagsData(new Set(tag.ancestorTags)); setCheckedTags(newCheckedTags); }; @@ -215,20 +205,6 @@ const TagActions: React.FC = ({ } }; - useQuery(USER_TAG_ANCESTORS, { - variables: { id: checkedTagId }, - onCompleted: /* istanbul ignore next */ (data) => { - setAddAncestorTagsData(data.getUserTagAncestors.slice(0, -1)); // Update the ancestor tags data, to check the ancestor tags - }, - }); - - useQuery(USER_TAG_ANCESTORS, { - variables: { id: uncheckedTagId }, - onCompleted: /* istanbul ignore next */ (data) => { - setRemoveAncestorTagsData(data.getUserTagAncestors.slice(0, -1)); // Update the ancestor tags data, to uncheck the ancestor tags - }, - }); - const [assignToTags] = useMutation(ASSIGN_TO_TAGS); const [removeFromTags] = useMutation(REMOVE_FROM_TAGS); @@ -237,6 +213,11 @@ const TagActions: React.FC = ({ ): Promise => { e.preventDefault(); + if (!selectedTags.length) { + toast.error(t('noTagSelected')); + return; + } + const mutationObject = { variables: { currentTagId, @@ -301,44 +282,58 @@ const TagActions: React.FC = ({ +
+ {selectedTags.length === 0 ? ( +
+ {t('noTagSelected')} +
+ ) : ( + selectedTags.map((tag: InterfaceTagData) => ( +
+ {tag.name} +
+ )) + )} +
+ +
+ + setTagSearchName(e.target.value.trim())} + data-testid="searchByName" + autoComplete="off" + /> +
+ +
+ {t('allTags')} +
{orgUserTagsLoading ? ( - +
+ +
) : ( <> -
- {selectedTags.length === 0 ? ( -
- {t('noTagSelected')} -
- ) : ( - selectedTags.map((tag: InterfaceTagData) => ( -
- {tag.name} -
- )) - )} -
- -
- {t('allTags')} -
-
@@ -353,17 +348,36 @@ const TagActions: React.FC = ({ scrollableTarget="scrollableDiv" > {userTagsList?.map((tag) => ( -
- +
+
+ +
+ + {/* Ancestor tags breadcrumbs positioned at the end of TagNode */} + {tag.parentTag && ( +
+ <>{'('} + {tag.ancestorTags?.map((ancestorTag) => ( + + {ancestorTag.name} + + + ))} + <>{')'} +
+ )}
))} diff --git a/src/components/TagActions/TagActionsMocks.ts b/src/components/TagActions/TagActionsMocks.ts index a6ed89ab8b..f22458fa53 100644 --- a/src/components/TagActions/TagActionsMocks.ts +++ b/src/components/TagActions/TagActionsMocks.ts @@ -13,6 +13,7 @@ export const MOCKS = [ variables: { id: '123', first: TAGS_QUERY_DATA_CHUNK_SIZE, + where: { name: { starts_with: '' } }, }, }, result: { @@ -25,12 +26,14 @@ export const MOCKS = [ node: { _id: '1', name: 'userTag 1', + parentTag: null, usersAssignedTo: { totalCount: 5, }, childTags: { totalCount: 11, }, + ancestorTags: [], }, cursor: '1', }, @@ -38,12 +41,14 @@ export const MOCKS = [ node: { _id: '2', name: 'userTag 2', + parentTag: null, usersAssignedTo: { totalCount: 5, }, childTags: { totalCount: 0, }, + ancestorTags: [], }, cursor: '2', }, @@ -51,12 +56,14 @@ export const MOCKS = [ node: { _id: '3', name: 'userTag 3', + parentTag: null, usersAssignedTo: { totalCount: 0, }, childTags: { totalCount: 5, }, + ancestorTags: [], }, cursor: '3', }, @@ -64,12 +71,14 @@ export const MOCKS = [ node: { _id: '4', name: 'userTag 4', + parentTag: null, usersAssignedTo: { totalCount: 0, }, childTags: { totalCount: 0, }, + ancestorTags: [], }, cursor: '4', }, @@ -77,12 +86,14 @@ export const MOCKS = [ node: { _id: '5', name: 'userTag 5', + parentTag: null, usersAssignedTo: { totalCount: 5, }, childTags: { totalCount: 5, }, + ancestorTags: [], }, cursor: '5', }, @@ -90,12 +101,14 @@ export const MOCKS = [ node: { _id: '6', name: 'userTag 6', + parentTag: null, usersAssignedTo: { totalCount: 6, }, childTags: { totalCount: 6, }, + ancestorTags: [], }, cursor: '6', }, @@ -103,12 +116,14 @@ export const MOCKS = [ node: { _id: '7', name: 'userTag 7', + parentTag: null, usersAssignedTo: { totalCount: 7, }, childTags: { totalCount: 7, }, + ancestorTags: [], }, cursor: '7', }, @@ -116,12 +131,14 @@ export const MOCKS = [ node: { _id: '8', name: 'userTag 8', + parentTag: null, usersAssignedTo: { totalCount: 8, }, childTags: { totalCount: 8, }, + ancestorTags: [], }, cursor: '8', }, @@ -129,12 +146,14 @@ export const MOCKS = [ node: { _id: '9', name: 'userTag 9', + parentTag: null, usersAssignedTo: { totalCount: 9, }, childTags: { totalCount: 9, }, + ancestorTags: [], }, cursor: '9', }, @@ -142,12 +161,14 @@ export const MOCKS = [ node: { _id: '10', name: 'userTag 10', + parentTag: null, usersAssignedTo: { totalCount: 10, }, childTags: { totalCount: 10, }, + ancestorTags: [], }, cursor: '10', }, @@ -172,6 +193,7 @@ export const MOCKS = [ id: '123', first: TAGS_QUERY_DATA_CHUNK_SIZE, after: '10', + where: { name: { starts_with: '' } }, }, }, result: { @@ -184,12 +206,14 @@ export const MOCKS = [ node: { _id: '11', name: 'userTag 11', + parentTag: null, usersAssignedTo: { totalCount: 5, }, childTags: { totalCount: 5, }, + ancestorTags: [], }, cursor: '11', }, @@ -197,12 +221,14 @@ export const MOCKS = [ node: { _id: '12', name: 'userTag 12', + parentTag: null, usersAssignedTo: { totalCount: 5, }, childTags: { totalCount: 0, }, + ancestorTags: [], }, cursor: '12', }, @@ -220,6 +246,79 @@ export const MOCKS = [ }, }, }, + { + request: { + query: ORGANIZATION_USER_TAGS_LIST, + variables: { + id: '123', + first: TAGS_QUERY_DATA_CHUNK_SIZE, + where: { name: { starts_with: 'searchUserTag' } }, + }, + }, + result: { + data: { + organizations: [ + { + userTags: { + edges: [ + { + node: { + _id: '1', + name: 'searchUserTag 1', + parentTag: { + _id: '1', + }, + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 5, + }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], + }, + cursor: '1', + }, + { + node: { + _id: '2', + name: 'searchUserTag 2', + parentTag: { + _id: '1', + }, + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 0, + }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], + }, + cursor: '2', + }, + ], + pageInfo: { + startCursor: '1', + endCursor: '2', + hasNextPage: false, + hasPreviousPage: false, + }, + totalCount: 2, + }, + }, + ], + }, + }, + }, { request: { query: USER_TAG_SUB_TAGS, @@ -244,6 +343,12 @@ export const MOCKS = [ childTags: { totalCount: 5, }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], }, cursor: 'subTag1', }, @@ -257,6 +362,12 @@ export const MOCKS = [ childTags: { totalCount: 0, }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], }, cursor: 'subTag2', }, @@ -270,6 +381,12 @@ export const MOCKS = [ childTags: { totalCount: 5, }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], }, cursor: 'subTag3', }, @@ -283,6 +400,12 @@ export const MOCKS = [ childTags: { totalCount: 0, }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], }, cursor: 'subTag4', }, @@ -296,6 +419,12 @@ export const MOCKS = [ childTags: { totalCount: 5, }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], }, cursor: 'subTag5', }, @@ -309,6 +438,12 @@ export const MOCKS = [ childTags: { totalCount: 5, }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], }, cursor: 'subTag6', }, @@ -322,6 +457,12 @@ export const MOCKS = [ childTags: { totalCount: 5, }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], }, cursor: 'subTag7', }, @@ -335,6 +476,12 @@ export const MOCKS = [ childTags: { totalCount: 5, }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], }, cursor: 'subTag8', }, @@ -348,6 +495,12 @@ export const MOCKS = [ childTags: { totalCount: 5, }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], }, cursor: 'subTag9', }, @@ -361,6 +514,12 @@ export const MOCKS = [ childTags: { totalCount: 5, }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], }, cursor: 'subTag10', }, @@ -373,6 +532,7 @@ export const MOCKS = [ }, totalCount: 11, }, + ancestorTags: [], }, }, }, @@ -402,6 +562,12 @@ export const MOCKS = [ childTags: { totalCount: 0, }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], }, cursor: 'subTag11', }, @@ -414,6 +580,7 @@ export const MOCKS = [ }, totalCount: 11, }, + ancestorTags: [], }, }, }, @@ -459,6 +626,7 @@ export const MOCKS_ERROR_ORGANIZATION_TAGS_QUERY = [ variables: { id: '123', first: TAGS_QUERY_DATA_CHUNK_SIZE, + where: { name: { starts_with: '' } }, }, }, error: new Error('Mock Graphql Error for organization root tags query'), @@ -472,6 +640,7 @@ export const MOCKS_ERROR_SUBTAGS_QUERY = [ variables: { id: '123', first: TAGS_QUERY_DATA_CHUNK_SIZE, + where: { name: { starts_with: '' } }, }, }, result: { @@ -484,12 +653,14 @@ export const MOCKS_ERROR_SUBTAGS_QUERY = [ node: { _id: '1', name: 'userTag 1', + parentTag: null, usersAssignedTo: { totalCount: 5, }, childTags: { totalCount: 11, }, + ancestorTags: [], }, cursor: '1', }, @@ -497,12 +668,14 @@ export const MOCKS_ERROR_SUBTAGS_QUERY = [ node: { _id: '2', name: 'userTag 2', + parentTag: null, usersAssignedTo: { totalCount: 5, }, childTags: { totalCount: 0, }, + ancestorTags: [], }, cursor: '2', }, diff --git a/src/components/TagActions/TagNode.tsx b/src/components/TagActions/TagNode.tsx index e05d572f30..4a085ecaf9 100644 --- a/src/components/TagActions/TagNode.tsx +++ b/src/components/TagActions/TagNode.tsx @@ -61,7 +61,7 @@ const TagNode: React.FC = ({ fetchMoreResult?: { getChildTags: InterfaceQueryUserTagChildTags }; }, ) => { - if (!fetchMoreResult) return prevResult; + if (!fetchMoreResult) /* istanbul ignore next */ return prevResult; return { getChildTags: { diff --git a/src/screens/ManageTag/ManageTag.test.tsx b/src/screens/ManageTag/ManageTag.test.tsx index c4c1375e0e..598a15cc9a 100644 --- a/src/screens/ManageTag/ManageTag.test.tsx +++ b/src/screens/ManageTag/ManageTag.test.tsx @@ -20,11 +20,7 @@ import { store } from 'state/store'; import { StaticMockLink } from 'utils/StaticMockLink'; import i18n from 'utils/i18nForTest'; import ManageTag from './ManageTag'; -import { - MOCKS, - MOCKS_ERROR_ASSIGNED_MEMBERS, - MOCKS_ERROR_TAG_ANCESTORS, -} from './ManageTagMocks'; +import { MOCKS, MOCKS_ERROR_ASSIGNED_MEMBERS } from './ManageTagMocks'; import { type ApolloLink } from '@apollo/client'; const translations = { @@ -37,7 +33,6 @@ const translations = { const link = new StaticMockLink(MOCKS, true); const link2 = new StaticMockLink(MOCKS_ERROR_ASSIGNED_MEMBERS, true); -const link3 = new StaticMockLink(MOCKS_ERROR_TAG_ANCESTORS, true); async function wait(ms = 500): Promise { await act(() => { @@ -129,16 +124,6 @@ describe('Manage Tag Page', () => { }); }); - test('renders error component on unsuccessful userTag ancestors query', async () => { - const { queryByText } = renderManageTag(link3); - - await wait(); - - await waitFor(() => { - expect(queryByText(translations.addPeopleToTag)).not.toBeInTheDocument(); - }); - }); - test('opens and closes the add people to tag modal', async () => { renderManageTag(link); @@ -339,6 +324,84 @@ describe('Manage Tag Page', () => { }); }); + test('searchs for tags where the name matches the provided search input', async () => { + renderManageTag(link); + + await wait(); + + await waitFor(() => { + expect( + screen.getByPlaceholderText(translations.searchByName), + ).toBeInTheDocument(); + }); + const input = screen.getByPlaceholderText(translations.searchByName); + fireEvent.change(input, { target: { value: 'assigned user' } }); + + // should render the two users from the mock data + // where firstName starts with "assigned" and lastName starts with "user" + await waitFor(() => { + const buttons = screen.getAllByTestId('viewProfileBtn'); + expect(buttons.length).toEqual(2); + }); + }); + + test('fetches the tags by the sort order, i.e. latest or oldest first', async () => { + renderManageTag(link); + + await wait(); + + await waitFor(() => { + expect( + screen.getByPlaceholderText(translations.searchByName), + ).toBeInTheDocument(); + }); + const input = screen.getByPlaceholderText(translations.searchByName); + fireEvent.change(input, { target: { value: 'assigned user' } }); + + // should render the two searched tags from the mock data + // where name starts with "searchUserTag" + await waitFor(() => { + expect(screen.getAllByTestId('memberName')[0]).toHaveTextContent( + 'assigned user1', + ); + }); + + // now change the sorting order + await waitFor(() => { + expect(screen.getByTestId('sortPeople')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('sortPeople')); + + await waitFor(() => { + expect(screen.getByTestId('oldest')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('oldest')); + + // returns the tags in reverse order + await waitFor(() => { + expect(screen.getAllByTestId('memberName')[0]).toHaveTextContent( + 'assigned user2', + ); + }); + + await waitFor(() => { + expect(screen.getByTestId('sortPeople')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('sortPeople')); + + await waitFor(() => { + expect(screen.getByTestId('latest')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('latest')); + + // reverse the order again + await waitFor(() => { + expect(screen.getAllByTestId('memberName')[0]).toHaveTextContent( + 'assigned user1', + ); + }); + }); + test('Fetches more assigned members with infinite scroll', async () => { const { getByText } = renderManageTag(link); diff --git a/src/screens/ManageTag/ManageTag.tsx b/src/screens/ManageTag/ManageTag.tsx index f04965ba4d..e8eb9bb8df 100644 --- a/src/screens/ManageTag/ManageTag.tsx +++ b/src/screens/ManageTag/ManageTag.tsx @@ -1,7 +1,7 @@ import type { FormEvent } from 'react'; import React, { useEffect, useState } from 'react'; -import { useMutation, useQuery, type ApolloError } from '@apollo/client'; -import { Search, WarningAmberRounded } from '@mui/icons-material'; +import { useMutation, useQuery } from '@apollo/client'; +import { WarningAmberRounded } from '@mui/icons-material'; import SortIcon from '@mui/icons-material/Sort'; import Loader from 'components/Loader/Loader'; import IconComponent from 'components/IconComponent/IconComponent'; @@ -17,6 +17,7 @@ import styles from './ManageTag.module.css'; import { DataGrid } from '@mui/x-data-grid'; import type { InterfaceTagAssignedMembersQuery, + SortedByType, TagActionType, } from 'utils/organizationTagsUtils'; import { @@ -30,10 +31,7 @@ import { UNASSIGN_USER_TAG, UPDATE_USER_TAG, } from 'GraphQl/Mutations/TagMutations'; -import { - USER_TAG_ANCESTORS, - USER_TAGS_ASSIGNED_MEMBERS, -} from 'GraphQl/Queries/userTagQueries'; +import { USER_TAGS_ASSIGNED_MEMBERS } from 'GraphQl/Queries/userTagQueries'; import AddPeopleToTag from 'components/AddPeopleToTag/AddPeopleToTag'; import TagActions from 'components/TagActions/TagActions'; import InfiniteScroll from 'react-infinite-scroll-component'; @@ -43,10 +41,7 @@ import RemoveUserTagModal from './RemoveUserTagModal'; import UnassignUserTagModal from './UnassignUserTagModal'; /** - * Component that renders the Manage Tag screen when the app navigates to '/orgtags/:orgId/managetag/:tagId'. - * - * This component does not accept any props and is responsible for displaying - * the content associated with the corresponding route. + * Component that renders the Manage Tag screen when the app navigates to '/orgtags/:orgId/manageTag/:tagId'. */ function ManageTag(): JSX.Element { @@ -54,6 +49,8 @@ function ManageTag(): JSX.Element { keyPrefix: 'manageTag', }); const { t: tCommon } = useTranslation('common'); + const { orgId, tagId: currentTagId } = useParams(); + const navigate = useNavigate(); const [unassignUserTagModalIsOpen, setUnassignUserTagModalIsOpen] = useState(false); @@ -63,11 +60,15 @@ function ManageTag(): JSX.Element { const [editUserTagModalIsOpen, setEditUserTagModalIsOpen] = useState(false); const [removeUserTagModalIsOpen, setRemoveUserTagModalIsOpen] = useState(false); - - const { orgId, tagId: currentTagId } = useParams(); - const navigate = useNavigate(); const [unassignUserId, setUnassignUserId] = useState(null); - + const [assignedMemberSearchInput, setAssignedMemberSearchInput] = + useState(''); + const [assignedMemberSearchFirstName, setAssignedMemberSearchFirstName] = + useState(''); + const [assignedMemberSearchLastName, setAssignedMemberSearchLastName] = + useState(''); + const [assignedMemberSortOrder, setAssignedMemberSortOrder] = + useState('DESCENDING'); // a state to specify whether we're assigning to tags or removing from tags const [tagActionType, setTagActionType] = useState('assignToTags'); @@ -75,21 +76,18 @@ function ManageTag(): JSX.Element { const toggleRemoveUserTagModal = (): void => { setRemoveUserTagModalIsOpen(!removeUserTagModalIsOpen); }; - const showAddPeopleToTagModal = (): void => { setAddPeopleToTagModalIsOpen(true); }; const hideAddPeopleToTagModal = (): void => { setAddPeopleToTagModalIsOpen(false); }; - const showTagActionsModal = (): void => { setTagActionsModalIsOpen(true); }; const hideTagActionsModal = (): void => { setTagActionsModalIsOpen(false); }; - const showEditUserTagModal = (): void => { setEditUserTagModalIsOpen(true); }; @@ -107,7 +105,13 @@ function ManageTag(): JSX.Element { variables: { id: currentTagId, first: TAGS_QUERY_DATA_CHUNK_SIZE, + where: { + firstName: { starts_with: assignedMemberSearchFirstName }, + lastName: { starts_with: assignedMemberSearchLastName }, + }, + sortedBy: { id: assignedMemberSortOrder }, }, + fetchPolicy: 'no-cache', }); const loadMoreAssignedMembers = (): void => { @@ -128,7 +132,7 @@ function ManageTag(): JSX.Element { }; }, ) => { - if (!fetchMoreResult) return prevResult; + if (!fetchMoreResult) /* istanbul ignore next */ return prevResult; return { getAssignedUsers: { @@ -146,26 +150,14 @@ function ManageTag(): JSX.Element { }); }; - const { - data: orgUserTagAncestorsData, - loading: orgUserTagsAncestorsLoading, - refetch: orgUserTagsAncestorsRefetch, - error: orgUserTagsAncestorsError, - }: { - data?: { - getUserTagAncestors: { - _id: string; - name: string; - }[]; - }; - loading: boolean; - error?: ApolloError; - refetch: () => void; - } = useQuery(USER_TAG_ANCESTORS, { - variables: { - id: currentTagId, - }, - }); + useEffect(() => { + const [firstName, ...lastNameParts] = assignedMemberSearchInput + .trim() + .split(/\s+/); + const lastName = lastNameParts.join(' '); // Joins everything after the first word + setAssignedMemberSearchFirstName(firstName); + setAssignedMemberSearchLastName(lastName); + }, [assignedMemberSearchInput]); const [unassignUserTag] = useMutation(UNASSIGN_USER_TAG); @@ -220,7 +212,6 @@ function ManageTag(): JSX.Element { if (data) { toast.success(t('tagUpdationSuccess')); userTagAssignedMembersRefetch(); - orgUserTagsAncestorsRefetch(); setEditUserTagModalIsOpen(false); } } catch (error: unknown) { @@ -251,22 +242,13 @@ function ManageTag(): JSX.Element { } }; - if (userTagAssignedMembersLoading || orgUserTagsAncestorsLoading) { - return ; - } - - if (userTagAssignedMembersError || orgUserTagsAncestorsError) { + if (userTagAssignedMembersError) { return (
- Error occured while loading{' '} - {userTagAssignedMembersError ? 'assigned users' : 'tag ancestors'} -
- {userTagAssignedMembersError - ? userTagAssignedMembersError.message - : orgUserTagsAncestorsError?.message} + Error occured while loading assigned users
@@ -277,7 +259,16 @@ function ManageTag(): JSX.Element { userTagAssignedMembersData?.getAssignedUsers.usersAssignedTo.edges.map( (edge) => edge.node, ) ?? /* istanbul ignore next */ []; - const orgUserTagAncestors = orgUserTagAncestorsData?.getUserTagAncestors; + + // get the ancestorTags array and push the current tag in it + // used for the tag breadcrumbs + const orgUserTagAncestors = [ + ...(userTagAssignedMembersData?.getAssignedUsers.ancestorTags ?? []), + { + _id: currentTagId, + name: currentTagName, + }, + ]; const redirectToSubTags = (tagId: string): void => { navigate(`/orgtags/${orgId}/subTags/${tagId}`); @@ -285,7 +276,6 @@ function ManageTag(): JSX.Element { const redirectToManageTag = (tagId: string): void => { navigate(`/orgtags/${orgId}/manageTag/${tagId}`); }; - const toggleUnassignUserTagModal = (): void => { if (unassignUserTagModalIsOpen) { setUnassignUserId(null); @@ -366,21 +356,18 @@ function ManageTag(): JSX.Element {
+ + setAssignedMemberSearchInput(e.target.value.trim()) + } data-testid="searchByName" autoComplete="off" - required /> -
- {tCommon('sort')} + {assignedMemberSortOrder === 'DESCENDING' + ? tCommon('Latest') + : tCommon('Oldest')} - + setAssignedMemberSortOrder('DESCENDING')} + > {tCommon('Latest')} - + setAssignedMemberSortOrder('ASCENDING')} + > {tCommon('Oldest')} @@ -423,131 +418,137 @@ function ManageTag(): JSX.Element { {t('addPeopleToTag')}
- - -
-
- + + {userTagAssignedMembersLoading ? ( + + ) : ( + + +
+
+ +
+
navigate(`/orgtags/${orgId}`)} + className={`fs-6 ms-3 my-1 ${styles.tagsBreadCrumbs}`} + data-testid="allTagsBtn" + > + {'Tags'} + +
+ {orgUserTagAncestors?.map((tag, index) => ( +
redirectToManageTag(tag._id as string)} + data-testid="redirectToManageTag" + > + {tag.name} + {orgUserTagAncestors.length - 1 !== index && ( + /* istanbul ignore next */ + + )} +
+ ))}
navigate(`/orgtags/${orgId}`)} - className={`fs-6 ms-3 my-1 ${styles.tagsBreadCrumbs}`} - data-testid="allTagsBtn" + id="manageTagScrollableDiv" + data-testid="manageTagScrollableDiv" + className={styles.manageTagScrollableDiv} > - {'Tags'} - + } + scrollableTarget="manageTagScrollableDiv" + > + row.id} + slots={{ + noRowsOverlay: /* istanbul ignore next */ () => ( + + {t('noAssignedMembersFound')} + + ), + }} + sx={dataGridStyle} + getRowClassName={() => `${styles.rowBackground}`} + autoHeight + rowHeight={65} + rows={userTagAssignedMembers?.map( + (assignedMembers, index) => ({ + id: index + 1, + ...assignedMembers, + }), + )} + columns={columns} + isRowSelectable={() => false} + /> + +
+ + +
+
{'Actions'}
- {orgUserTagAncestors?.map((tag, index) => ( +
redirectToManageTag(tag._id as string)} - data-testid="redirectToManageTag" + onClick={() => { + setTagActionType('assignToTags'); + showTagActionsModal(); + }} + className="my-2 btn btn-primary btn-sm w-75" + data-testid="assignToTags" > - {tag.name} - {orgUserTagAncestors.length - 1 !== index && ( - /* istanbul ignore next */ - - )} + {t('assignToTags')}
- ))} -
-
- } - scrollableTarget="manageTagScrollableDiv" - > - row.id} - slots={{ - noRowsOverlay: /* istanbul ignore next */ () => ( - - {t('noAssignedMembersFound')} - - ), +
{ + setTagActionType('removeFromTags'); + showTagActionsModal(); + }} + className="mb-1 btn btn-danger btn-sm w-75" + data-testid="removeFromTags" + > + {t('removeFromTags')} +
+
`${styles.rowBackground}`} - autoHeight - rowHeight={65} - rows={userTagAssignedMembers?.map( - (assignedMembers, index) => ({ - id: index + 1, - ...assignedMembers, - }), - )} - columns={columns} - isRowSelectable={() => false} /> -
-
- - -
-
{'Actions'}
-
-
-
{ - setTagActionType('assignToTags'); - showTagActionsModal(); - }} - className="my-2 btn btn-primary btn-sm w-75" - data-testid="assignToTags" - > - {t('assignToTags')} -
-
{ - setTagActionType('removeFromTags'); - showTagActionsModal(); - }} - className="mb-1 btn btn-danger btn-sm w-75" - data-testid="removeFromTags" - > - {t('removeFromTags')} -
-
-
- {tCommon('edit')} -
-
- {tCommon('remove')} +
+ {tCommon('edit')} +
+
+ {tCommon('remove')} +
-
- -
+ + + )}
diff --git a/src/screens/ManageTag/ManageTagMocks.ts b/src/screens/ManageTag/ManageTagMocks.ts index 4e9c64badd..5ce1e62595 100644 --- a/src/screens/ManageTag/ManageTagMocks.ts +++ b/src/screens/ManageTag/ManageTagMocks.ts @@ -3,10 +3,7 @@ import { UNASSIGN_USER_TAG, UPDATE_USER_TAG, } from 'GraphQl/Mutations/TagMutations'; -import { - USER_TAG_ANCESTORS, - USER_TAGS_ASSIGNED_MEMBERS, -} from 'GraphQl/Queries/userTagQueries'; +import { USER_TAGS_ASSIGNED_MEMBERS } from 'GraphQl/Queries/userTagQueries'; import { TAGS_QUERY_DATA_CHUNK_SIZE } from 'utils/organizationTagsUtils'; export const MOCKS = [ @@ -16,6 +13,11 @@ export const MOCKS = [ variables: { id: '1', first: TAGS_QUERY_DATA_CHUNK_SIZE, + where: { + firstName: { starts_with: '' }, + lastName: { starts_with: '' }, + }, + sortedBy: { id: 'DESCENDING' }, }, }, result: { @@ -113,6 +115,7 @@ export const MOCKS = [ }, totalCount: 12, }, + ancestorTags: [], }, }, }, @@ -124,6 +127,11 @@ export const MOCKS = [ id: '1', first: TAGS_QUERY_DATA_CHUNK_SIZE, after: '10', + where: { + firstName: { starts_with: '' }, + lastName: { starts_with: '' }, + }, + sortedBy: { id: 'DESCENDING' }, }, }, result: { @@ -157,25 +165,106 @@ export const MOCKS = [ }, totalCount: 12, }, + ancestorTags: [], }, }, }, }, { request: { - query: USER_TAG_ANCESTORS, + query: USER_TAGS_ASSIGNED_MEMBERS, variables: { id: '1', + first: TAGS_QUERY_DATA_CHUNK_SIZE, + where: { + firstName: { starts_with: 'assigned' }, + lastName: { starts_with: 'user' }, + }, + sortedBy: { id: 'DESCENDING' }, }, }, result: { data: { - getUserTagAncestors: [ - { - _id: '1', - name: 'tag1', + getAssignedUsers: { + name: 'tag1', + usersAssignedTo: { + edges: [ + { + node: { + _id: '1', + firstName: 'assigned', + lastName: 'user1', + }, + cursor: '1', + }, + { + node: { + _id: '2', + firstName: 'assigned', + lastName: 'user2', + }, + cursor: '2', + }, + ], + pageInfo: { + startCursor: '1', + endCursor: '2', + hasNextPage: false, + hasPreviousPage: false, + }, + totalCount: 2, }, - ], + ancestorTags: [], + }, + }, + }, + }, + { + request: { + query: USER_TAGS_ASSIGNED_MEMBERS, + variables: { + id: '1', + first: TAGS_QUERY_DATA_CHUNK_SIZE, + where: { + firstName: { starts_with: 'assigned' }, + lastName: { starts_with: 'user' }, + }, + sortedBy: { id: 'ASCENDING' }, + }, + }, + result: { + data: { + getAssignedUsers: { + name: 'tag1', + usersAssignedTo: { + edges: [ + { + node: { + _id: '2', + firstName: 'assigned', + lastName: 'user2', + }, + cursor: '2', + }, + { + node: { + _id: '1', + firstName: 'assigned', + lastName: 'user1', + }, + cursor: '1', + }, + ], + pageInfo: { + startCursor: '2', + endCursor: '1', + hasNextPage: false, + hasPreviousPage: false, + }, + totalCount: 2, + }, + ancestorTags: [], + }, }, }, }, @@ -235,57 +324,11 @@ export const MOCKS_ERROR_ASSIGNED_MEMBERS = [ variables: { id: '1', first: TAGS_QUERY_DATA_CHUNK_SIZE, - }, - }, - error: new Error('Mock Graphql Error'), - }, - { - request: { - query: USER_TAG_ANCESTORS, - variables: { - id: '1', - }, - }, - result: { - data: { - getUserTagAncestors: [], - }, - }, - }, -]; - -export const MOCKS_ERROR_TAG_ANCESTORS = [ - { - request: { - query: USER_TAGS_ASSIGNED_MEMBERS, - variables: { - id: '1', - first: TAGS_QUERY_DATA_CHUNK_SIZE, - }, - }, - result: { - data: { - getAssignedUsers: { - name: 'tag1', - usersAssignedTo: { - edges: [], - pageInfo: { - startCursor: '1', - endCursor: '1', - hasNextPage: false, - hasPreviousPage: false, - }, - totalCount: 1, - }, + where: { + firstName: { starts_with: '' }, + lastName: { starts_with: '' }, }, - }, - }, - }, - { - request: { - query: USER_TAG_ANCESTORS, - variables: { - id: '1', + sortedBy: { id: 'DESCENDING' }, }, }, error: new Error('Mock Graphql Error'), diff --git a/src/screens/OrganizationTags/OrganizationTags.test.tsx b/src/screens/OrganizationTags/OrganizationTags.test.tsx index 1ab94ce35c..0d426d20ac 100644 --- a/src/screens/OrganizationTags/OrganizationTags.test.tsx +++ b/src/screens/OrganizationTags/OrganizationTags.test.tsx @@ -88,7 +88,7 @@ describe('Organisation Tags Page', () => { cleanup(); }); - test('Component loads correctly', async () => { + test('component loads correctly', async () => { const { getByText } = renderOrganizationTags(link); await wait(); @@ -160,7 +160,85 @@ describe('Organisation Tags Page', () => { }); }); - test('Fetches more tags with infinite scroll', async () => { + test('searchs for tags where the name matches the provided search input', async () => { + renderOrganizationTags(link); + + await wait(); + + await waitFor(() => { + expect( + screen.getByPlaceholderText(translations.searchByName), + ).toBeInTheDocument(); + }); + const input = screen.getByPlaceholderText(translations.searchByName); + fireEvent.change(input, { target: { value: 'searchUserTag' } }); + + // should render the two searched tags from the mock data + // where name starts with "searchUserTag" + await waitFor(() => { + const buttons = screen.getAllByTestId('manageTagBtn'); + expect(buttons.length).toEqual(2); + }); + }); + + test('fetches the tags by the sort order, i.e. latest or oldest first', async () => { + renderOrganizationTags(link); + + await wait(); + + await waitFor(() => { + expect( + screen.getByPlaceholderText(translations.searchByName), + ).toBeInTheDocument(); + }); + const input = screen.getByPlaceholderText(translations.searchByName); + fireEvent.change(input, { target: { value: 'searchUserTag' } }); + + // should render the two searched tags from the mock data + // where name starts with "searchUserTag" + await waitFor(() => { + expect(screen.getAllByTestId('tagName')[0]).toHaveTextContent( + 'searchUserTag 1', + ); + }); + + // now change the sorting order + await waitFor(() => { + expect(screen.getByTestId('sortTags')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('sortTags')); + + await waitFor(() => { + expect(screen.getByTestId('oldest')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('oldest')); + + // returns the tags in reverse order + await waitFor(() => { + expect(screen.getAllByTestId('tagName')[0]).toHaveTextContent( + 'searchUserTag 2', + ); + }); + + await waitFor(() => { + expect(screen.getByTestId('sortTags')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('sortTags')); + + await waitFor(() => { + expect(screen.getByTestId('latest')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('latest')); + + // reverse the order again + await waitFor(() => { + expect(screen.getAllByTestId('tagName')[0]).toHaveTextContent( + 'searchUserTag 1', + ); + }); + }); + + test('fetches more tags with infinite scroll', async () => { const { getByText } = renderOrganizationTags(link); await wait(); @@ -199,6 +277,12 @@ describe('Organisation Tags Page', () => { }); userEvent.click(screen.getByTestId('createTagBtn')); + userEvent.click(screen.getByTestId('createTagSubmitBtn')); + + await waitFor(() => { + expect(toast.error).toHaveBeenCalledWith(translations.enterTagName); + }); + userEvent.type( screen.getByPlaceholderText(translations.tagNamePlaceholder), 'userTag 12', diff --git a/src/screens/OrganizationTags/OrganizationTags.tsx b/src/screens/OrganizationTags/OrganizationTags.tsx index ce37528cc1..b59da67fd0 100644 --- a/src/screens/OrganizationTags/OrganizationTags.tsx +++ b/src/screens/OrganizationTags/OrganizationTags.tsx @@ -1,11 +1,11 @@ import { useMutation, useQuery } from '@apollo/client'; -import { Search, WarningAmberRounded } from '@mui/icons-material'; +import { WarningAmberRounded } from '@mui/icons-material'; import SortIcon from '@mui/icons-material/Sort'; import Loader from 'components/Loader/Loader'; import IconComponent from 'components/IconComponent/IconComponent'; import { useNavigate, useParams, Link } from 'react-router-dom'; import type { ChangeEvent } from 'react'; -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { Form } from 'react-bootstrap'; import Button from 'react-bootstrap/Button'; import Dropdown from 'react-bootstrap/Dropdown'; @@ -13,10 +13,16 @@ import Modal from 'react-bootstrap/Modal'; import Row from 'react-bootstrap/Row'; import { useTranslation } from 'react-i18next'; import { toast } from 'react-toastify'; -import type { InterfaceQueryOrganizationUserTags } from 'utils/interfaces'; +import type { + InterfaceQueryOrganizationUserTags, + InterfaceTagData, +} from 'utils/interfaces'; import styles from './OrganizationTags.module.css'; import { DataGrid } from '@mui/x-data-grid'; -import type { InterfaceOrganizationTagsQuery } from 'utils/organizationTagsUtils'; +import type { + InterfaceOrganizationTagsQuery, + SortedByType, +} from 'utils/organizationTagsUtils'; import { dataGridStyle, TAGS_QUERY_DATA_CHUNK_SIZE, @@ -43,6 +49,9 @@ function OrganizationTags(): JSX.Element { const [createTagModalIsOpen, setCreateTagModalIsOpen] = useState(false); + const [tagSearchName, setTagSearchName] = useState(''); + const [tagSortOrder, setTagSortOrder] = useState('DESCENDING'); + const { orgId } = useParams(); const navigate = useNavigate(); @@ -67,6 +76,8 @@ function OrganizationTags(): JSX.Element { variables: { id: orgId, first: TAGS_QUERY_DATA_CHUNK_SIZE, + where: { name: { starts_with: tagSearchName } }, + sortedBy: { id: tagSortOrder }, }, }); @@ -76,6 +87,7 @@ function OrganizationTags(): JSX.Element { first: TAGS_QUERY_DATA_CHUNK_SIZE, after: orgUserTagsData?.organizations?.[0]?.userTags?.pageInfo?.endCursor ?? + /* istanbul ignore next */ null, }, updateQuery: ( @@ -88,7 +100,7 @@ function OrganizationTags(): JSX.Element { }; }, ) => { - if (!fetchMoreResult) return prevResult; + if (!fetchMoreResult) /* istanbul ignore next */ return prevResult; return { organizations: [ @@ -109,12 +121,21 @@ function OrganizationTags(): JSX.Element { }); }; + useEffect(() => { + orgUserTagsRefetch(); + }, []); + const [create, { loading: createUserTagLoading }] = useMutation(CREATE_USER_TAG); const createTag = async (e: ChangeEvent): Promise => { e.preventDefault(); + if (!tagName.trim()) { + toast.error(t('enterTagName')); + return; + } + try { const { data } = await create({ variables: { @@ -124,7 +145,7 @@ function OrganizationTags(): JSX.Element { }); if (data) { - toast.success(t('tagCreationSuccess') as string); + toast.success(t('tagCreationSuccess')); orgUserTagsRefetch(); setTagName(''); setCreateTagModalIsOpen(false); @@ -137,10 +158,6 @@ function OrganizationTags(): JSX.Element { } }; - if (createUserTagLoading || orgUserTagsLoading) { - return ; - } - if (orgUserTagsError) { return (
@@ -188,16 +205,29 @@ function OrganizationTags(): JSX.Element { minWidth: 100, sortable: false, headerClassName: `${styles.tableHeader}`, - renderCell: (params: GridCellParams) => { + renderCell: (params: GridCellParams) => { return ( -
redirectToSubTags(params.row._id)} - > - {params.row.name} +
+ {params.row.parentTag && + params.row.ancestorTags?.map((tag) => ( +
+ {tag.name} + +
+ ))} - +
redirectToSubTags(params.row._id)} + > + {params.row.name} + +
); }, @@ -272,21 +302,16 @@ function OrganizationTags(): JSX.Element {
+ setTagSearchName(e.target.value.trim())} autoComplete="off" - required /> -
- {tCommon('sort')} + {tagSortOrder === 'DESCENDING' + ? tCommon('Latest') + : tCommon('Oldest')} - + setTagSortOrder('DESCENDING')} + > {tCommon('Latest')} - + setTagSortOrder('ASCENDING')} + > {tCommon('Oldest')} @@ -322,61 +355,66 @@ function OrganizationTags(): JSX.Element {
-
-
-
- -
+ {orgUserTagsLoading || createUserTagLoading ? ( + + ) : ( +
+
+
+ +
-
- {'Tags'} +
+ {'Tags'} +
-
-
- } - scrollableTarget="orgUserTagsScrollableDiv" + +
- row.id} - slots={{ - noRowsOverlay: /* istanbul ignore next */ () => ( - - {t('noTagsFound')} - - ), - }} - sx={dataGridStyle} - getRowClassName={() => `${styles.rowBackground}`} - autoHeight - rowHeight={65} - rows={userTagsList?.map((userTag, index) => ({ - id: index + 1, - ...userTag, - }))} - columns={columns} - isRowSelectable={() => false} - /> - + } + scrollableTarget="orgUserTagsScrollableDiv" + > + row.id} + slots={{ + noRowsOverlay: /* istanbul ignore next */ () => ( + + {t('noTagsFound')} + + ), + }} + sx={dataGridStyle} + getRowClassName={() => `${styles.rowBackground}`} + autoHeight + rowHeight={65} + rows={userTagsList?.map((userTag, index) => ({ + id: index + 1, + ...userTag, + }))} + columns={columns} + isRowSelectable={() => false} + /> + +
-
+ )}
diff --git a/src/screens/OrganizationTags/OrganizationTagsMocks.ts b/src/screens/OrganizationTags/OrganizationTagsMocks.ts index a8e186b393..0fe48ca97f 100644 --- a/src/screens/OrganizationTags/OrganizationTagsMocks.ts +++ b/src/screens/OrganizationTags/OrganizationTagsMocks.ts @@ -9,6 +9,8 @@ export const MOCKS = [ variables: { id: '123', first: TAGS_QUERY_DATA_CHUNK_SIZE, + where: { name: { starts_with: '' } }, + sortedBy: { id: 'DESCENDING' }, }, }, result: { @@ -21,12 +23,14 @@ export const MOCKS = [ node: { _id: '1', name: 'userTag 1', + parentTag: null, usersAssignedTo: { totalCount: 5, }, childTags: { totalCount: 11, }, + ancestorTags: [], }, cursor: '1', }, @@ -34,12 +38,14 @@ export const MOCKS = [ node: { _id: '2', name: 'userTag 2', + parentTag: null, usersAssignedTo: { totalCount: 5, }, childTags: { totalCount: 0, }, + ancestorTags: [], }, cursor: '2', }, @@ -47,12 +53,14 @@ export const MOCKS = [ node: { _id: '3', name: 'userTag 3', + parentTag: null, usersAssignedTo: { totalCount: 0, }, childTags: { totalCount: 5, }, + ancestorTags: [], }, cursor: '3', }, @@ -60,12 +68,14 @@ export const MOCKS = [ node: { _id: '4', name: 'userTag 4', + parentTag: null, usersAssignedTo: { totalCount: 0, }, childTags: { totalCount: 0, }, + ancestorTags: [], }, cursor: '4', }, @@ -73,12 +83,14 @@ export const MOCKS = [ node: { _id: '5', name: 'userTag 5', + parentTag: null, usersAssignedTo: { totalCount: 5, }, childTags: { totalCount: 5, }, + ancestorTags: [], }, cursor: '5', }, @@ -86,12 +98,14 @@ export const MOCKS = [ node: { _id: '6', name: 'userTag 6', + parentTag: null, usersAssignedTo: { totalCount: 6, }, childTags: { totalCount: 6, }, + ancestorTags: [], }, cursor: '6', }, @@ -99,12 +113,14 @@ export const MOCKS = [ node: { _id: '7', name: 'userTag 7', + parentTag: null, usersAssignedTo: { totalCount: 7, }, childTags: { totalCount: 7, }, + ancestorTags: [], }, cursor: '7', }, @@ -112,12 +128,14 @@ export const MOCKS = [ node: { _id: '8', name: 'userTag 8', + parentTag: null, usersAssignedTo: { totalCount: 8, }, childTags: { totalCount: 8, }, + ancestorTags: [], }, cursor: '8', }, @@ -125,12 +143,14 @@ export const MOCKS = [ node: { _id: '9', name: 'userTag 9', + parentTag: null, usersAssignedTo: { totalCount: 9, }, childTags: { totalCount: 9, }, + ancestorTags: [], }, cursor: '9', }, @@ -138,12 +158,14 @@ export const MOCKS = [ node: { _id: '10', name: 'userTag 10', + parentTag: null, usersAssignedTo: { totalCount: 10, }, childTags: { totalCount: 10, }, + ancestorTags: [], }, cursor: '10', }, @@ -168,6 +190,8 @@ export const MOCKS = [ id: '123', first: TAGS_QUERY_DATA_CHUNK_SIZE, after: '10', + where: { name: { starts_with: '' } }, + sortedBy: { id: 'DESCENDING' }, }, }, result: { @@ -180,12 +204,14 @@ export const MOCKS = [ node: { _id: '11', name: 'userTag 11', + parentTag: null, usersAssignedTo: { totalCount: 5, }, childTags: { totalCount: 5, }, + ancestorTags: [], }, cursor: '11', }, @@ -193,12 +219,14 @@ export const MOCKS = [ node: { _id: '12', name: 'userTag 12', + parentTag: null, usersAssignedTo: { totalCount: 5, }, childTags: { totalCount: 0, }, + ancestorTags: [], }, cursor: '12', }, @@ -216,6 +244,154 @@ export const MOCKS = [ }, }, }, + { + request: { + query: ORGANIZATION_USER_TAGS_LIST, + variables: { + id: '123', + first: TAGS_QUERY_DATA_CHUNK_SIZE, + where: { name: { starts_with: 'searchUserTag' } }, + sortedBy: { id: 'DESCENDING' }, + }, + }, + result: { + data: { + organizations: [ + { + userTags: { + edges: [ + { + node: { + _id: 'searchUserTag1', + name: 'searchUserTag 1', + parentTag: { + _id: '1', + }, + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 5, + }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], + }, + cursor: 'searchUserTag1', + }, + { + node: { + _id: 'searchUserTag2', + name: 'searchUserTag 2', + parentTag: { + _id: '1', + }, + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 0, + }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], + }, + cursor: 'searchUserTag2', + }, + ], + pageInfo: { + startCursor: 'searchUserTag1', + endCursor: 'searchUserTag2', + hasNextPage: false, + hasPreviousPage: false, + }, + totalCount: 2, + }, + }, + ], + }, + }, + }, + { + request: { + query: ORGANIZATION_USER_TAGS_LIST, + variables: { + id: '123', + first: TAGS_QUERY_DATA_CHUNK_SIZE, + where: { name: { starts_with: 'searchUserTag' } }, + sortedBy: { id: 'ASCENDING' }, + }, + }, + result: { + data: { + organizations: [ + { + userTags: { + edges: [ + { + node: { + _id: 'searchUserTag2', + name: 'searchUserTag 2', + parentTag: { + _id: '1', + }, + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 5, + }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], + }, + cursor: 'searchUserTag2', + }, + { + node: { + _id: 'searchUserTag1', + name: 'searchUserTag 1', + parentTag: { + _id: '1', + }, + usersAssignedTo: { + totalCount: 5, + }, + childTags: { + totalCount: 0, + }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], + }, + cursor: 'searchUserTag1', + }, + ], + pageInfo: { + startCursor: 'searchUserTag2', + endCursor: 'searchUserTag1', + hasNextPage: false, + hasPreviousPage: false, + }, + totalCount: 2, + }, + }, + ], + }, + }, + }, { request: { query: CREATE_USER_TAG, @@ -241,6 +417,8 @@ export const MOCKS_ERROR = [ variables: { id: '123', first: TAGS_QUERY_DATA_CHUNK_SIZE, + where: { name: { starts_with: '' } }, + sortedBy: { id: 'DESCENDING' }, }, }, error: new Error('Mock Graphql Error'), diff --git a/src/screens/SubTags/SubTags.test.tsx b/src/screens/SubTags/SubTags.test.tsx index 9cd778b858..145d31109d 100644 --- a/src/screens/SubTags/SubTags.test.tsx +++ b/src/screens/SubTags/SubTags.test.tsx @@ -20,12 +20,8 @@ import { store } from 'state/store'; import { StaticMockLink } from 'utils/StaticMockLink'; import i18n from 'utils/i18nForTest'; import SubTags from './SubTags'; -import { - MOCKS, - MOCKS_ERROR_SUB_TAGS, - MOCKS_ERROR_TAG_ANCESTORS, -} from './SubTagsMocks'; -import { type ApolloLink } from '@apollo/client'; +import { MOCKS, MOCKS_ERROR_SUB_TAGS } from './SubTagsMocks'; +import { InMemoryCache, type ApolloLink } from '@apollo/client'; const translations = { ...JSON.parse( @@ -39,7 +35,6 @@ const translations = { const link = new StaticMockLink(MOCKS, true); const link2 = new StaticMockLink(MOCKS_ERROR_SUB_TAGS, true); -const link3 = new StaticMockLink(MOCKS_ERROR_TAG_ANCESTORS, true); async function wait(ms = 500): Promise { await act(() => { @@ -56,25 +51,37 @@ jest.mock('react-toastify', () => ({ }, })); -// const cache = new InMemoryCache({ -// typePolicies: { -// Query: { -// fields: { -// getUserTag: { -// keyArgs: false, -// merge(_, incoming) { -// return incoming; -// }, -// }, -// }, -// }, -// }, -// }); +const cache = new InMemoryCache({ + typePolicies: { + Query: { + fields: { + getUserTag: { + merge(existing = {}, incoming) { + const merged = { + ...existing, + ...incoming, + childTags: { + ...existing.childTags, + ...incoming.childTags, + edges: [ + ...(existing.childTags?.edges || []), + ...(incoming.childTags?.edges || []), + ], + }, + }; + + return merged; + }, + }, + }, + }, + }, +}); const renderSubTags = (link: ApolloLink): RenderResult => { return render( - - + + @@ -104,6 +111,7 @@ describe('Organisation Tags Page', () => { ...jest.requireActual('react-router-dom'), useParams: () => ({ orgId: 'orgId' }), })); + cache.reset(); }); afterEach(() => { @@ -131,16 +139,6 @@ describe('Organisation Tags Page', () => { }); }); - test('renders error component on unsuccessful userTag ancestors query', async () => { - const { queryByText } = renderSubTags(link3); - - await wait(); - - await waitFor(() => { - expect(queryByText(translations.addChildTag)).not.toBeInTheDocument(); - }); - }); - test('opens and closes the create tag modal', async () => { renderSubTags(link); @@ -238,6 +236,84 @@ describe('Organisation Tags Page', () => { }); }); + test('searchs for tags where the name matches the provided search input', async () => { + renderSubTags(link); + + await wait(); + + await waitFor(() => { + expect( + screen.getByPlaceholderText(translations.searchByName), + ).toBeInTheDocument(); + }); + const input = screen.getByPlaceholderText(translations.searchByName); + fireEvent.change(input, { target: { value: 'searchSubTag' } }); + + // should render the two searched tags from the mock data + // where name starts with "searchUserTag" + await waitFor(() => { + const buttons = screen.getAllByTestId('manageTagBtn'); + expect(buttons.length).toEqual(2); + }); + }); + + test('fetches the tags by the sort order, i.e. latest or oldest first', async () => { + renderSubTags(link); + + await wait(); + + await waitFor(() => { + expect( + screen.getByPlaceholderText(translations.searchByName), + ).toBeInTheDocument(); + }); + const input = screen.getByPlaceholderText(translations.searchByName); + fireEvent.change(input, { target: { value: 'searchSubTag' } }); + + // should render the two searched tags from the mock data + // where name starts with "searchUserTag" + await waitFor(() => { + expect(screen.getAllByTestId('tagName')[0]).toHaveTextContent( + 'searchSubTag 1', + ); + }); + + // now change the sorting order + await waitFor(() => { + expect(screen.getByTestId('sortTags')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('sortTags')); + + await waitFor(() => { + expect(screen.getByTestId('oldest')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('oldest')); + + // returns the tags in reverse order + await waitFor(() => { + expect(screen.getAllByTestId('tagName')[0]).toHaveTextContent( + 'searchSubTag 2', + ); + }); + + await waitFor(() => { + expect(screen.getByTestId('sortTags')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('sortTags')); + + await waitFor(() => { + expect(screen.getByTestId('latest')).toBeInTheDocument(); + }); + userEvent.click(screen.getByTestId('latest')); + + // reverse the order again + await waitFor(() => { + expect(screen.getAllByTestId('tagName')[0]).toHaveTextContent( + 'searchSubTag 1', + ); + }); + }); + test('Fetches more sub tags with infinite scroll', async () => { const { getByText } = renderSubTags(link); diff --git a/src/screens/SubTags/SubTags.tsx b/src/screens/SubTags/SubTags.tsx index 193670ac59..063ce9f028 100644 --- a/src/screens/SubTags/SubTags.tsx +++ b/src/screens/SubTags/SubTags.tsx @@ -1,5 +1,5 @@ -import { useMutation, useQuery, type ApolloError } from '@apollo/client'; -import { Search, WarningAmberRounded } from '@mui/icons-material'; +import { useMutation, useQuery } from '@apollo/client'; +import { WarningAmberRounded } from '@mui/icons-material'; import SortIcon from '@mui/icons-material/Sort'; import Loader from 'components/Loader/Loader'; import IconComponent from 'components/IconComponent/IconComponent'; @@ -16,7 +16,10 @@ import { toast } from 'react-toastify'; import type { InterfaceQueryUserTagChildTags } from 'utils/interfaces'; import styles from './SubTags.module.css'; import { DataGrid } from '@mui/x-data-grid'; -import type { InterfaceOrganizationSubTagsQuery } from 'utils/organizationTagsUtils'; +import type { + InterfaceOrganizationSubTagsQuery, + SortedByType, +} from 'utils/organizationTagsUtils'; import { dataGridStyle, TAGS_QUERY_DATA_CHUNK_SIZE, @@ -24,10 +27,7 @@ import { import type { GridCellParams, GridColDef } from '@mui/x-data-grid'; import { Stack } from '@mui/material'; import { CREATE_USER_TAG } from 'GraphQl/Mutations/TagMutations'; -import { - USER_TAG_ANCESTORS, - USER_TAG_SUB_TAGS, -} from 'GraphQl/Queries/userTagQueries'; +import { USER_TAG_SUB_TAGS } from 'GraphQl/Queries/userTagQueries'; import InfiniteScroll from 'react-infinite-scroll-component'; import InfiniteScrollLoader from 'components/InfiniteScrollLoader/InfiniteScrollLoader'; @@ -52,6 +52,9 @@ function SubTags(): JSX.Element { const [tagName, setTagName] = useState(''); + const [tagSearchName, setTagSearchName] = useState(''); + const [tagSortOrder, setTagSortOrder] = useState('DESCENDING'); + const showAddSubTagModal = (): void => { setAddSubTagModalIsOpen(true); }; @@ -71,6 +74,8 @@ function SubTags(): JSX.Element { variables: { id: parentTagId, first: TAGS_QUERY_DATA_CHUNK_SIZE, + where: { name: { starts_with: tagSearchName } }, + sortedBy: { id: tagSortOrder }, }, }); @@ -88,7 +93,7 @@ function SubTags(): JSX.Element { fetchMoreResult?: { getChildTags: InterfaceQueryUserTagChildTags }; }, ) => { - if (!fetchMoreResult) return prevResult; + if (!fetchMoreResult) /* istanbul ignore next */ return prevResult; return { getChildTags: { @@ -106,26 +111,6 @@ function SubTags(): JSX.Element { }); }; - const { - data: orgUserTagAncestorsData, - loading: orgUserTagsAncestorsLoading, - error: orgUserTagsAncestorsError, - }: { - data?: { - getUserTagAncestors: { - _id: string; - name: string; - }[]; - }; - loading: boolean; - error?: ApolloError; - refetch: () => void; - } = useQuery(USER_TAG_ANCESTORS, { - variables: { - id: parentTagId, - }, - }); - const [create, { loading: createUserTagLoading }] = useMutation(CREATE_USER_TAG); @@ -156,22 +141,13 @@ function SubTags(): JSX.Element { } }; - if (createUserTagLoading || subTagsLoading || orgUserTagsAncestorsLoading) { - return ; - } - - if (subTagsError || orgUserTagsAncestorsError) { + if (subTagsError) { return (
- Error occured while loading{' '} - {subTagsError ? 'sub tags' : 'tag ancestors'} -
- {subTagsError - ? subTagsError.message - : orgUserTagsAncestorsError?.message} + Error occured while loading sub tags
@@ -182,7 +158,17 @@ function SubTags(): JSX.Element { subTagsData?.getChildTags.childTags.edges.map((edge) => edge.node) ?? /* istanbul ignore next */ []; - const orgUserTagAncestors = orgUserTagAncestorsData?.getUserTagAncestors; + const parentTagName = subTagsData?.getChildTags.name; + + // get the ancestorTags array and push the current tag in it + // used for the tag breadcrumbs + const orgUserTagAncestors = [ + ...(subTagsData?.getChildTags.ancestorTags ?? []), + { + _id: parentTagId, + name: parentTagName, + }, + ]; const redirectToManageTag = (tagId: string): void => { navigate(`/orgtags/${orgId}/manageTag/${tagId}`); @@ -296,21 +282,16 @@ function SubTags(): JSX.Element {
+ setTagSearchName(e.target.value.trim())} data-testid="searchByName" autoComplete="off" - required /> -
- {tCommon('sort')} + {tagSortOrder === 'DESCENDING' + ? tCommon('Latest') + : tCommon('Oldest')} - + setTagSortOrder('DESCENDING')} + > {tCommon('Latest')} - + setTagSortOrder('ASCENDING')} + > {tCommon('Oldest')} @@ -355,82 +344,86 @@ function SubTags(): JSX.Element {
-
-
-
- -
- -
navigate(`/orgtags/${orgId}`)} - className={`fs-6 ms-3 my-1 ${styles.tagsBreadCrumbs}`} - data-testid="allTagsBtn" - > - {'Tags'} - -
+ {subTagsLoading || createUserTagLoading ? ( + + ) : ( +
+
+
+ +
- {orgUserTagAncestors?.map((tag, index) => (
redirectToSubTags(tag._id as string)} - data-testid="redirectToSubTags" + onClick={() => navigate(`/orgtags/${orgId}`)} + className={`fs-6 ms-3 my-1 ${styles.tagsBreadCrumbs}`} + data-testid="allTagsBtn" > - {tag.name} - - {orgUserTagAncestors.length - 1 !== index && ( - - )} + {'Tags'} +
- ))} -
-
- } - scrollableTarget="subTagsScrollableDiv" + + {orgUserTagAncestors?.map((tag, index) => ( +
redirectToSubTags(tag._id as string)} + data-testid="redirectToSubTags" + > + {tag.name} + + {orgUserTagAncestors.length - 1 !== index && ( + + )} +
+ ))} +
+
- row.id} - slots={{ - noRowsOverlay: /* istanbul ignore next */ () => ( - - {t('noTagsFound')} - - ), - }} - sx={dataGridStyle} - getRowClassName={() => `${styles.rowBackground}`} - autoHeight - rowHeight={65} - rows={subTagsList?.map((subTag, index) => ({ - id: index + 1, - ...subTag, - }))} - columns={columns} - isRowSelectable={() => false} - /> - + } + scrollableTarget="subTagsScrollableDiv" + > + row.id} + slots={{ + noRowsOverlay: /* istanbul ignore next */ () => ( + + {t('noTagsFound')} + + ), + }} + sx={dataGridStyle} + getRowClassName={() => `${styles.rowBackground}`} + autoHeight + rowHeight={65} + rows={subTagsList?.map((subTag, index) => ({ + id: index + 1, + ...subTag, + }))} + columns={columns} + isRowSelectable={() => false} + /> + +
-
+ )}
diff --git a/src/screens/SubTags/SubTagsMocks.ts b/src/screens/SubTags/SubTagsMocks.ts index b51541a5e7..5165ea3a53 100644 --- a/src/screens/SubTags/SubTagsMocks.ts +++ b/src/screens/SubTags/SubTagsMocks.ts @@ -1,8 +1,5 @@ import { CREATE_USER_TAG } from 'GraphQl/Mutations/TagMutations'; -import { - USER_TAG_ANCESTORS, - USER_TAG_SUB_TAGS, -} from 'GraphQl/Queries/userTagQueries'; +import { USER_TAG_SUB_TAGS } from 'GraphQl/Queries/userTagQueries'; import { TAGS_QUERY_DATA_CHUNK_SIZE } from 'utils/organizationTagsUtils'; export const MOCKS = [ @@ -12,6 +9,8 @@ export const MOCKS = [ variables: { id: '1', first: TAGS_QUERY_DATA_CHUNK_SIZE, + where: { name: { starts_with: '' } }, + sortedBy: { id: 'DESCENDING' }, }, }, result: { @@ -30,6 +29,12 @@ export const MOCKS = [ childTags: { totalCount: 5, }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], }, cursor: 'subTag1', }, @@ -43,6 +48,12 @@ export const MOCKS = [ childTags: { totalCount: 0, }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], }, cursor: 'subTag2', }, @@ -56,6 +67,12 @@ export const MOCKS = [ childTags: { totalCount: 5, }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], }, cursor: 'subTag3', }, @@ -69,6 +86,12 @@ export const MOCKS = [ childTags: { totalCount: 0, }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], }, cursor: 'subTag4', }, @@ -82,6 +105,12 @@ export const MOCKS = [ childTags: { totalCount: 5, }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], }, cursor: 'subTag5', }, @@ -95,6 +124,12 @@ export const MOCKS = [ childTags: { totalCount: 5, }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], }, cursor: 'subTag6', }, @@ -108,6 +143,12 @@ export const MOCKS = [ childTags: { totalCount: 5, }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], }, cursor: 'subTag7', }, @@ -121,6 +162,12 @@ export const MOCKS = [ childTags: { totalCount: 5, }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], }, cursor: 'subTag8', }, @@ -134,6 +181,12 @@ export const MOCKS = [ childTags: { totalCount: 5, }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], }, cursor: 'subTag9', }, @@ -147,6 +200,12 @@ export const MOCKS = [ childTags: { totalCount: 5, }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], }, cursor: 'subTag10', }, @@ -159,6 +218,7 @@ export const MOCKS = [ }, totalCount: 11, }, + ancestorTags: [], }, }, }, @@ -170,12 +230,14 @@ export const MOCKS = [ id: '1', after: '10', first: TAGS_QUERY_DATA_CHUNK_SIZE, + where: { name: { starts_with: '' } }, + sortedBy: { id: 'DESCENDING' }, }, }, result: { data: { getChildTags: { - name: 'tag1', + name: 'userTag 1', childTags: { edges: [ { @@ -188,6 +250,12 @@ export const MOCKS = [ childTags: { totalCount: 0, }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], }, cursor: 'subTag11', }, @@ -200,34 +268,19 @@ export const MOCKS = [ }, totalCount: 11, }, + ancestorTags: [], }, }, }, }, - { - request: { - query: USER_TAG_ANCESTORS, - variables: { - id: '1', - }, - }, - result: { - data: { - getUserTagAncestors: [ - { - _id: '1', - name: 'tag1', - }, - ], - }, - }, - }, { request: { query: USER_TAG_SUB_TAGS, variables: { id: 'subTag1', first: TAGS_QUERY_DATA_CHUNK_SIZE, + where: { name: { starts_with: '' } }, + sortedBy: { id: 'DESCENDING' }, }, }, result: { @@ -246,6 +299,16 @@ export const MOCKS = [ childTags: { totalCount: 5, }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + { + _id: 'subTag1', + name: 'subTag 1', + }, + ], }, cursor: 'subTag1.1', }, @@ -258,109 +321,180 @@ export const MOCKS = [ }, totalCount: 1, }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], }, }, }, }, { request: { - query: USER_TAG_ANCESTORS, + query: USER_TAG_SUB_TAGS, variables: { - id: 'subTag1', + id: '1', + first: TAGS_QUERY_DATA_CHUNK_SIZE, + where: { name: { starts_with: 'searchSubTag' } }, + sortedBy: { id: 'DESCENDING' }, }, }, result: { data: { - getUserTagAncestors: [ - { - _id: '1', - name: 'tag 1', - }, - { - _id: 'subTag1', - name: 'subTag 1', + getChildTags: { + name: 'userTag 1', + childTags: { + edges: [ + { + node: { + _id: 'searchSubTag1', + name: 'searchSubTag 1', + usersAssignedTo: { + totalCount: 0, + }, + childTags: { + totalCount: 0, + }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], + }, + cursor: 'searchSubTag1', + }, + { + node: { + _id: 'searchSubTag2', + name: 'searchSubTag 2', + usersAssignedTo: { + totalCount: 0, + }, + childTags: { + totalCount: 0, + }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], + }, + cursor: 'searchSubTag2', + }, + ], + pageInfo: { + startCursor: 'searchSubTag1', + endCursor: 'searchSubTag2', + hasNextPage: false, + hasPreviousPage: false, + }, + totalCount: 2, }, - ], - }, - }, - }, - { - request: { - query: CREATE_USER_TAG, - variables: { - name: 'subTag 12', - organizationId: '123', - parentTagId: '1', - }, - }, - result: { - data: { - createUserTag: { - _id: 'subTag12', + ancestorTags: [], }, }, }, }, -]; - -export const MOCKS_ERROR_SUB_TAGS = [ { request: { query: USER_TAG_SUB_TAGS, variables: { id: '1', first: TAGS_QUERY_DATA_CHUNK_SIZE, - }, - }, - error: new Error('Mock Graphql Error'), - }, - { - request: { - query: USER_TAG_ANCESTORS, - variables: { - id: '1', + where: { name: { starts_with: 'searchSubTag' } }, + sortedBy: { id: 'ASCENDING' }, }, }, result: { data: { - getUserTagAncestors: [], + getChildTags: { + name: 'userTag 1', + childTags: { + edges: [ + { + node: { + _id: 'searchSubTag2', + name: 'searchSubTag 2', + usersAssignedTo: { + totalCount: 0, + }, + childTags: { + totalCount: 0, + }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], + }, + cursor: 'searchSubTag2', + }, + { + node: { + _id: 'searchSubTag1', + name: 'searchSubTag 1', + usersAssignedTo: { + totalCount: 0, + }, + childTags: { + totalCount: 0, + }, + ancestorTags: [ + { + _id: '1', + name: 'userTag 1', + }, + ], + }, + cursor: 'searchSubTag1', + }, + ], + pageInfo: { + startCursor: 'searchSubTag2', + endCursor: 'searchSubTag1', + hasNextPage: false, + hasPreviousPage: false, + }, + totalCount: 2, + }, + ancestorTags: [], + }, }, }, }, -]; - -export const MOCKS_ERROR_TAG_ANCESTORS = [ { request: { - query: USER_TAG_SUB_TAGS, + query: CREATE_USER_TAG, variables: { - id: '1', - first: TAGS_QUERY_DATA_CHUNK_SIZE, + name: 'subTag 12', + organizationId: '123', + parentTagId: '1', }, }, result: { data: { - getChildTags: { - name: 'tag1', - childTags: { - edges: [], - pageInfo: { - startCursor: '0', - endCursor: '0', - hasNextPage: false, - hasPreviousPage: false, - }, - totalCount: 0, - }, + createUserTag: { + _id: 'subTag12', }, }, }, }, +]; + +export const MOCKS_ERROR_SUB_TAGS = [ { request: { - query: USER_TAG_ANCESTORS, + query: USER_TAG_SUB_TAGS, variables: { id: '1', + first: TAGS_QUERY_DATA_CHUNK_SIZE, + where: { name: { starts_with: '' } }, + sortedBy: { id: 'DESCENDING' }, }, }, error: new Error('Mock Graphql Error'), diff --git a/src/utils/interfaces.ts b/src/utils/interfaces.ts index 3d3af2ac64..234b36262e 100644 --- a/src/utils/interfaces.ts +++ b/src/utils/interfaces.ts @@ -212,12 +212,17 @@ export interface InterfaceQueryOrganizationPostListItem { export interface InterfaceTagData { _id: string; name: string; + parentTag: { _id: string }; usersAssignedTo: { totalCount: number; }; childTags: { totalCount: number; }; + ancestorTags: { + _id: string; + name: string; + }[]; } interface InterfaceTagNodeData { @@ -258,16 +263,19 @@ export interface InterfaceQueryOrganizationUserTags { export interface InterfaceQueryUserTagChildTags { name: string; childTags: InterfaceTagNodeData; + ancestorTags: { + _id: string; + name: string; + }[]; } export interface InterfaceQueryUserTagsAssignedMembers { name: string; usersAssignedTo: InterfaceTagMembersData; -} - -export interface InterfaceQueryUserTagsMembersToAssignTo { - name: string; - usersToAssignTo: InterfaceTagMembersData; + ancestorTags: { + _id: string; + name: string; + }[]; } export interface InterfaceQueryUserTagsMembersToAssignTo { diff --git a/src/utils/organizationTagsUtils.ts b/src/utils/organizationTagsUtils.ts index 75c001816e..99faca3bf2 100644 --- a/src/utils/organizationTagsUtils.ts +++ b/src/utils/organizationTagsUtils.ts @@ -44,6 +44,9 @@ export const TAGS_QUERY_DATA_CHUNK_SIZE = 10; // the tag action type export type TagActionType = 'assignToTags' | 'removeFromTags'; +// the sortedByType +export type SortedByType = 'ASCENDING' | 'DESCENDING'; + // Interfaces for tag queries: // 1. Base interface for Apollo query results interface InterfaceBaseQueryResult { From 17c53a85f27b29b7e79d14b354fe165dd7067073 Mon Sep 17 00:00:00 2001 From: adithya <144007420+adithyanotfound@users.noreply.github.com> Date: Sat, 2 Nov 2024 18:06:09 +0530 Subject: [PATCH 2/2] Upgraded mui (#2399) --- jest.config.js | 1 - package-lock.json | 1226 ++++++++++++++--- package.json | 15 +- src/components/Pagination/Pagination.test.tsx | 19 +- 4 files changed, 1071 insertions(+), 190 deletions(-) diff --git a/jest.config.js b/jest.config.js index 4346984c74..42a132d348 100644 --- a/jest.config.js +++ b/jest.config.js @@ -23,7 +23,6 @@ export default { ], moduleNameMapper: { '^react-native$': 'react-native-web', - '^@mui/(.*)$': '/node_modules/@mui/$1', '^@dicebear/core$': '/scripts/__mocks__/@dicebear/core.ts', '^@dicebear/collection$': '/scripts/__mocks__/@dicebear/collection.ts', diff --git a/package-lock.json b/package-lock.json index 31efdaed89..cb98e5dccf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,13 +15,14 @@ "@dicebear/core": "^8.0.2", "@emotion/react": "^11.13.3", "@emotion/styled": "^11.13.0", - "@mui/icons-material": "^5.16.7", - "@mui/material": "^5.16.7", - "@mui/private-theming": "^5.15.12", - "@mui/system": "^5.14.12", - "@mui/x-charts": "^7.17.0", - "@mui/x-data-grid": "^7.22.0", - "@mui/x-date-pickers": "^7.11.1", + "@mui/base": "^5.0.0-beta.61", + "@mui/icons-material": "^6.1.6", + "@mui/material": "^6.1.6", + "@mui/private-theming": "^6.1.6", + "@mui/system": "^6.1.6", + "@mui/x-charts": "^7.22.1", + "@mui/x-data-grid": "^7.22.1", + "@mui/x-date-pickers": "^7.22.1", "@pdfme/generator": "^4.5.2", "@reduxjs/toolkit": "^2.3.0", "@vitejs/plugin-react": "^4.3.2", @@ -2699,14 +2700,14 @@ } }, "node_modules/@emotion/serialize": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.1.tgz", - "integrity": "sha512-dEPNKzBPU+vFPGa+z3axPRn8XVDetYORmDC0wAiej+TNcOZE70ZMJa0X7JdeoM6q/nWTMZeLpN/fTnD9o8MQBA==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.2.tgz", + "integrity": "sha512-grVnMvVPK9yUVE6rkKfAJlYZgo0cu3l9iMC77V7DW6E1DUIrU68pSEXRmFZFOFB1QFo57TncmOcvcbMDWsL4yA==", "dependencies": { "@emotion/hash": "^0.9.2", "@emotion/memoize": "^0.9.0", "@emotion/unitless": "^0.10.0", - "@emotion/utils": "^1.4.0", + "@emotion/utils": "^1.4.1", "csstype": "^3.0.2" } }, @@ -2753,10 +2754,9 @@ } }, "node_modules/@emotion/utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.0.tgz", - "integrity": "sha512-spEnrA1b6hDR/C68lC2M7m6ALPUHZC0lIY7jAS/B/9DuuO1ZP04eov8SMv/6fwRd8pzmsn2AuJEznRREWlQrlQ==", - "license": "MIT" + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.1.tgz", + "integrity": "sha512-BymCXzCG3r72VKJxaYVwOXATqXIZ85cuvg0YOUDxMGNrKc1DJRZk8MgV5wyXRyEayIMd4FuXJIUgTBXvDNW5cA==" }, "node_modules/@emotion/weak-memoize": { "version": "0.4.0", @@ -2764,6 +2764,337 @@ "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==", "license": "MIT" }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.1.tgz", + "integrity": "sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/@esbuild/win32-x64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", @@ -3475,20 +3806,20 @@ } }, "node_modules/@mui/base": { - "version": "5.0.0-beta.40", - "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.40.tgz", - "integrity": "sha512-I/lGHztkCzvwlXpjD2+SNmvNQvB4227xBXhISPjEaJUXGImOQ9f3D2Yj/T3KasSI/h0MLWy74X0J6clhPmsRbQ==", - "dependencies": { - "@babel/runtime": "^7.23.9", - "@floating-ui/react-dom": "^2.0.8", - "@mui/types": "^7.2.14", - "@mui/utils": "^5.15.14", + "version": "5.0.0-beta.61", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.61.tgz", + "integrity": "sha512-YaMOTXS3ecDNGsPKa6UdlJ8loFLvcL9+VbpCK3hfk71OaNauZRp4Yf7KeXDYr7Ms3M/XBD3SaiR6JMr6vYtfDg==", + "dependencies": { + "@babel/runtime": "^7.26.0", + "@floating-ui/react-dom": "^2.1.1", + "@mui/types": "^7.2.19", + "@mui/utils": "^6.1.6", "@popperjs/core": "^2.11.8", - "clsx": "^2.1.0", + "clsx": "^2.1.1", "prop-types": "^15.8.1" }, "engines": { - "node": ">=12.0.0" + "node": ">=14.0.0" }, "funding": { "type": "opencollective", @@ -3506,32 +3837,32 @@ } }, "node_modules/@mui/core-downloads-tracker": { - "version": "5.16.7", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.16.7.tgz", - "integrity": "sha512-RtsCt4Geed2/v74sbihWzzRs+HsIQCfclHeORh5Ynu2fS4icIKozcSubwuG7vtzq2uW3fOR1zITSP84TNt2GoQ==", + "version": "6.1.6", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-6.1.6.tgz", + "integrity": "sha512-nz1SlR9TdBYYPz4qKoNasMPRiGb4PaIHFkzLzhju0YVYS5QSuFF2+n7CsiHMIDcHv3piPu/xDWI53ruhOqvZwQ==", "funding": { "type": "opencollective", "url": "https://opencollective.com/mui-org" } }, "node_modules/@mui/icons-material": { - "version": "5.16.7", - "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.16.7.tgz", - "integrity": "sha512-UrGwDJCXEszbDI7yV047BYU5A28eGJ79keTCP4cc74WyncuVrnurlmIRxaHL8YK+LI1Kzq+/JM52IAkNnv4u+Q==", + "version": "6.1.6", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-6.1.6.tgz", + "integrity": "sha512-5r9urIL2lxXb/sPN3LFfFYEibsXJUb986HhhIeu1gOcte460pwdSiEhBSxkAuyT8Dj7jvu9MjqSBmSumQELo8A==", "dependencies": { - "@babel/runtime": "^7.23.9" + "@babel/runtime": "^7.26.0" }, "engines": { - "node": ">=12.0.0" + "node": ">=14.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/mui-org" }, "peerDependencies": { - "@mui/material": "^5.0.0", - "@types/react": "^17.0.0 || ^18.0.0", - "react": "^17.0.0 || ^18.0.0" + "@mui/material": "^6.1.6", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, "peerDependenciesMeta": { "@types/react": { @@ -3540,25 +3871,25 @@ } }, "node_modules/@mui/material": { - "version": "5.16.7", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.16.7.tgz", - "integrity": "sha512-cwwVQxBhK60OIOqZOVLFt55t01zmarKJiJUWbk0+8s/Ix5IaUzAShqlJchxsIQ4mSrWqgcKCCXKtIlG5H+/Jmg==", - "dependencies": { - "@babel/runtime": "^7.23.9", - "@mui/core-downloads-tracker": "^5.16.7", - "@mui/system": "^5.16.7", - "@mui/types": "^7.2.15", - "@mui/utils": "^5.16.6", + "version": "6.1.6", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-6.1.6.tgz", + "integrity": "sha512-1yvejiQ/601l5AK3uIdUlAVElyCxoqKnl7QA+2oFB/2qYPWfRwDgavW/MoywS5Y2gZEslcJKhe0s2F3IthgFgw==", + "dependencies": { + "@babel/runtime": "^7.26.0", + "@mui/core-downloads-tracker": "^6.1.6", + "@mui/system": "^6.1.6", + "@mui/types": "^7.2.19", + "@mui/utils": "^6.1.6", "@popperjs/core": "^2.11.8", - "@types/react-transition-group": "^4.4.10", - "clsx": "^2.1.0", + "@types/react-transition-group": "^4.4.11", + "clsx": "^2.1.1", "csstype": "^3.1.3", "prop-types": "^15.8.1", "react-is": "^18.3.1", "react-transition-group": "^4.4.5" }, "engines": { - "node": ">=12.0.0" + "node": ">=14.0.0" }, "funding": { "type": "opencollective", @@ -3567,9 +3898,10 @@ "peerDependencies": { "@emotion/react": "^11.5.0", "@emotion/styled": "^11.3.0", - "@types/react": "^17.0.0 || ^18.0.0", - "react": "^17.0.0 || ^18.0.0", - "react-dom": "^17.0.0 || ^18.0.0" + "@mui/material-pigment-css": "^6.1.6", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" }, "peerDependenciesMeta": { "@emotion/react": { @@ -3578,30 +3910,33 @@ "@emotion/styled": { "optional": true }, + "@mui/material-pigment-css": { + "optional": true + }, "@types/react": { "optional": true } } }, "node_modules/@mui/private-theming": { - "version": "5.16.6", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.16.6.tgz", - "integrity": "sha512-rAk+Rh8Clg7Cd7shZhyt2HGTTE5wYKNSJ5sspf28Fqm/PZ69Er9o6KX25g03/FG2dfpg5GCwZh/xOojiTfm3hw==", + "version": "6.1.6", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-6.1.6.tgz", + "integrity": "sha512-ioAiFckaD/fJSnTrUMWgjl9HYBWt7ixCh7zZw7gDZ+Tae7NuprNV6QJK95EidDT7K0GetR2rU3kAeIR61Myttw==", "dependencies": { - "@babel/runtime": "^7.23.9", - "@mui/utils": "^5.16.6", + "@babel/runtime": "^7.26.0", + "@mui/utils": "^6.1.6", "prop-types": "^15.8.1" }, "engines": { - "node": ">=12.0.0" + "node": ">=14.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/mui-org" }, "peerDependencies": { - "@types/react": "^17.0.0 || ^18.0.0", - "react": "^17.0.0 || ^18.0.0" + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, "peerDependenciesMeta": { "@types/react": { @@ -3610,17 +3945,19 @@ } }, "node_modules/@mui/styled-engine": { - "version": "5.16.6", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.16.6.tgz", - "integrity": "sha512-zaThmS67ZmtHSWToTiHslbI8jwrmITcN93LQaR2lKArbvS7Z3iLkwRoiikNWutx9MBs8Q6okKvbZq1RQYB3v7g==", + "version": "6.1.6", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-6.1.6.tgz", + "integrity": "sha512-I+yS1cSuSvHnZDBO7e7VHxTWpj+R7XlSZvTC4lS/OIbUNJOMMSd3UDP6V2sfwzAdmdDNBi7NGCRv2SZ6O9hGDA==", "dependencies": { - "@babel/runtime": "^7.23.9", - "@emotion/cache": "^11.11.0", + "@babel/runtime": "^7.26.0", + "@emotion/cache": "^11.13.1", + "@emotion/serialize": "^1.3.2", + "@emotion/sheet": "^1.4.0", "csstype": "^3.1.3", "prop-types": "^15.8.1" }, "engines": { - "node": ">=12.0.0" + "node": ">=14.0.0" }, "funding": { "type": "opencollective", @@ -3629,7 +3966,7 @@ "peerDependencies": { "@emotion/react": "^11.4.1", "@emotion/styled": "^11.3.0", - "react": "^17.0.0 || ^18.0.0" + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, "peerDependenciesMeta": { "@emotion/react": { @@ -3641,21 +3978,21 @@ } }, "node_modules/@mui/system": { - "version": "5.16.7", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.16.7.tgz", - "integrity": "sha512-Jncvs/r/d/itkxh7O7opOunTqbbSSzMTHzZkNLM+FjAOg+cYAZHrPDlYe1ZGKUYORwwb2XexlWnpZp0kZ4AHuA==", - "dependencies": { - "@babel/runtime": "^7.23.9", - "@mui/private-theming": "^5.16.4", - "@mui/styled-engine": "^5.16.4", - "@mui/types": "^7.2.15", - "@mui/utils": "^5.16.4", - "clsx": "^2.1.0", + "version": "6.1.6", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-6.1.6.tgz", + "integrity": "sha512-qOf1VUE9wK8syiB0BBCp82oNBAVPYdj4Trh+G1s+L+ImYiKlubWhhqlnvWt3xqMevR+D2h1CXzA1vhX2FvA+VQ==", + "dependencies": { + "@babel/runtime": "^7.26.0", + "@mui/private-theming": "^6.1.6", + "@mui/styled-engine": "^6.1.6", + "@mui/types": "^7.2.19", + "@mui/utils": "^6.1.6", + "clsx": "^2.1.1", "csstype": "^3.1.3", "prop-types": "^15.8.1" }, "engines": { - "node": ">=12.0.0" + "node": ">=14.0.0" }, "funding": { "type": "opencollective", @@ -3664,8 +4001,8 @@ "peerDependencies": { "@emotion/react": "^11.5.0", "@emotion/styled": "^11.3.0", - "@types/react": "^17.0.0 || ^18.0.0", - "react": "^17.0.0 || ^18.0.0" + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, "peerDependenciesMeta": { "@emotion/react": { @@ -3680,11 +4017,11 @@ } }, "node_modules/@mui/types": { - "version": "7.2.15", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.15.tgz", - "integrity": "sha512-nbo7yPhtKJkdf9kcVOF8JZHPZTmqXjJ/tI0bdWgHg5tp9AnIN4Y7f7wm9T+0SyGYJk76+GYZ8Q5XaTYAsUHN0Q==", + "version": "7.2.19", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.19.tgz", + "integrity": "sha512-6XpZEM/Q3epK9RN8ENoXuygnqUQxE+siN/6rGRi2iwJPgBUR25mphYQ9ZI87plGh58YoZ5pp40bFvKYOCDJ3tA==", "peerDependencies": { - "@types/react": "^17.0.0 || ^18.0.0" + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, "peerDependenciesMeta": { "@types/react": { @@ -3693,27 +4030,27 @@ } }, "node_modules/@mui/utils": { - "version": "5.16.6", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.16.6.tgz", - "integrity": "sha512-tWiQqlhxAt3KENNiSRL+DIn9H5xNVK6Jjf70x3PnfQPz1MPBdh7yyIcAyVBT9xiw7hP3SomRhPR7hzBMBCjqEA==", + "version": "6.1.6", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.1.6.tgz", + "integrity": "sha512-sBS6D9mJECtELASLM+18WUcXF6RH3zNxBRFeyCRg8wad6NbyNrdxLuwK+Ikvc38sTZwBzAz691HmSofLqHd9sQ==", "dependencies": { - "@babel/runtime": "^7.23.9", - "@mui/types": "^7.2.15", - "@types/prop-types": "^15.7.12", + "@babel/runtime": "^7.26.0", + "@mui/types": "^7.2.19", + "@types/prop-types": "^15.7.13", "clsx": "^2.1.1", "prop-types": "^15.8.1", "react-is": "^18.3.1" }, "engines": { - "node": ">=12.0.0" + "node": ">=14.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/mui-org" }, "peerDependencies": { - "@types/react": "^17.0.0 || ^18.0.0", - "react": "^17.0.0 || ^18.0.0" + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, "peerDependenciesMeta": { "@types/react": { @@ -3722,16 +4059,16 @@ } }, "node_modules/@mui/x-charts": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@mui/x-charts/-/x-charts-7.17.0.tgz", - "integrity": "sha512-xDH/lOnb57+VBIA7q+1KlC0Ht1O46d/N2MEl1tUq1JYIXhA2Owi5cp+bcaof8Rvw5ApCmkoBxyUIjqT0guNIwA==", - "dependencies": { - "@babel/runtime": "^7.25.6", - "@mui/utils": "^5.16.6", - "@mui/x-charts-vendor": "7.16.0", - "@mui/x-internals": "7.17.0", - "@react-spring/rafz": "^9.7.4", - "@react-spring/web": "^9.7.4", + "version": "7.22.1", + "resolved": "https://registry.npmjs.org/@mui/x-charts/-/x-charts-7.22.1.tgz", + "integrity": "sha512-zgr8CN4yLen5puqaX7Haj5+AoVG7E13HHsIiDoEAuQvuFDF0gKTxTTdLSKXqhd1qJUIIzJaztZtrr3YCVrENqw==", + "dependencies": { + "@babel/runtime": "^7.25.7", + "@mui/utils": "^5.16.6 || ^6.0.0", + "@mui/x-charts-vendor": "7.20.0", + "@mui/x-internals": "7.21.0", + "@react-spring/rafz": "^9.7.5", + "@react-spring/web": "^9.7.5", "clsx": "^2.1.1", "prop-types": "^15.8.1" }, @@ -3756,11 +4093,11 @@ } }, "node_modules/@mui/x-charts-vendor": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@mui/x-charts-vendor/-/x-charts-vendor-7.16.0.tgz", - "integrity": "sha512-MyMCCl7eAM53rLbjqP4zbMy5hYtdeqCjAYCH2jpvBKdgugm2eaPLKOPM8bUVfen0wHA8BXleQrIrNceytFPyZA==", + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@mui/x-charts-vendor/-/x-charts-vendor-7.20.0.tgz", + "integrity": "sha512-pzlh7z/7KKs5o0Kk0oPcB+sY0+Dg7Q7RzqQowDQjpy5Slz6qqGsgOB5YUzn0L+2yRmvASc4Pe0914Ao3tMBogg==", "dependencies": { - "@babel/runtime": "^7.25.6", + "@babel/runtime": "^7.25.7", "@types/d3-color": "^3.1.3", "@types/d3-delaunay": "^6.0.4", "@types/d3-interpolate": "^3.0.4", @@ -3777,29 +4114,10 @@ "robust-predicates": "^3.0.2" } }, - "node_modules/@mui/x-charts/node_modules/@mui/x-internals": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@mui/x-internals/-/x-internals-7.17.0.tgz", - "integrity": "sha512-FLlAGSJl/vsuaA/8hPGazXFppyzIzxApJJDZMoTS0geUmHd0hyooISV2ltllLmrZ/DGtHhI08m8GGnHL6/vVeg==", - "dependencies": { - "@babel/runtime": "^7.25.6", - "@mui/utils": "^5.16.6" - }, - "engines": { - "node": ">=14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui-org" - }, - "peerDependencies": { - "react": "^17.0.0 || ^18.0.0" - } - }, "node_modules/@mui/x-data-grid": { - "version": "7.22.0", - "resolved": "https://registry.npmjs.org/@mui/x-data-grid/-/x-data-grid-7.22.0.tgz", - "integrity": "sha512-gXl7+hG0YRNU3YODlPvz6Q/9+EeUsPAWn/u2YMQmYTgwAxeY5QE3lY224VRnwM5v9SfTFheo1kzAKmXPdjb9tQ==", + "version": "7.22.1", + "resolved": "https://registry.npmjs.org/@mui/x-data-grid/-/x-data-grid-7.22.1.tgz", + "integrity": "sha512-YHF96MEv7ACG/VuiycZjEAPH7cZLNuV2+bi/MyR1t/e6E6LTolYFykvjSFq+Imz1mYbW4+9mEvrHZsIKL5KKIQ==", "dependencies": { "@babel/runtime": "^7.25.7", "@mui/utils": "^5.16.6 || ^6.0.0", @@ -3833,15 +4151,14 @@ } }, "node_modules/@mui/x-date-pickers": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-7.12.1.tgz", - "integrity": "sha512-Zj8kt3SCQbJp1qhMi+A3I4KqB8i5OY2Q11mdOEathFhqN/SQm1sUjIa1G09cGP1dPDgK1a6KM6qJGNtcw/nuWA==", - "dependencies": { - "@babel/runtime": "^7.24.6", - "@mui/base": "^5.0.0-beta.40", - "@mui/system": "^5.15.15", - "@mui/utils": "^5.15.14", - "@types/react-transition-group": "^4.4.10", + "version": "7.22.1", + "resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-7.22.1.tgz", + "integrity": "sha512-VBgicE+7PvJrdHSL6HyieHT6a/0dENH8RaMIM2VwUFrGoZzvik50WNwY5U+Hip1BwZLIEvlqtNRQIIj6kgBR6Q==", + "dependencies": { + "@babel/runtime": "^7.25.7", + "@mui/utils": "^5.16.6 || ^6.0.0", + "@mui/x-internals": "7.21.0", + "@types/react-transition-group": "^4.4.11", "clsx": "^2.1.1", "prop-types": "^15.8.1", "react-transition-group": "^4.4.5" @@ -3856,8 +4173,9 @@ "peerDependencies": { "@emotion/react": "^11.9.0", "@emotion/styled": "^11.8.1", - "@mui/material": "^5.15.14", - "date-fns": "^2.25.0 || ^3.2.0", + "@mui/material": "^5.15.14 || ^6.0.0", + "@mui/system": "^5.15.14 || ^6.0.0", + "date-fns": "^2.25.0 || ^3.2.0 || ^4.0.0", "date-fns-jalali": "^2.13.0-0 || ^3.2.0-0", "dayjs": "^1.10.7", "luxon": "^3.0.2", @@ -4076,25 +4394,25 @@ } }, "node_modules/@react-spring/animated": { - "version": "9.7.4", - "resolved": "https://registry.npmjs.org/@react-spring/animated/-/animated-9.7.4.tgz", - "integrity": "sha512-7As+8Pty2QlemJ9O5ecsuPKjmO0NKvmVkRR1n6mEotFgWar8FKuQt2xgxz3RTgxcccghpx1YdS1FCdElQNexmQ==", + "version": "9.7.5", + "resolved": "https://registry.npmjs.org/@react-spring/animated/-/animated-9.7.5.tgz", + "integrity": "sha512-Tqrwz7pIlsSDITzxoLS3n/v/YCUHQdOIKtOJf4yL6kYVSDTSmVK1LI1Q3M/uu2Sx4X3pIWF3xLUhlsA6SPNTNg==", "dependencies": { - "@react-spring/shared": "~9.7.4", - "@react-spring/types": "~9.7.4" + "@react-spring/shared": "~9.7.5", + "@react-spring/types": "~9.7.5" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, "node_modules/@react-spring/core": { - "version": "9.7.4", - "resolved": "https://registry.npmjs.org/@react-spring/core/-/core-9.7.4.tgz", - "integrity": "sha512-GzjA44niEJBFUe9jN3zubRDDDP2E4tBlhNlSIkTChiNf9p4ZQlgXBg50qbXfSXHQPHak/ExYxwhipKVsQ/sUTw==", + "version": "9.7.5", + "resolved": "https://registry.npmjs.org/@react-spring/core/-/core-9.7.5.tgz", + "integrity": "sha512-rmEqcxRcu7dWh7MnCcMXLvrf6/SDlSokLaLTxiPlAYi11nN3B5oiCUAblO72o+9z/87j2uzxa2Inm8UbLjXA+w==", "dependencies": { - "@react-spring/animated": "~9.7.4", - "@react-spring/shared": "~9.7.4", - "@react-spring/types": "~9.7.4" + "@react-spring/animated": "~9.7.5", + "@react-spring/shared": "~9.7.5", + "@react-spring/types": "~9.7.5" }, "funding": { "type": "opencollective", @@ -4105,36 +4423,36 @@ } }, "node_modules/@react-spring/rafz": { - "version": "9.7.4", - "resolved": "https://registry.npmjs.org/@react-spring/rafz/-/rafz-9.7.4.tgz", - "integrity": "sha512-mqDI6rW0Ca8IdryOMiXRhMtVGiEGLIO89vIOyFQXRIwwIMX30HLya24g9z4olDvFyeDW3+kibiKwtZnA4xhldA==" + "version": "9.7.5", + "resolved": "https://registry.npmjs.org/@react-spring/rafz/-/rafz-9.7.5.tgz", + "integrity": "sha512-5ZenDQMC48wjUzPAm1EtwQ5Ot3bLIAwwqP2w2owG5KoNdNHpEJV263nGhCeKKmuA3vG2zLLOdu3or6kuDjA6Aw==" }, "node_modules/@react-spring/shared": { - "version": "9.7.4", - "resolved": "https://registry.npmjs.org/@react-spring/shared/-/shared-9.7.4.tgz", - "integrity": "sha512-bEPI7cQp94dOtCFSEYpxvLxj0+xQfB5r9Ru1h8OMycsIq7zFZon1G0sHrBLaLQIWeMCllc4tVDYRTLIRv70C8w==", + "version": "9.7.5", + "resolved": "https://registry.npmjs.org/@react-spring/shared/-/shared-9.7.5.tgz", + "integrity": "sha512-wdtoJrhUeeyD/PP/zo+np2s1Z820Ohr/BbuVYv+3dVLW7WctoiN7std8rISoYoHpUXtbkpesSKuPIw/6U1w1Pw==", "dependencies": { - "@react-spring/rafz": "~9.7.4", - "@react-spring/types": "~9.7.4" + "@react-spring/rafz": "~9.7.5", + "@react-spring/types": "~9.7.5" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, "node_modules/@react-spring/types": { - "version": "9.7.4", - "resolved": "https://registry.npmjs.org/@react-spring/types/-/types-9.7.4.tgz", - "integrity": "sha512-iQVztO09ZVfsletMiY+DpT/JRiBntdsdJ4uqk3UJFhrhS8mIC9ZOZbmfGSRs/kdbNPQkVyzucceDicQ/3Mlj9g==" + "version": "9.7.5", + "resolved": "https://registry.npmjs.org/@react-spring/types/-/types-9.7.5.tgz", + "integrity": "sha512-HVj7LrZ4ReHWBimBvu2SKND3cDVUPWKLqRTmWe/fNY6o1owGOX0cAHbdPDTMelgBlVbrTKrre6lFkhqGZErK/g==" }, "node_modules/@react-spring/web": { - "version": "9.7.4", - "resolved": "https://registry.npmjs.org/@react-spring/web/-/web-9.7.4.tgz", - "integrity": "sha512-UMvCZp7I5HCVIleSa4BwbNxynqvj+mJjG2m20VO2yPoi2pnCYANy58flvz9v/YcXTAvsmL655FV3pm5fbr6akA==", + "version": "9.7.5", + "resolved": "https://registry.npmjs.org/@react-spring/web/-/web-9.7.5.tgz", + "integrity": "sha512-lmvqGwpe+CSttsWNZVr+Dg62adtKhauGwLyGE/RRyZ8AAMLgb9x3NDMA5RMElXo+IMyTkPp7nxTB8ZQlmhb6JQ==", "dependencies": { - "@react-spring/animated": "~9.7.4", - "@react-spring/core": "~9.7.4", - "@react-spring/shared": "~9.7.4", - "@react-spring/types": "~9.7.4" + "@react-spring/animated": "~9.7.5", + "@react-spring/core": "~9.7.5", + "@react-spring/shared": "~9.7.5", + "@react-spring/types": "~9.7.5" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0", @@ -4212,6 +4530,174 @@ "react": ">=16.14.0" } }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.21.3.tgz", + "integrity": "sha512-MmKSfaB9GX+zXl6E8z4koOr/xU63AMVleLEa64v7R0QF/ZloMs5vcD1sHgM64GXXS1csaJutG+ddtzcueI/BLg==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.21.3.tgz", + "integrity": "sha512-zrt8ecH07PE3sB4jPOggweBjJMzI1JG5xI2DIsUbkA+7K+Gkjys6eV7i9pOenNSDJH3eOr/jLb/PzqtmdwDq5g==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.21.3.tgz", + "integrity": "sha512-L1M0vKGO5ASKntqtsFEjTq/fD91vAqnzeaF6sfNAy55aD+Hi2pBI5DKwCO+UNDQHWsDViJLqshxOahXyLSh3EA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.21.3.tgz", + "integrity": "sha512-btVgIsCjuYFKUjopPoWiDqmoUXQDiW2A4C3Mtmp5vACm7/GnyuprqIDPNczeyR5W8rTXEbkmrJux7cJmD99D2g==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.21.3.tgz", + "integrity": "sha512-zmjbSphplZlau6ZTkxd3+NMtE4UKVy7U4aVFMmHcgO5CUbw17ZP6QCgyxhzGaU/wFFdTfiojjbLG3/0p9HhAqA==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.21.3.tgz", + "integrity": "sha512-nSZfcZtAnQPRZmUkUQwZq2OjQciR6tEoJaZVFvLHsj0MF6QhNMg0fQ6mUOsiCUpTqxTx0/O6gX0V/nYc7LrgPw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.21.3.tgz", + "integrity": "sha512-MnvSPGO8KJXIMGlQDYfvYS3IosFN2rKsvxRpPO2l2cum+Z3exiExLwVU+GExL96pn8IP+GdH8Tz70EpBhO0sIQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.21.3.tgz", + "integrity": "sha512-+W+p/9QNDr2vE2AXU0qIy0qQE75E8RTwTwgqS2G5CRQ11vzq0tbnfBd6brWhS9bCRjAjepJe2fvvkvS3dno+iw==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.21.3.tgz", + "integrity": "sha512-yXH6K6KfqGXaxHrtr+Uoy+JpNlUlI46BKVyonGiaD74ravdnF9BUNC+vV+SIuB96hUMGShhKV693rF9QDfO6nQ==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.21.3.tgz", + "integrity": "sha512-R8cwY9wcnApN/KDYWTH4gV/ypvy9yZUHlbJvfaiXSB48JO3KpwSpjOGqO4jnGkLDSk1hgjYkTbTt6Q7uvPf8eg==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.21.3.tgz", + "integrity": "sha512-kZPbX/NOPh0vhS5sI+dR8L1bU2cSO9FgxwM8r7wHzGydzfSjLRCFAT87GR5U9scj2rhzN3JPYVC7NoBbl4FZ0g==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.21.3.tgz", + "integrity": "sha512-S0Yq+xA1VEH66uiMNhijsWAafffydd2X5b77eLHfRmfLsRSpbiAWiRHV6DEpz6aOToPsgid7TI9rGd6zB1rhbg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.21.3.tgz", + "integrity": "sha512-9isNzeL34yquCPyerog+IMCNxKR8XYmGd0tHSV+OVx0TmE0aJOo9uw4fZfUuk2qxobP5sug6vNdZR6u7Mw7Q+Q==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.21.3.tgz", + "integrity": "sha512-nMIdKnfZfzn1Vsk+RuOvl43ONTZXoAPUUxgcU0tXooqg4YrAqzfKzVenqqk2g5efWh46/D28cKFrOzDSW28gTA==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@rollup/rollup-win32-x64-msvc": { "version": "4.21.3", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.21.3.tgz", @@ -4949,9 +5435,9 @@ "dev": true }, "node_modules/@types/prop-types": { - "version": "15.7.12", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", - "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==" + "version": "15.7.13", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz", + "integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==" }, "node_modules/@types/react": { "version": "18.3.3", @@ -5049,9 +5535,9 @@ } }, "node_modules/@types/react-transition-group": { - "version": "4.4.10", - "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.10.tgz", - "integrity": "sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==", + "version": "4.4.11", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.11.tgz", + "integrity": "sha512-RM05tAniPZ5DZPzzNFP+DmrcOdD0efDUxMy3145oljWSl3x9ZV5vhme98gTxFrj2lhXvmGNnUiuDyJgY9IKkNA==", "dependencies": { "@types/react": "*" } @@ -8024,6 +8510,21 @@ "@esbuild/win32-x64": "0.21.5" } }, + "node_modules/esbuild/node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -9147,6 +9648,19 @@ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -15428,6 +15942,18 @@ "fsevents": "~2.3.2" } }, + "node_modules/rollup/node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.21.3.tgz", + "integrity": "sha512-P0UxIOrKNBFTQaXTxOH4RxuEBVCgEA5UTNV6Yz7z9QHnUJ7eLX9reOd/NYMO3+XZO2cco19mXTxDMXxit4R/eQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, "node_modules/run-async": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", @@ -16549,6 +17075,358 @@ "fsevents": "~2.3.3" } }, + "node_modules/tsx/node_modules/@esbuild/aix-ppc64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.23.1.tgz", + "integrity": "sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-arm": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.23.1.tgz", + "integrity": "sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.23.1.tgz", + "integrity": "sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.23.1.tgz", + "integrity": "sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/darwin-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.23.1.tgz", + "integrity": "sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/darwin-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.23.1.tgz", + "integrity": "sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/freebsd-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.1.tgz", + "integrity": "sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/freebsd-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.23.1.tgz", + "integrity": "sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-arm": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.23.1.tgz", + "integrity": "sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.23.1.tgz", + "integrity": "sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ia32": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.23.1.tgz", + "integrity": "sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-loong64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.23.1.tgz", + "integrity": "sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-mips64el": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.23.1.tgz", + "integrity": "sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ppc64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.23.1.tgz", + "integrity": "sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-riscv64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.23.1.tgz", + "integrity": "sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-s390x": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.23.1.tgz", + "integrity": "sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.23.1.tgz", + "integrity": "sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/netbsd-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.23.1.tgz", + "integrity": "sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/openbsd-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.23.1.tgz", + "integrity": "sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/sunos-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.23.1.tgz", + "integrity": "sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.23.1.tgz", + "integrity": "sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-ia32": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.23.1.tgz", + "integrity": "sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/tsx/node_modules/@esbuild/win32-x64": { "version": "0.23.1", "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.23.1.tgz", diff --git a/package.json b/package.json index 8ef05d105f..ea3a9f9fac 100644 --- a/package.json +++ b/package.json @@ -12,13 +12,14 @@ "@dicebear/core": "^8.0.2", "@emotion/react": "^11.13.3", "@emotion/styled": "^11.13.0", - "@mui/icons-material": "^5.16.7", - "@mui/material": "^5.16.7", - "@mui/private-theming": "^5.15.12", - "@mui/system": "^5.14.12", - "@mui/x-charts": "^7.17.0", - "@mui/x-data-grid": "^7.22.0", - "@mui/x-date-pickers": "^7.11.1", + "@mui/base": "^5.0.0-beta.61", + "@mui/icons-material": "^6.1.6", + "@mui/material": "^6.1.6", + "@mui/private-theming": "^6.1.6", + "@mui/system": "^6.1.6", + "@mui/x-charts": "^7.22.1", + "@mui/x-data-grid": "^7.22.1", + "@mui/x-date-pickers": "^7.22.1", "@pdfme/generator": "^4.5.2", "@reduxjs/toolkit": "^2.3.0", "@vitejs/plugin-react": "^4.3.2", diff --git a/src/components/Pagination/Pagination.test.tsx b/src/components/Pagination/Pagination.test.tsx index b8161c4c84..40ac2ed19a 100644 --- a/src/components/Pagination/Pagination.test.tsx +++ b/src/components/Pagination/Pagination.test.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { act } from 'react'; import { render, screen } from '@testing-library/react'; import { Provider } from 'react-redux'; import { BrowserRouter } from 'react-router-dom'; @@ -17,7 +17,7 @@ describe('Testing Pagination component', () => { }, }; - test('Component should be rendered properly on rtl', () => { + test('Component should be rendered properly on rtl', async () => { render( @@ -25,9 +25,10 @@ describe('Testing Pagination component', () => { , ); - - userEvent.click(screen.getByTestId(/nextPage/i)); - userEvent.click(screen.getByTestId(/previousPage/i)); + await act(async () => { + userEvent.click(screen.getByTestId(/nextPage/i)); + userEvent.click(screen.getByTestId(/previousPage/i)); + }); }); }); @@ -41,7 +42,7 @@ const props = { theme: { direction: 'rtl' }, }; -test('Component should be rendered properly', () => { +test('Component should be rendered properly', async () => { const theme = createTheme({ direction: 'rtl', }); @@ -56,6 +57,8 @@ test('Component should be rendered properly', () => { , ); - userEvent.click(screen.getByTestId(/nextPage/i)); - userEvent.click(screen.getByTestId(/previousPage/i)); + await act(async () => { + userEvent.click(screen.getByTestId(/nextPage/i)); + userEvent.click(screen.getByTestId(/previousPage/i)); + }); });