diff --git a/src/pages/pegase/home/components/StudiesPagination.tsx b/src/pages/pegase/home/components/StudiesPagination.tsx index 91938ca..750dfe3 100644 --- a/src/pages/pegase/home/components/StudiesPagination.tsx +++ b/src/pages/pegase/home/components/StudiesPagination.tsx @@ -12,7 +12,7 @@ type StudiesPaginationProps = StdTablePaginationProps; const StudiesPagination = ({ count, intervalSize, current, onChange }: StudiesPaginationProps) => { return ( -
+
); diff --git a/src/pages/pegase/home/components/StudyTableDisplay.tsx b/src/pages/pegase/home/components/StudyTableDisplay.tsx index cf7e054..29c1419 100644 --- a/src/pages/pegase/home/components/StudyTableDisplay.tsx +++ b/src/pages/pegase/home/components/StudyTableDisplay.tsx @@ -3,155 +3,107 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -import StdAvatar from '@/components/common/layout/stdAvatar/StdAvatar'; import StdSimpleTable from '@/components/common/data/stdSimpleTable/StdSimpleTable'; -import { createColumnHelper } from '@tanstack/react-table'; import { useState } from 'react'; -import { useTranslation } from 'react-i18next'; import { StudyDTO } from '@/shared/types/index'; -import { StdIconId } from '@/shared/utils/common/mappings/iconMaps'; -import StdIcon from '@common/base/stdIcon/StdIcon'; +import getStudyTableHeaders from './StudyTableHeaders'; +import { addSortColumn } from './StudyTableUtils'; import StudiesPagination from './StudiesPagination'; -import StdTagList from '@common/base/StdTagList/StdTagList'; -import StdRadioButton from '@/components/common/forms/stdRadioButton/StdRadioButton'; +import { RowSelectionState } from '@tanstack/react-table'; +import StdButton from '@/components/common/base/stdButton/StdButton'; +import { StudyStatus } from '@/shared/types/common/StudyStatus.type'; import { useStudyTableDisplay } from './useStudyTableDisplay'; -const columnHelper = createColumnHelper(); - interface StudyTableDisplayProps { searchStudy: string | undefined; projectId?: string; } const StudyTableDisplay = ({ searchStudy, projectId }: StudyTableDisplayProps) => { - const { t } = useTranslation(); - const [sortBy, setSortBy] = useState<{ [key: string]: 'asc' | 'desc' }>({}); + const [sortByState, setSortByState] = useState<{ [key: string]: 'asc' | 'desc' }>({}); + const [rowSelection, setRowSelection] = useState({}); + const [sortedColumn, setSortedColumn] = useState('status'); + const [isHeaderHovered, setIsHeaderHovered] = useState(false); const handleSort = (column: string) => { - const newSortOrder = sortBy[column] === 'asc' ? 'desc' : 'asc'; - setSortBy({ [column]: newSortOrder }); + const newSortOrder = sortByState[column] === 'asc' ? 'desc' : 'asc'; + setSortByState({ [column]: newSortOrder }); setSortedColumn(column); }; - const [sortedColumn, setSortedColumn] = useState('status'); + const handleHeaderHover = (hovered: boolean) => { + setIsHeaderHovered(hovered); + }; - const headers = [ - columnHelper.display({ - id: 'radioColumn', - header: ({ table }) => ( - table.toggleAllRowsSelected()} - name="headerRadio" - /> - ), - cell: ({ row }) => ( -
e.stopPropagation()} - className={`${row.getIsSelected() ? 'block' : 'hidden group-hover:block'}`} - > - -
- ), - }), + const headers = getStudyTableHeaders(); + console.log('Original Headers:', headers); - columnHelper.accessor('name', { - header: t('home.@study_name'), - cell: ({ getValue, row }) => { - const status = row.original.status; - const textClass = status === 'GENERATED' ? 'text-primary-900' : 'group-hover:text-green-500'; + const sortedHeaders = addSortColumn( + headers, + handleSort, + sortByState, + sortedColumn, + handleHeaderHover, + isHeaderHovered, + ); - return {getValue()}; - }, - }), + console.log('Sorted Headers:', sortedHeaders); - columnHelper.accessor('createdBy', { - header: t('home.@user_name'), - cell: ({ getValue }: { getValue: () => string }) => ( - - ), - }), - columnHelper.accessor('project', { header: t('home.@project') }), - columnHelper.accessor('status', { header: t('home.@status') }), - columnHelper.accessor('horizon', { header: t('home.@horizon') }), - columnHelper.accessor('keywords', { - header: 'keywords', - minSize: 500, - size: 500, - cell: ({ getValue, row }) => ( -
- -
- ), - }), - columnHelper.accessor('creationDate', { header: t('home.@creation_date') }), - ]; + const { rows, count, intervalSize, current, setPage } = useStudyTableDisplay({ + searchStudy, + projectId, + sortBy: sortByState, + }); - const [isHeaderHovered, setIsHeaderHovered] = useState(false); + const selectedRowId = Object.keys(rowSelection)[0]; - const handleHeaderHover = (hovered: boolean) => { - setIsHeaderHovered(hovered); - }; + const selectedStatus = rows[Number.parseInt(selectedRowId || '-1')]?.status?.toUpperCase(); - function addSortColumn(headers: any[]) { - return headers.map((column) => { - const isSortable = column.accessorKey !== 'keywords' && column.id !== 'radioColumn'; - return { - ...column, - header: ( -
isSortable && handleHeaderHover(true)} - onMouseLeave={() => isSortable && handleHeaderHover(false)} - onClick={() => { - if (isSortable) { - handleHeaderHover(false); - handleSort(column.accessorKey as string); - } - }} - > -
{column.header}
- {isSortable && ( -
- {sortBy[column.accessorKey as string] && sortedColumn === column.accessorKey ? ( - sortBy[column.accessorKey as string] === 'asc' ? ( - - - - ) : ( - - - - ) - ) : ( - - - - )} -
- )} -
- ), - }; - }); - } - const { rows, count, intervalSize, current, setPage } = useStudyTableDisplay({ searchStudy, projectId, sortBy }); + const isDuplicateActive = selectedStatus === StudyStatus.GENERATED; + const isDeleteActive = selectedStatus === StudyStatus.ERROR || selectedStatus === StudyStatus.IN_PROGRESS; return (
- + RowSelectionState), + ) => { + if (typeof updaterOrValue === 'function') { + setRowSelection((prev: RowSelectionState) => updaterOrValue(prev)); + } else { + setRowSelection(updaterOrValue); + } + }} + />
-
+
+
+ {selectedRowId !== undefined ? ( + <> + console.log('duplicate')} + variant="outlined" + disabled={!isDuplicateActive} + /> + console.log('Delete')} + variant="outlined" + color="danger" + disabled={!isDeleteActive} + /> + + ) : ( + console.log('NewStudy')} /> + )} +
diff --git a/src/pages/pegase/home/components/StudyTableHeaders.tsx b/src/pages/pegase/home/components/StudyTableHeaders.tsx new file mode 100644 index 0000000..69c0db3 --- /dev/null +++ b/src/pages/pegase/home/components/StudyTableHeaders.tsx @@ -0,0 +1,81 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +import StdTagList from '@/components/common/base/StdTagList/StdTagList'; +import StdRadioButton from '@/components/common/forms/stdRadioButton/StdRadioButton'; +import StdAvatar from '@/components/common/layout/stdAvatar/StdAvatar'; +import { StudyStatus } from '@/shared/types/common/StudyStatus.type'; +import { StudyDTO } from '@/shared/types/pegase/study'; +import { createColumnHelper } from '@tanstack/react-table'; +import { useTranslation } from 'react-i18next'; + +const columnHelper = createColumnHelper(); + +const getStudyTableHeaders = () => { + const { t } = useTranslation(); + return [ + columnHelper.display({ + id: 'radioColumn', + header: () => <>, + cell: ({ row }) => ( +
+ +
+ ), + }), + + columnHelper.accessor('name', { + header: t('home.@study_name'), + cell: ({ getValue, row }) => { + const status = row.original.status; + const textClass = status === StudyStatus.GENERATED ? 'text-primary-900' : 'group-hover:text-green-500'; + return {getValue()}; + }, + }), + + columnHelper.accessor('createdBy', { + header: t('home.@user_name'), + cell: ({ getValue }) => ( + + ), + }), + + columnHelper.accessor('project', { + header: t('home.@project'), + }), + + columnHelper.accessor('status', { + header: t('home.@status'), + }), + + columnHelper.accessor('horizon', { + header: t('home.@horizon'), + }), + + columnHelper.accessor('keywords', { + header: t('home.@keywords'), + minSize: 500, + size: 500, + cell: ({ getValue, row }) => ( +
+ +
+ ), + }), + + columnHelper.accessor('creationDate', { + header: t('home.@creation_date'), + }), + ]; +}; + +export default getStudyTableHeaders; diff --git a/src/pages/pegase/home/components/StudyTableUtils.tsx b/src/pages/pegase/home/components/StudyTableUtils.tsx new file mode 100644 index 0000000..928f6d9 --- /dev/null +++ b/src/pages/pegase/home/components/StudyTableUtils.tsx @@ -0,0 +1,62 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +import StdIcon from '@/components/common/base/stdIcon/StdIcon'; +import { StdIconId } from '@/shared/utils/common/mappings/iconMaps'; + +export function addSortColumn( + headers: any[], + handleSort: (column: string) => void, + sortBy: { [key: string]: 'asc' | 'desc' }, + sortedColumn: string | null, + handleHeaderHover: (hovered: boolean) => void, + isHeaderHovered: boolean, +) { + return headers.map((column) => { + const isSortable = column.accessorKey !== 'keywords' && column.id !== 'radioColumn'; + return { + ...column, + header: ( +
isSortable && handleHeaderHover(true)} + onMouseLeave={() => isSortable && handleHeaderHover(false)} + onClick={() => { + if (isSortable) { + handleHeaderHover(false); + handleSort(column.accessorKey as string); + } + }} + > +
{column.header}
+ {isSortable && ( +
+ {sortBy[column.accessorKey as string] && sortedColumn === column.accessorKey ? ( + sortBy[column.accessorKey as string] === 'asc' ? ( + + + + ) : ( + + + + ) + ) : ( + + + + )} +
+ )} +
+ ), + }; + }); +} diff --git a/src/shared/types/common/StudyStatus.type.ts b/src/shared/types/common/StudyStatus.type.ts new file mode 100644 index 0000000..09d7d6d --- /dev/null +++ b/src/shared/types/common/StudyStatus.type.ts @@ -0,0 +1,13 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +export enum StudyStatus { + IN_PROGRESS = 'IN_PROGRESS', + GENERATED = 'GENERATED', + ERROR = 'ERROR', + CLOSED = 'CLOSED', + DELETED = 'DELETED', +} diff --git a/vite.config.js b/vite.config.js index 3160a3f..e7a3899 100644 --- a/vite.config.js +++ b/vite.config.js @@ -32,6 +32,11 @@ export default defineConfig({ globals: true, environment: 'jsdom', setupFiles: './src/testSetup.ts', + coverage: { + provider: 'v8', + reporter: ['lcov', 'text'], + exclude: ['src/*.test.ts', 'src/shared/**', 'src/components/common/**'], + }, }, server: { port: DEFAULT_PORT,