-
-
-
-
-
-
+
+ }
+ 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}
+ />
+
-
-
-
- {'Email Users'}
+
+
{
+ setTagActionType('assignToTags');
+ showTagActionsModal();
+ }}
+ className="my-2 btn btn-primary btn-sm w-75"
+ data-testid="assignToTags"
+ >
+ {t('assignToTags')}
-
-
-
-
- {'Add to tags'}
+
{
+ setTagActionType('removeFromTags');
+ showTagActionsModal();
+ }}
+ className="mb-1 btn btn-danger btn-sm w-75"
+ data-testid="removeFromTags"
+ >
+ {t('removeFromTags')}
-
- {'Remove from tags'}
+
+
+ {tCommon('edit')}
+
+
+ {tCommon('remove')}
@@ -432,80 +552,48 @@ function ManageTag(): JSX.Element {
{/* Add People To Tag Modal */}
-
-
- {t('addPeople')}
-
-
-
-
- {/* Unassign Tag Modal */}
-
-
-
- {t('unassignUserTag')}
-
-
- {t('unassignUserTagMessage')}
-
-
-
-
-
+
+ {/* Assign People To Tags Modal */}
+
+ {/* Unassign User Tag Modal */}
+
+ {/* Edit User Tag Modal */}
+
+ {/* Remove User Tag Modal */}
+
>
);
}
-
export default ManageTag;
diff --git a/src/screens/ManageTag/ManageTagMockComponents/MockAddPeopleToTag.tsx b/src/screens/ManageTag/ManageTagMockComponents/MockAddPeopleToTag.tsx
new file mode 100644
index 0000000000..7e62c47f86
--- /dev/null
+++ b/src/screens/ManageTag/ManageTagMockComponents/MockAddPeopleToTag.tsx
@@ -0,0 +1,42 @@
+import React from 'react';
+import type { InterfaceAddPeopleToTagProps } from '../../../components/AddPeopleToTag/AddPeopleToTag';
+
+/**
+ * Component that mocks the AddPeopleToTag component for the Manage Tag screen.
+ */
+
+const TEST_IDS = {
+ MODAL: 'addPeopleToTagModal',
+ CLOSE_BUTTON: 'closeAddPeopleToTagModal',
+} as const;
+const MockAddPeopleToTag: React.FC
= ({
+ addPeopleToTagModalIsOpen,
+ hideAddPeopleToTagModal,
+}) => {
+ return (
+ <>
+ {addPeopleToTagModalIsOpen && (
+
+
+ Add People to Tag
+
+
+
+ )}
+ >
+ );
+};
+
+export default MockAddPeopleToTag;
diff --git a/src/screens/ManageTag/ManageTagMockComponents/MockTagActions.tsx b/src/screens/ManageTag/ManageTagMockComponents/MockTagActions.tsx
new file mode 100644
index 0000000000..3d2d6cc880
--- /dev/null
+++ b/src/screens/ManageTag/ManageTagMockComponents/MockTagActions.tsx
@@ -0,0 +1,37 @@
+import React from 'react';
+import type { InterfaceTagActionsProps } from '../../../components/TagActions/TagActions';
+
+/**
+ * Component that mocks the TagActions component for the Manage Tag screen.
+ */
+
+const MockTagActions: React.FC = ({
+ tagActionsModalIsOpen,
+ hideTagActionsModal,
+}) => {
+ return (
+ <>
+ {tagActionsModalIsOpen && (
+
+
+ Tag Actions
+
+
+
+ )}
+ >
+ );
+};
+
+export default MockTagActions;
diff --git a/src/screens/ManageTag/ManageTagMocks.ts b/src/screens/ManageTag/ManageTagMocks.ts
index c42c4a9e5f..4e9c64badd 100644
--- a/src/screens/ManageTag/ManageTagMocks.ts
+++ b/src/screens/ManageTag/ManageTagMocks.ts
@@ -1,8 +1,13 @@
-import { UNASSIGN_USER_TAG } from 'GraphQl/Mutations/TagMutations';
+import {
+ REMOVE_USER_TAG,
+ UNASSIGN_USER_TAG,
+ UPDATE_USER_TAG,
+} from 'GraphQl/Mutations/TagMutations';
import {
USER_TAG_ANCESTORS,
USER_TAGS_ASSIGNED_MEMBERS,
} from 'GraphQl/Queries/userTagQueries';
+import { TAGS_QUERY_DATA_CHUNK_SIZE } from 'utils/organizationTagsUtils';
export const MOCKS = [
{
@@ -10,15 +15,12 @@ export const MOCKS = [
query: USER_TAGS_ASSIGNED_MEMBERS,
variables: {
id: '1',
- after: null,
- before: null,
- first: 5,
- last: null,
+ first: TAGS_QUERY_DATA_CHUNK_SIZE,
},
},
result: {
data: {
- getUserTag: {
+ getAssignedUsers: {
name: 'tag1',
usersAssignedTo: {
edges: [
@@ -62,36 +64,6 @@ export const MOCKS = [
},
cursor: '5',
},
- ],
- pageInfo: {
- startCursor: '1',
- endCursor: '5',
- hasNextPage: true,
- hasPreviousPage: false,
- },
- totalCount: 6,
- },
- },
- },
- },
- },
- {
- request: {
- query: USER_TAGS_ASSIGNED_MEMBERS,
- variables: {
- id: '1',
- after: '5',
- before: null,
- first: 5,
- last: null,
- },
- },
- result: {
- data: {
- getUserTag: {
- name: 'tag1',
- usersAssignedTo: {
- edges: [
{
node: {
_id: '6',
@@ -100,14 +72,46 @@ export const MOCKS = [
},
cursor: '6',
},
+ {
+ node: {
+ _id: '7',
+ firstName: 'member',
+ lastName: '7',
+ },
+ cursor: '7',
+ },
+ {
+ node: {
+ _id: '8',
+ firstName: 'member',
+ lastName: '8',
+ },
+ cursor: '8',
+ },
+ {
+ node: {
+ _id: '9',
+ firstName: 'member',
+ lastName: '9',
+ },
+ cursor: '9',
+ },
+ {
+ node: {
+ _id: '10',
+ firstName: 'member',
+ lastName: '10',
+ },
+ cursor: '10',
+ },
],
pageInfo: {
- startCursor: '6',
- endCursor: '6',
- hasNextPage: false,
- hasPreviousPage: true,
+ startCursor: '1',
+ endCursor: '10',
+ hasNextPage: true,
+ hasPreviousPage: false,
},
- totalCount: 6,
+ totalCount: 12,
},
},
},
@@ -118,66 +122,40 @@ export const MOCKS = [
query: USER_TAGS_ASSIGNED_MEMBERS,
variables: {
id: '1',
- after: null,
- before: '6',
- first: null,
- last: 5,
+ first: TAGS_QUERY_DATA_CHUNK_SIZE,
+ after: '10',
},
},
result: {
data: {
- getUserTag: {
+ getAssignedUsers: {
name: 'tag1',
usersAssignedTo: {
edges: [
{
node: {
- _id: '1',
- firstName: 'member',
- lastName: '1',
- },
- cursor: '1',
- },
- {
- node: {
- _id: '2',
- firstName: 'member',
- lastName: '2',
- },
- cursor: '2',
- },
- {
- node: {
- _id: '3',
- firstName: 'member',
- lastName: '3',
- },
- cursor: '3',
- },
- {
- node: {
- _id: '4',
+ _id: '11',
firstName: 'member',
- lastName: '4',
+ lastName: '11',
},
- cursor: '4',
+ cursor: '11',
},
{
node: {
- _id: '5',
+ _id: '12',
firstName: 'member',
- lastName: '5',
+ lastName: '12',
},
- cursor: '5',
+ cursor: '12',
},
],
pageInfo: {
- startCursor: '1',
- endCursor: '5',
- hasNextPage: true,
- hasPreviousPage: false,
+ startCursor: '11',
+ endCursor: '12',
+ hasNextPage: false,
+ hasPreviousPage: true,
},
- totalCount: 6,
+ totalCount: 12,
},
},
},
@@ -217,6 +195,37 @@ export const MOCKS = [
},
},
},
+ {
+ request: {
+ query: UPDATE_USER_TAG,
+ variables: {
+ tagId: '1',
+ name: 'tag 1 edited',
+ },
+ },
+ result: {
+ data: {
+ updateUserTag: {
+ _id: '1',
+ },
+ },
+ },
+ },
+ {
+ request: {
+ query: REMOVE_USER_TAG,
+ variables: {
+ id: '1',
+ },
+ },
+ result: {
+ data: {
+ removeUserTag: {
+ _id: '1',
+ },
+ },
+ },
+ },
];
export const MOCKS_ERROR_ASSIGNED_MEMBERS = [
@@ -225,10 +234,7 @@ export const MOCKS_ERROR_ASSIGNED_MEMBERS = [
query: USER_TAGS_ASSIGNED_MEMBERS,
variables: {
id: '1',
- after: null,
- before: null,
- first: 5,
- last: null,
+ first: TAGS_QUERY_DATA_CHUNK_SIZE,
},
},
error: new Error('Mock Graphql Error'),
@@ -254,25 +260,22 @@ export const MOCKS_ERROR_TAG_ANCESTORS = [
query: USER_TAGS_ASSIGNED_MEMBERS,
variables: {
id: '1',
- after: null,
- before: null,
- first: 5,
- last: null,
+ first: TAGS_QUERY_DATA_CHUNK_SIZE,
},
},
result: {
data: {
- getUserTag: {
+ getAssignedUsers: {
name: 'tag1',
usersAssignedTo: {
edges: [],
pageInfo: {
startCursor: '1',
- endCursor: '5',
- hasNextPage: true,
+ endCursor: '1',
+ hasNextPage: false,
hasPreviousPage: false,
},
- totalCount: 6,
+ totalCount: 1,
},
},
},
diff --git a/src/screens/ManageTag/RemoveUserTagModal.tsx b/src/screens/ManageTag/RemoveUserTagModal.tsx
new file mode 100644
index 0000000000..dc000f443c
--- /dev/null
+++ b/src/screens/ManageTag/RemoveUserTagModal.tsx
@@ -0,0 +1,72 @@
+import type { TFunction } from 'i18next';
+import React from 'react';
+import { Button, Modal } from 'react-bootstrap';
+
+/**
+ * Remove UserTag Modal component for the Manage Tag screen.
+ */
+
+export interface InterfaceRemoveUserTagModalProps {
+ removeUserTagModalIsOpen: boolean;
+ toggleRemoveUserTagModal: () => void;
+ handleRemoveUserTag: () => Promise;
+ t: TFunction<'translation', 'manageTag'>;
+ tCommon: TFunction<'common', undefined>;
+}
+
+const RemoveUserTagModal: React.FC = ({
+ removeUserTagModalIsOpen,
+ toggleRemoveUserTagModal,
+ handleRemoveUserTag,
+ t,
+ tCommon,
+}) => {
+ return (
+ <>
+
+
+
+ {t('removeUserTag')}
+
+
+
+ {t('removeUserTagMessage')}
+
+
+
+
+
+
+ >
+ );
+};
+
+export default RemoveUserTagModal;
diff --git a/src/screens/ManageTag/UnassignUserTagModal.tsx b/src/screens/ManageTag/UnassignUserTagModal.tsx
new file mode 100644
index 0000000000..46df2fa4ac
--- /dev/null
+++ b/src/screens/ManageTag/UnassignUserTagModal.tsx
@@ -0,0 +1,80 @@
+import type { TFunction } from 'i18next';
+import React from 'react';
+import { Button, Modal } from 'react-bootstrap';
+
+/**
+ * Unassign UserTag Modal component for the Manage Tag screen.
+ */
+
+export interface InterfaceUnassignUserTagModalProps {
+ unassignUserTagModalIsOpen: boolean;
+ toggleUnassignUserTagModal: () => void;
+ handleUnassignUserTag: () => Promise;
+ t: TFunction<'translation', 'manageTag'>;
+ tCommon: TFunction<'common', undefined>;
+}
+
+const UnassignUserTagModal: React.FC = ({
+ unassignUserTagModalIsOpen,
+ toggleUnassignUserTagModal,
+ handleUnassignUserTag,
+ t,
+ tCommon,
+}) => {
+ return (
+ <>
+
+
+
+ {t('unassignUserTag')}
+
+
+ {t('unassignUserTagMessage')}
+
+
+
+
+
+ >
+ );
+};
+
+export default UnassignUserTagModal;
diff --git a/src/screens/OrganizationTags/OrganizationTags.module.css b/src/screens/OrganizationTags/OrganizationTags.module.css
index 7251a79d0d..aa2e2abb40 100644
--- a/src/screens/OrganizationTags/OrganizationTags.module.css
+++ b/src/screens/OrganizationTags/OrganizationTags.module.css
@@ -139,3 +139,12 @@
color: var(--bs-gray);
cursor: pointer;
}
+
+.orgUserTagsScrollableDiv {
+ scrollbar-width: auto;
+ scrollbar-color: var(--bs-gray-400) var(--bs-white);
+
+ max-height: calc(100vh - 18rem);
+ overflow: auto;
+ position: sticky;
+}
diff --git a/src/screens/OrganizationTags/OrganizationTags.test.tsx b/src/screens/OrganizationTags/OrganizationTags.test.tsx
index 923a26d982..1ab94ce35c 100644
--- a/src/screens/OrganizationTags/OrganizationTags.test.tsx
+++ b/src/screens/OrganizationTags/OrganizationTags.test.tsx
@@ -4,6 +4,7 @@ import type { RenderResult } from '@testing-library/react';
import {
act,
cleanup,
+ fireEvent,
render,
screen,
waitFor,
@@ -59,11 +60,11 @@ const renderOrganizationTags = (link: ApolloLink): RenderResult => {
} />
}
/>
}
/>
@@ -103,7 +104,7 @@ describe('Organisation Tags Page', () => {
await wait();
await waitFor(() => {
- expect(queryByText(translations.create)).not.toBeInTheDocument();
+ expect(queryByText(translations.createTag)).not.toBeInTheDocument();
});
});
@@ -129,28 +130,6 @@ describe('Organisation Tags Page', () => {
);
});
- test('opens and closes the remove tag modal', async () => {
- renderOrganizationTags(link);
-
- await wait();
-
- await waitFor(() => {
- expect(screen.getAllByTestId('removeUserTagBtn')[0]).toBeInTheDocument();
- });
- userEvent.click(screen.getAllByTestId('removeUserTagBtn')[0]);
-
- await waitFor(() => {
- return expect(
- screen.findByTestId('removeUserTagModalCloseBtn'),
- ).resolves.toBeInTheDocument();
- });
- userEvent.click(screen.getByTestId('removeUserTagModalCloseBtn'));
-
- await waitForElementToBeRemoved(() =>
- screen.queryByTestId('removeUserTagModalCloseBtn'),
- );
- });
-
test('navigates to sub tags screen after clicking on a tag', async () => {
renderOrganizationTags(link);
@@ -181,27 +160,32 @@ describe('Organisation Tags Page', () => {
});
});
- test('paginates between different pages', async () => {
- renderOrganizationTags(link);
+ test('Fetches more tags with infinite scroll', async () => {
+ const { getByText } = renderOrganizationTags(link);
await wait();
await waitFor(() => {
- expect(screen.getByTestId('nextPagBtn')).toBeInTheDocument();
+ expect(getByText(translations.createTag)).toBeInTheDocument();
});
- userEvent.click(screen.getByTestId('nextPagBtn'));
- await waitFor(() => {
- expect(screen.getAllByTestId('tagName')[0]).toHaveTextContent('6');
- });
+ const orgUserTagsScrollableDiv = screen.getByTestId(
+ 'orgUserTagsScrollableDiv',
+ );
- await waitFor(() => {
- expect(screen.getByTestId('previousPageBtn')).toBeInTheDocument();
+ // Get the initial number of tags loaded
+ const initialTagsDataLength = screen.getAllByTestId('manageTagBtn').length;
+
+ // Set scroll position to the bottom
+ fireEvent.scroll(orgUserTagsScrollableDiv, {
+ target: { scrollY: orgUserTagsScrollableDiv.scrollHeight },
});
- userEvent.click(screen.getByTestId('previousPageBtn'));
await waitFor(() => {
- expect(screen.getAllByTestId('tagName')[0]).toHaveTextContent('1');
+ const finalTagsDataLength = screen.getAllByTestId('manageTagBtn').length;
+ expect(finalTagsDataLength).toBeGreaterThan(initialTagsDataLength);
+
+ expect(getByText(translations.createTag)).toBeInTheDocument();
});
});
@@ -217,30 +201,15 @@ describe('Organisation Tags Page', () => {
userEvent.type(
screen.getByPlaceholderText(translations.tagNamePlaceholder),
- '7',
+ 'userTag 12',
);
userEvent.click(screen.getByTestId('createTagSubmitBtn'));
await waitFor(() => {
- expect(toast.success).toBeCalledWith(translations.tagCreationSuccess);
- });
- });
-
- test('removes a user tag', async () => {
- renderOrganizationTags(link);
-
- await wait();
-
- await waitFor(() => {
- expect(screen.getAllByTestId('removeUserTagBtn')[0]).toBeInTheDocument();
- });
- userEvent.click(screen.getAllByTestId('removeUserTagBtn')[0]);
-
- userEvent.click(screen.getByTestId('removeUserTagSubmitBtn'));
-
- await waitFor(() => {
- expect(toast.success).toBeCalledWith(translations.tagRemovalSuccess);
+ expect(toast.success).toHaveBeenCalledWith(
+ translations.tagCreationSuccess,
+ );
});
});
});
diff --git a/src/screens/OrganizationTags/OrganizationTags.tsx b/src/screens/OrganizationTags/OrganizationTags.tsx
index e4bf0604e9..ce37528cc1 100644
--- a/src/screens/OrganizationTags/OrganizationTags.tsx
+++ b/src/screens/OrganizationTags/OrganizationTags.tsx
@@ -1,4 +1,4 @@
-import { useMutation, useQuery, type ApolloError } from '@apollo/client';
+import { useMutation, useQuery } from '@apollo/client';
import { Search, WarningAmberRounded } from '@mui/icons-material';
import SortIcon from '@mui/icons-material/Sort';
import Loader from 'components/Loader/Loader';
@@ -16,14 +16,17 @@ import { toast } from 'react-toastify';
import type { InterfaceQueryOrganizationUserTags } from 'utils/interfaces';
import styles from './OrganizationTags.module.css';
import { DataGrid } from '@mui/x-data-grid';
-import { dataGridStyle } from 'utils/organizationTagsUtils';
+import type { InterfaceOrganizationTagsQuery } from 'utils/organizationTagsUtils';
+import {
+ dataGridStyle,
+ TAGS_QUERY_DATA_CHUNK_SIZE,
+} from 'utils/organizationTagsUtils';
import type { GridCellParams, GridColDef } from '@mui/x-data-grid';
import { Stack } from '@mui/material';
import { ORGANIZATION_USER_TAGS_LIST } from 'GraphQl/Queries/OrganizationQueries';
-import {
- CREATE_USER_TAG,
- REMOVE_USER_TAG,
-} from 'GraphQl/Mutations/TagMutations';
+import { CREATE_USER_TAG } from 'GraphQl/Mutations/TagMutations';
+import InfiniteScroll from 'react-infinite-scroll-component';
+import InfiniteScrollLoader from 'components/InfiniteScrollLoader/InfiniteScrollLoader';
/**
* Component that renders the Organization Tags screen when the app navigates to '/orgtags/:orgId'.
@@ -42,17 +45,9 @@ function OrganizationTags(): JSX.Element {
const { orgId } = useParams();
const navigate = useNavigate();
- const [after, setAfter] = useState
(null);
- const [before, setBefore] = useState(null);
- const [first, setFirst] = useState(5);
- const [last, setLast] = useState(null);
- const [tagSerialNumber, setTagSerialNumber] = useState(0);
const [tagName, setTagName] = useState('');
- const [removeUserTagId, setRemoveUserTagId] = useState(null);
- const [removeTagModalIsOpen, setRemoveTagModalIsOpen] = useState(false);
-
const showCreateTagModal = (): void => {
setTagName('');
setCreateTagModalIsOpen(true);
@@ -67,23 +62,53 @@ function OrganizationTags(): JSX.Element {
loading: orgUserTagsLoading,
error: orgUserTagsError,
refetch: orgUserTagsRefetch,
- }: {
- data?: {
- organizations: InterfaceQueryOrganizationUserTags[];
- };
- loading: boolean;
- error?: ApolloError;
- refetch: () => void;
- } = useQuery(ORGANIZATION_USER_TAGS_LIST, {
+ fetchMore: orgUserTagsFetchMore,
+ }: InterfaceOrganizationTagsQuery = useQuery(ORGANIZATION_USER_TAGS_LIST, {
variables: {
id: orgId,
- after: after,
- before: before,
- first: first,
- last: last,
+ first: TAGS_QUERY_DATA_CHUNK_SIZE,
},
});
+ const loadMoreUserTags = (): void => {
+ orgUserTagsFetchMore({
+ variables: {
+ first: TAGS_QUERY_DATA_CHUNK_SIZE,
+ after:
+ orgUserTagsData?.organizations?.[0]?.userTags?.pageInfo?.endCursor ??
+ null,
+ },
+ updateQuery: (
+ prevResult: { organizations: InterfaceQueryOrganizationUserTags[] },
+ {
+ fetchMoreResult,
+ }: {
+ fetchMoreResult?: {
+ organizations: InterfaceQueryOrganizationUserTags[];
+ };
+ },
+ ) => {
+ if (!fetchMoreResult) return prevResult;
+
+ return {
+ organizations: [
+ {
+ ...prevResult.organizations[0],
+ userTags: {
+ ...prevResult.organizations[0].userTags,
+ edges: [
+ ...prevResult.organizations[0].userTags.edges,
+ ...fetchMoreResult.organizations[0].userTags.edges,
+ ],
+ pageInfo: fetchMoreResult.organizations[0].userTags.pageInfo,
+ },
+ },
+ ],
+ };
+ },
+ });
+ };
+
const [create, { loading: createUserTagLoading }] =
useMutation(CREATE_USER_TAG);
@@ -112,26 +137,6 @@ function OrganizationTags(): JSX.Element {
}
};
- const [removeUserTag] = useMutation(REMOVE_USER_TAG);
- const handleRemoveUserTag = async (): Promise => {
- try {
- await removeUserTag({
- variables: {
- id: removeUserTagId,
- },
- });
-
- orgUserTagsRefetch();
- toggleRemoveUserTagModal();
- toast.success(t('tagRemovalSuccess') as string);
- } catch (error: unknown) {
- /* istanbul ignore next */
- if (error instanceof Error) {
- toast.error(error.message);
- }
- }
- };
-
if (createUserTagLoading || orgUserTagsLoading) {
return ;
}
@@ -151,38 +156,18 @@ function OrganizationTags(): JSX.Element {
);
}
- const handleNextPage = (): void => {
- setAfter(orgUserTagsData?.organizations[0].userTags.pageInfo.endCursor);
- setBefore(null);
- setFirst(5);
- setLast(null);
- setTagSerialNumber(tagSerialNumber + 1);
- };
- const handlePreviousPage = (): void => {
- setBefore(orgUserTagsData?.organizations[0].userTags.pageInfo.startCursor);
- setAfter(null);
- setFirst(null);
- setLast(5);
- setTagSerialNumber(tagSerialNumber - 1);
- };
-
const userTagsList = orgUserTagsData?.organizations[0].userTags.edges.map(
(edge) => edge.node,
);
const redirectToManageTag = (tagId: string): void => {
- navigate(`/orgtags/${orgId}/managetag/${tagId}`);
+ navigate(`/orgtags/${orgId}/manageTag/${tagId}`);
};
const redirectToSubTags = (tagId: string): void => {
navigate(`/orgtags/${orgId}/subTags/${tagId}`);
};
- const toggleRemoveUserTagModal = (): void => {
- if (removeTagModalIsOpen) setRemoveUserTagId(null);
- setRemoveTagModalIsOpen(!removeTagModalIsOpen);
- };
-
const columns: GridColDef[] = [
{
field: 'id',
@@ -193,7 +178,7 @@ function OrganizationTags(): JSX.Element {
headerClassName: `${styles.tableHeader}`,
sortable: false,
renderCell: (params: GridCellParams) => {
- return {tagSerialNumber * 5 + params.row.id}
;
+ return {params.row.id}
;
},
},
{
@@ -230,7 +215,7 @@ function OrganizationTags(): JSX.Element {
return (
{params.row.childTags.totalCount}
@@ -250,7 +235,7 @@ function OrganizationTags(): JSX.Element {
return (
{params.row.usersAssignedTo.totalCount}
@@ -268,28 +253,14 @@ function OrganizationTags(): JSX.Element {
headerClassName: `${styles.tableHeader}`,
renderCell: (params: GridCellParams) => {
return (
-
-
-
-
-
+
);
},
},
@@ -351,8 +322,8 @@ function OrganizationTags(): JSX.Element {
-
-
+
+
@@ -361,61 +332,50 @@ function OrganizationTags(): JSX.Element {
{'Tags'}
-
row._id}
- slots={{
- noRowsOverlay: /* istanbul ignore next */ () => (
-
- {t('noTagsFound')}
-
- ),
- }}
- sx={dataGridStyle}
- getRowClassName={() => `${styles.rowBackground}`}
- autoHeight
- rowHeight={65}
- rows={userTagsList?.map((fund, index) => ({
- id: index + 1,
- ...fund,
- }))}
- 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}
+ />
+
+
@@ -471,43 +431,6 @@ function OrganizationTags(): JSX.Element {
-
- {/* Remove User Tag Modal */}
-
-
-
- {t('removeUserTag')}
-
-
- {t('removeUserTagMessage')}
-
-
-
-
-
>
);
}
diff --git a/src/screens/OrganizationTags/OrganizationTagsMocks.ts b/src/screens/OrganizationTags/OrganizationTagsMocks.ts
index 3700c66c46..a8e186b393 100644
--- a/src/screens/OrganizationTags/OrganizationTagsMocks.ts
+++ b/src/screens/OrganizationTags/OrganizationTagsMocks.ts
@@ -1,8 +1,6 @@
-import {
- CREATE_USER_TAG,
- REMOVE_USER_TAG,
-} from 'GraphQl/Mutations/TagMutations';
+import { CREATE_USER_TAG } from 'GraphQl/Mutations/TagMutations';
import { ORGANIZATION_USER_TAGS_LIST } from 'GraphQl/Queries/OrganizationQueries';
+import { TAGS_QUERY_DATA_CHUNK_SIZE } from 'utils/organizationTagsUtils';
export const MOCKS = [
{
@@ -10,10 +8,7 @@ export const MOCKS = [
query: ORGANIZATION_USER_TAGS_LIST,
variables: {
id: '123',
- after: null,
- before: null,
- first: 5,
- last: null,
+ first: TAGS_QUERY_DATA_CHUNK_SIZE,
},
},
result: {
@@ -30,7 +25,7 @@ export const MOCKS = [
totalCount: 5,
},
childTags: {
- totalCount: 5,
+ totalCount: 11,
},
},
cursor: '1',
@@ -87,154 +82,79 @@ export const MOCKS = [
},
cursor: '5',
},
- ],
- pageInfo: {
- startCursor: '1',
- endCursor: '5',
- hasNextPage: true,
- hasPreviousPage: false,
- },
- totalCount: 6,
- },
- },
- ],
- },
- },
- },
- {
- request: {
- query: ORGANIZATION_USER_TAGS_LIST,
- variables: {
- id: '123',
- after: '5',
- before: null,
- first: 5,
- last: null,
- },
- },
- result: {
- data: {
- organizations: [
- {
- userTags: {
- edges: [
{
node: {
_id: '6',
name: 'userTag 6',
usersAssignedTo: {
- totalCount: 0,
+ totalCount: 6,
},
childTags: {
- totalCount: 0,
+ totalCount: 6,
},
},
cursor: '6',
},
- ],
- pageInfo: {
- startCursor: '6',
- endCursor: '6',
- hasNextPage: false,
- hasPreviousPage: true,
- },
- totalCount: 6,
- },
- },
- ],
- },
- },
- },
- {
- request: {
- query: ORGANIZATION_USER_TAGS_LIST,
- variables: {
- id: '123',
- after: null,
- before: '6',
- first: null,
- last: 5,
- },
- },
- result: {
- data: {
- organizations: [
- {
- userTags: {
- edges: [
- {
- node: {
- _id: '1',
- name: 'userTag 1',
- usersAssignedTo: {
- totalCount: 5,
- },
- childTags: {
- totalCount: 5,
- },
- },
- cursor: '1',
- },
{
node: {
- _id: '2',
- name: 'userTag 2',
+ _id: '7',
+ name: 'userTag 7',
usersAssignedTo: {
- totalCount: 5,
+ totalCount: 7,
},
childTags: {
- totalCount: 0,
+ totalCount: 7,
},
},
- cursor: '2',
+ cursor: '7',
},
{
node: {
- _id: '3',
- name: 'userTag 3',
+ _id: '8',
+ name: 'userTag 8',
usersAssignedTo: {
- totalCount: 0,
+ totalCount: 8,
},
childTags: {
- totalCount: 5,
+ totalCount: 8,
},
},
- cursor: '3',
+ cursor: '8',
},
{
node: {
- _id: '4',
- name: 'userTag 4',
+ _id: '9',
+ name: 'userTag 9',
usersAssignedTo: {
- totalCount: 0,
+ totalCount: 9,
},
childTags: {
- totalCount: 0,
+ totalCount: 9,
},
},
- cursor: '4',
+ cursor: '9',
},
{
node: {
- _id: '5',
- name: 'userTag 5',
+ _id: '10',
+ name: 'userTag 10',
usersAssignedTo: {
- totalCount: 5,
+ totalCount: 10,
},
childTags: {
- totalCount: 5,
+ totalCount: 10,
},
},
- cursor: '5',
+ cursor: '10',
},
],
pageInfo: {
startCursor: '1',
- endCursor: '5',
+ endCursor: '10',
hasNextPage: true,
hasPreviousPage: false,
},
- totalCount: 6,
+ totalCount: 12,
},
},
],
@@ -243,31 +163,71 @@ export const MOCKS = [
},
{
request: {
- query: CREATE_USER_TAG,
+ query: ORGANIZATION_USER_TAGS_LIST,
variables: {
- name: '7',
- organizationId: '123',
+ id: '123',
+ first: TAGS_QUERY_DATA_CHUNK_SIZE,
+ after: '10',
},
},
result: {
data: {
- createUserTag: {
- _id: '7',
- },
+ organizations: [
+ {
+ userTags: {
+ edges: [
+ {
+ node: {
+ _id: '11',
+ name: 'userTag 11',
+ usersAssignedTo: {
+ totalCount: 5,
+ },
+ childTags: {
+ totalCount: 5,
+ },
+ },
+ cursor: '11',
+ },
+ {
+ node: {
+ _id: '12',
+ name: 'userTag 12',
+ usersAssignedTo: {
+ totalCount: 5,
+ },
+ childTags: {
+ totalCount: 0,
+ },
+ },
+ cursor: '12',
+ },
+ ],
+ pageInfo: {
+ startCursor: '11',
+ endCursor: '12',
+ hasNextPage: false,
+ hasPreviousPage: true,
+ },
+ totalCount: 12,
+ },
+ },
+ ],
},
},
},
{
request: {
- query: REMOVE_USER_TAG,
+ query: CREATE_USER_TAG,
variables: {
- id: '1',
+ name: 'userTag 12',
+ organizationId: '123',
},
},
result: {
data: {
- removeUserTag: {
- _id: '1',
+ createUserTag: {
+ _id: '12',
},
},
},
@@ -280,10 +240,7 @@ export const MOCKS_ERROR = [
query: ORGANIZATION_USER_TAGS_LIST,
variables: {
id: '123',
- after: null,
- before: null,
- first: 5,
- last: null,
+ first: TAGS_QUERY_DATA_CHUNK_SIZE,
},
},
error: new Error('Mock Graphql Error'),
diff --git a/src/screens/SubTags/SubTags.module.css b/src/screens/SubTags/SubTags.module.css
index 2fed58ec52..0a210bdfa4 100644
--- a/src/screens/SubTags/SubTags.module.css
+++ b/src/screens/SubTags/SubTags.module.css
@@ -135,3 +135,11 @@
font-weight: 600;
text-decoration: underline;
}
+
+.subTagsScrollableDiv {
+ scrollbar-width: auto;
+ scrollbar-color: var(--bs-gray-400) var(--bs-white);
+
+ max-height: calc(100vh - 18rem);
+ overflow: auto;
+}
diff --git a/src/screens/SubTags/SubTags.test.tsx b/src/screens/SubTags/SubTags.test.tsx
index 1780027639..9cd778b858 100644
--- a/src/screens/SubTags/SubTags.test.tsx
+++ b/src/screens/SubTags/SubTags.test.tsx
@@ -4,6 +4,7 @@ import type { RenderResult } from '@testing-library/react';
import {
act,
cleanup,
+ fireEvent,
render,
screen,
waitFor,
@@ -24,7 +25,7 @@ import {
MOCKS_ERROR_SUB_TAGS,
MOCKS_ERROR_TAG_ANCESTORS,
} from './SubTagsMocks';
-import { InMemoryCache, type ApolloLink } from '@apollo/client';
+import { type ApolloLink } from '@apollo/client';
const translations = {
...JSON.parse(
@@ -55,25 +56,25 @@ jest.mock('react-toastify', () => ({
},
}));
-const cache = new InMemoryCache({
- typePolicies: {
- Query: {
- fields: {
- getUserTag: {
- keyArgs: false,
- merge(existing = {}, incoming) {
- return incoming;
- },
- },
- },
- },
- },
-});
+// const cache = new InMemoryCache({
+// typePolicies: {
+// Query: {
+// fields: {
+// getUserTag: {
+// keyArgs: false,
+// merge(_, incoming) {
+// return incoming;
+// },
+// },
+// },
+// },
+// },
+// });
const renderSubTags = (link: ApolloLink): RenderResult => {
return render(
-
-
+
+
@@ -82,11 +83,11 @@ const renderSubTags = (link: ApolloLink): RenderResult => {
element={}
/>
}
/>