mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-15 04:13:47 +00:00
feat(projects): allow sorting project table
This commit is contained in:
committed by
Carlos Valente
parent
9974ce24cd
commit
70ce1d5553
@@ -1,6 +1,6 @@
|
||||
import { useMemo } from 'react';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { ProjectFileListResponse } from 'ontime-types';
|
||||
import { ProjectFile, ProjectFileList, ProjectFileListResponse } from 'ontime-types';
|
||||
|
||||
import { queryRefetchIntervalSlow } from '../../ontimeConfig';
|
||||
import { PROJECT_LIST } from '../api/constants';
|
||||
@@ -24,22 +24,33 @@ function useProjectList() {
|
||||
return { data: data ?? placeholderProjectList, status, refetch };
|
||||
}
|
||||
|
||||
export function useOrderedProjectList() {
|
||||
export type ProjectSortMode = 'alphabetical-asc' | 'alphabetical-desc' | 'modified-asc' | 'modified-desc';
|
||||
type SortComparator = (a: ProjectFile, b: ProjectFile) => number;
|
||||
const sortComparators: Record<ProjectSortMode, SortComparator> = {
|
||||
'alphabetical-asc': (a, b) => a.filename.localeCompare(b.filename),
|
||||
'alphabetical-desc': (a, b) => b.filename.localeCompare(a.filename),
|
||||
'modified-asc': (a, b) => new Date(a.updatedAt).getTime() - new Date(b.updatedAt).getTime(),
|
||||
'modified-desc': (a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime(),
|
||||
};
|
||||
|
||||
export function useOrderedProjectList(sort: ProjectSortMode = 'modified-desc') {
|
||||
const response = useProjectList();
|
||||
const { files, lastLoadedProject } = response.data;
|
||||
|
||||
const reorderedProjectFiles = useMemo(() => {
|
||||
const reorderedProjectFiles: ProjectFileList = useMemo(() => {
|
||||
if (!files.length) return [];
|
||||
|
||||
const currentlyLoadedIndex = files.findIndex((project) => project.filename === lastLoadedProject);
|
||||
const sorted = [...files].sort(sortComparators[sort]);
|
||||
|
||||
if (currentlyLoadedIndex === -1) return files;
|
||||
// keep loaded always on top
|
||||
const currentlyLoadedIndex = sorted.findIndex((project) => project.filename === lastLoadedProject);
|
||||
if (currentlyLoadedIndex > 0) {
|
||||
const [loaded] = sorted.splice(currentlyLoadedIndex, 1);
|
||||
sorted.unshift(loaded);
|
||||
}
|
||||
|
||||
const projectFiles = [...files];
|
||||
const current = projectFiles.splice(currentlyLoadedIndex, 1)[0];
|
||||
|
||||
return [current, ...projectFiles];
|
||||
}, [files, lastLoadedProject]);
|
||||
return sorted;
|
||||
}, [files, lastLoadedProject, sort]);
|
||||
|
||||
return { ...response, data: { reorderedProjectFiles, lastLoadedProject: response.data.lastLoadedProject } };
|
||||
}
|
||||
|
||||
@@ -1,18 +1,22 @@
|
||||
import { useState } from 'react';
|
||||
import { IoArrowDown, IoArrowUp } from 'react-icons/io5';
|
||||
|
||||
import Info from '../../../../common/components/info/Info';
|
||||
import { useOrderedProjectList } from '../../../../common/hooks-query/useProjectList';
|
||||
import { ProjectSortMode, useOrderedProjectList } from '../../../../common/hooks-query/useProjectList';
|
||||
import * as Panel from '../../panel-utils/PanelUtils';
|
||||
|
||||
import ProjectListItem, { EditMode } from './ProjectListItem';
|
||||
|
||||
import style from './ProjectPanel.module.scss';
|
||||
|
||||
export default function ProjectList() {
|
||||
const { data, refetch, status } = useOrderedProjectList();
|
||||
type SortParameter = 'alphabetical' | 'modified';
|
||||
|
||||
export default function ProjectList() {
|
||||
const [editingMode, setEditingMode] = useState<EditMode | null>(null);
|
||||
const [editingFilename, setEditingFilename] = useState<string | null>(null);
|
||||
const [sortMode, setSortMode] = useState<ProjectSortMode>('modified-desc');
|
||||
|
||||
const { data, refetch, status } = useOrderedProjectList(sortMode);
|
||||
|
||||
const handleToggleEditMode = (editMode: EditMode, filename: string | null) => {
|
||||
setEditingMode((prev) => (prev === editMode && filename === editingFilename ? null : editMode));
|
||||
@@ -28,6 +32,13 @@ export default function ProjectList() {
|
||||
await refetch();
|
||||
};
|
||||
|
||||
const handleSort = (sortParameter: SortParameter) => {
|
||||
setSortMode((current) => {
|
||||
const isAscending = current === `${sortParameter}-asc`;
|
||||
return `${sortParameter}-${isAscending ? 'desc' : 'asc'}` as ProjectSortMode;
|
||||
});
|
||||
};
|
||||
|
||||
if (status === 'pending') {
|
||||
return (
|
||||
<div className={style.empty}>
|
||||
@@ -48,8 +59,18 @@ export default function ProjectList() {
|
||||
<Panel.Table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th className={style.containCell}>File Name</th>
|
||||
<th>Last Used</th>
|
||||
<th className={style.containCell} onClick={() => handleSort('alphabetical')}>
|
||||
<span className={style.sortableHeader}>
|
||||
File Name
|
||||
<SortIcon sortMode={sortMode} type='alphabetical' />
|
||||
</span>
|
||||
</th>
|
||||
<th onClick={() => handleSort('modified')}>
|
||||
<span className={style.sortableHeader}>
|
||||
Last Used
|
||||
<SortIcon sortMode={sortMode} type='modified' />
|
||||
</span>
|
||||
</th>
|
||||
<th />
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -72,3 +93,10 @@ export default function ProjectList() {
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function SortIcon({ sortMode, type }: { sortMode: ProjectSortMode; type: SortParameter }) {
|
||||
const prefix = `${type}-`;
|
||||
if (sortMode === `${prefix}asc`) return <IoArrowDown />;
|
||||
if (sortMode === `${prefix}desc`) return <IoArrowUp />;
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,13 @@
|
||||
}
|
||||
|
||||
.containCell {
|
||||
max-width: 400px;
|
||||
max-width: 50%;
|
||||
}
|
||||
|
||||
.sortableHeader {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5em;
|
||||
}
|
||||
|
||||
.fullWidth {
|
||||
|
||||
Reference in New Issue
Block a user