Skip to content

Commit

Permalink
Merge pull request #24 from AntaresSimulatorTeam/feature/homepage_act…
Browse files Browse the repository at this point in the history
…ion_buttons

[FEATURE] Homepage buttons for studies actiosn added
  • Loading branch information
vargastat authored Dec 18, 2024
2 parents a0fcd6b + b78ee14 commit 4326932
Show file tree
Hide file tree
Showing 6 changed files with 235 additions and 122 deletions.
2 changes: 1 addition & 1 deletion src/pages/pegase/home/components/StudiesPagination.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ type StudiesPaginationProps = StdTablePaginationProps;

const StudiesPagination = ({ count, intervalSize, current, onChange }: StudiesPaginationProps) => {
return (
<div className="flex h-9 flex-[1_0_0] items-center justify-end px-4 py-3">
<div className="flex h-9 shrink-0 grow basis-0 items-center justify-end px-4 py-3">
<StdTablePagination count={count} intervalSize={intervalSize} current={current} onChange={onChange} />
</div>
);
Expand Down
194 changes: 73 additions & 121 deletions src/pages/pegase/home/components/StudyTableDisplay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<StudyDTO>();

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<RowSelectionState>({});
const [sortedColumn, setSortedColumn] = useState<string | null>('status');
const [isHeaderHovered, setIsHeaderHovered] = useState<boolean>(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<string | null>('status');
const handleHeaderHover = (hovered: boolean) => {
setIsHeaderHovered(hovered);
};

const headers = [
columnHelper.display({
id: 'radioColumn',
header: ({ table }) => (
<StdRadioButton
value="headerRadio"
label="Select All"
checked={table.getIsAllRowsSelected()}
onChange={() => table.toggleAllRowsSelected()}
name="headerRadio"
/>
),
cell: ({ row }) => (
<div
onClick={(e) => e.stopPropagation()}
className={`${row.getIsSelected() ? 'block' : 'hidden group-hover:block'}`}
>
<StdRadioButton
value={row.original.id.toString()}
label=""
disabled={!row.getCanSelect()}
checked={row.getIsSelected()}
name={`radio-${row.original.id}`}
/>
</div>
),
}),
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 <span className={`transition-colors ${textClass}`}>{getValue()}</span>;
},
}),
console.log('Sorted Headers:', sortedHeaders);

columnHelper.accessor('createdBy', {
header: t('home.@user_name'),
cell: ({ getValue }: { getValue: () => string }) => (
<StdAvatar size="s" backgroundColor="gray" fullname={getValue()} initials={getValue().substring(0, 2)} />
),
}),
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 }) => (
<div className="flex h-3 w-32">
<StdTagList id={`pegase-tags-${row.id}`} tags={getValue()} />
</div>
),
}),
columnHelper.accessor('creationDate', { header: t('home.@creation_date') }),
];
const { rows, count, intervalSize, current, setPage } = useStudyTableDisplay({
searchStudy,
projectId,
sortBy: sortByState,
});

const [isHeaderHovered, setIsHeaderHovered] = useState<boolean>(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: (
<div
className={`flex items-center ${isSortable ? 'cursor-pointer' : ''} header-container group`}
onMouseEnter={() => isSortable && handleHeaderHover(true)}
onMouseLeave={() => isSortable && handleHeaderHover(false)}
onClick={() => {
if (isSortable) {
handleHeaderHover(false);
handleSort(column.accessorKey as string);
}
}}
>
<div>{column.header}</div>
{isSortable && (
<div>
{sortBy[column.accessorKey as string] && sortedColumn === column.accessorKey ? (
sortBy[column.accessorKey as string] === 'asc' ? (
<span className="font-bold text-primary-600">
<StdIcon name={StdIconId.ArrowUpwardAlt} />
</span>
) : (
<span className="font-bold text-primary-600">
<StdIcon name={StdIconId.ArrowDownwardAlt} />
</span>
)
) : (
<span
className={`text-primary-900 ${isHeaderHovered ? 'opacity-100' : 'opacity-0'} transition-opacity duration-100`}
>
<StdIcon name={StdIconId.ArrowUpwardAlt} />
</span>
)}
</div>
)}
</div>
),
};
});
}
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 (
<div>
<div className="flex-1">
<StdSimpleTable columns={addSortColumn(headers)} data={rows as StudyDTO[]} enableRowSelection={true} />
<StdSimpleTable
columns={sortedHeaders}
data={rows as StudyDTO[]}
enableRowSelection={true}
state={{
rowSelection,
}}
onRowSelectionChange={(
updaterOrValue: RowSelectionState | ((oldState: RowSelectionState) => RowSelectionState),
) => {
if (typeof updaterOrValue === 'function') {
setRowSelection((prev: RowSelectionState) => updaterOrValue(prev));
} else {
setRowSelection(updaterOrValue);
}
}}
/>
</div>
<div className="flex h-[60px] items-center justify-between bg-gray-200 px-[32px]">
<div className="flex h-8 items-center justify-between bg-gray-200 px-4">
<div className="flex gap-2">
{selectedRowId !== undefined ? (
<>
<StdButton
label="Duplicate"
onClick={() => console.log('duplicate')}
variant="outlined"
disabled={!isDuplicateActive}
/>
<StdButton
label="Delete"
onClick={() => console.log('Delete')}
variant="outlined"
color="danger"
disabled={!isDeleteActive}
/>
</>
) : (
<StdButton label="NewStudy" onClick={() => console.log('NewStudy')} />
)}
</div>
<StudiesPagination count={count} intervalSize={intervalSize} current={current} onChange={setPage} />
</div>
</div>
Expand Down
81 changes: 81 additions & 0 deletions src/pages/pegase/home/components/StudyTableHeaders.tsx
Original file line number Diff line number Diff line change
@@ -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<StudyDTO>();

const getStudyTableHeaders = () => {
const { t } = useTranslation();
return [
columnHelper.display({
id: 'radioColumn',
header: () => <></>,
cell: ({ row }) => (
<div className={`${row.getIsSelected() ? 'block' : 'hidden group-hover:block'}`}>
<StdRadioButton
value={row.original.id.toString()}
label=""
disabled={!row.getCanSelect()}
checked={row.getIsSelected()}
name={`radio-${row.original.id}`}
/>
</div>
),
}),

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 <span className={`transition-colors ${textClass}`}>{getValue()}</span>;
},
}),

columnHelper.accessor('createdBy', {
header: t('home.@user_name'),
cell: ({ getValue }) => (
<StdAvatar size="s" backgroundColor="gray" fullname={getValue()} initials={getValue().substring(0, 2)} />
),
}),

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 }) => (
<div className="flex h-3 w-32">
<StdTagList id={`pegase-tags-${row.id}`} tags={getValue()} />
</div>
),
}),

columnHelper.accessor('creationDate', {
header: t('home.@creation_date'),
}),
];
};

export default getStudyTableHeaders;
62 changes: 62 additions & 0 deletions src/pages/pegase/home/components/StudyTableUtils.tsx
Original file line number Diff line number Diff line change
@@ -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: (
<div
className={`flex items-center ${isSortable ? 'cursor-pointer' : ''} header-container group`}
onMouseEnter={() => isSortable && handleHeaderHover(true)}
onMouseLeave={() => isSortable && handleHeaderHover(false)}
onClick={() => {
if (isSortable) {
handleHeaderHover(false);
handleSort(column.accessorKey as string);
}
}}
>
<div>{column.header}</div>
{isSortable && (
<div>
{sortBy[column.accessorKey as string] && sortedColumn === column.accessorKey ? (
sortBy[column.accessorKey as string] === 'asc' ? (
<span className="font-bold text-primary-600">
<StdIcon name={StdIconId.ArrowUpwardAlt} />
</span>
) : (
<span className="font-bold text-primary-600">
<StdIcon name={StdIconId.ArrowDownwardAlt} />
</span>
)
) : (
<span
className={`text-primary-900 ${
isHeaderHovered ? 'opacity-100' : 'opacity-0'
} transition-opacity duration-100`}
>
<StdIcon name={StdIconId.ArrowUpwardAlt} />
</span>
)}
</div>
)}
</div>
),
};
});
}
13 changes: 13 additions & 0 deletions src/shared/types/common/StudyStatus.type.ts
Original file line number Diff line number Diff line change
@@ -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',
}
Loading

0 comments on commit 4326932

Please sign in to comment.