Loading src/components/jobs/JobList.tsx +5 −3 Original line number Diff line number Diff line Loading @@ -4,12 +4,12 @@ import { Job } from "../../models/Job.model"; import { formatDate } from "../../util/datetime"; import { JobListHeader } from "./list/JobListHeader"; import { ColumnHeader } from "../../models/dataGrid/columnHeader.model"; import { headers } from "./list/JobListColumns"; import { GridSizes, getGridSize } from "../../util/gridSizing"; import { FetchNextPageOptions } from "@tanstack/react-query"; import { Outlet, useNavigate } from "@tanstack/react-router"; import { Route as JobsRoute } from "../../routes/simulations.$simulationId.jobs"; import { computeJobState } from "../../util/jobs" import { SortDirection } from "../../models/filters/sortDetails.model"; function JobListColumn({ size, Loading @@ -34,21 +34,23 @@ function JobListColumn({ export function JobList({ jobs, columns, totalJobs, fetchNextPage, hasNextPage, onSort, }: { jobs: Job[]; columns: ColumnHeader[], totalJobs: number; fetchNextPage: (options?: FetchNextPageOptions | undefined) => void; hasNextPage: boolean; onSort: (header: string, sorted: boolean, direction: "asc" | "desc") => void; onSort: (columnName: string, direction: SortDirection) => void; }) { const navigate = useNavigate({ from: JobsRoute.fullPath }); const { simulationId } = JobsRoute.useParams(); const { currentTimestamp } = JobsRoute.useSearch(); const rows: (ColumnHeader[] | Job)[] = [headers, ...jobs]; const rows: (ColumnHeader[] | Job)[] = [columns, ...jobs]; const parentRef = useRef(null); Loading src/components/jobs/list/JobListColumns.ts +8 −8 Original line number Diff line number Diff line Loading @@ -19,7 +19,7 @@ export const headers: ColumnHeader[] = [ FilterOperators.MaxiumumLength, ], propertyName: "job_id", sort: { sortable: true, sorted: true, direction: "asc" }, sort: { sortable: true, direction: "asc" }, size: "small", }, { Loading @@ -27,7 +27,7 @@ export const headers: ColumnHeader[] = [ inputType: "text", name: "Name", propertyName: "name", sort: { sortable: true, sorted: false, direction: null }, sort: { sortable: true, direction: null }, operators: [ FilterOperators.Contains, FilterOperators.DoesNotContain, Loading @@ -48,7 +48,7 @@ export const headers: ColumnHeader[] = [ name: "State", operators: [], propertyName: "state_current", sort: { sortable: false, sorted: false, direction: null }, sort: { sortable: false, direction: null }, size: "small", filterable: false, }, Loading @@ -67,7 +67,7 @@ export const headers: ColumnHeader[] = [ FilterOperators.OneOf, FilterOperators.NotOneOf, ], sort: { sortable: true, sorted: false, direction: null }, sort: { sortable: true, direction: null }, size: "small", }, { Loading @@ -85,7 +85,7 @@ export const headers: ColumnHeader[] = [ FilterOperators.OneOf, FilterOperators.NotOneOf, ], sort: { sortable: true, sorted: false, direction: null }, sort: { sortable: true, direction: null }, size: "large", }, { Loading @@ -103,7 +103,7 @@ export const headers: ColumnHeader[] = [ FilterOperators.OneOf, FilterOperators.NotOneOf, ], sort: { sortable: true, sorted: false, direction: null }, sort: { sortable: true, direction: null }, size: "small", }, { Loading @@ -121,7 +121,7 @@ export const headers: ColumnHeader[] = [ FilterOperators.OneOf, FilterOperators.NotOneOf, ], sort: { sortable: true, sorted: false, direction: null }, sort: { sortable: true, direction: null }, size: "medium", }, { Loading @@ -139,7 +139,7 @@ export const headers: ColumnHeader[] = [ FilterOperators.OneOf, FilterOperators.NotOneOf, ], sort: { sortable: true, sorted: false, direction: null }, sort: { sortable: true, direction: null }, size: "medium", }, ]; src/components/jobs/list/JobListHeader.tsx +16 −11 Original line number Diff line number Diff line import { CSSProperties, ReactNode } from "react"; import { ColumnHeader } from "../../../models/dataGrid/columnHeader.model"; import { GridSizes, getGridSize } from "../../../util/gridSizing"; import { SortDirection } from "../../../models/filters/sortDetails.model"; import { ArrowLongDownIcon } from "@heroicons/react/24/outline"; function JobListHeaderCell({ Loading @@ -13,7 +14,7 @@ function JobListHeaderCell({ size: GridSizes; children: ReactNode; lastIndex: boolean; onSort: (header: string, sorted: boolean, direction: "asc" | "desc") => void; onSort: (columnName: string, direction: SortDirection) => void; column: ColumnHeader; }) { return ( Loading @@ -22,21 +23,25 @@ function JobListHeaderCell({ onClick={(e) => { e.preventDefault(); if (column.sort.sortable) { const direction = column.sort.sorted ? column.sort.direction === "asc" ? "desc" : "asc" : "asc"; onSort(column.name, column.sort.direction !== "desc", direction); let direction: SortDirection; // cycle between asc/desc/no-sort if (column.sort.direction == "asc") { direction = "desc" } else if (column.sort.direction == "desc") { direction = null; } else { direction = "asc"; } onSort(column.name, direction); } }} > {children} {column.sort.sortable && ( {column.sort.sortable && column.sort.direction ? ( <ArrowLongDownIcon className={`absolute right-2 h-4 w-4 bg-neutral-300 dark:bg-neutral-800 ${column.sort?.sorted && column.sort?.direction === "asc" && "rotate-180"} transition-opacity duration-300 ease-in-out group-hover:opacity-100 ${!column.sort?.sorted && "opacity-0"}`} className={`absolute right-2 h-4 w-4 bg-neutral-300 dark:bg-neutral-800 ${column.sort.direction === "desc" && "rotate-180"} transition-opacity duration-300 ease-in-out group-hover:opacity-100`} /> )} ) : ""} </button> ); } Loading @@ -44,7 +49,7 @@ function JobListHeaderCell({ interface JobListHeaderProps { headers: ColumnHeader[]; style: CSSProperties; onSort: (header: string, sorted: boolean, direction: "asc" | "desc") => void; onSort: (columnName: string, direction: SortDirection) => void; } export function JobListHeader({ headers, style, onSort }: JobListHeaderProps) { Loading src/components/simulations/list/SimulationsDataGrid.tsx +2 −5 Original line number Diff line number Diff line Loading @@ -7,6 +7,7 @@ import { FetchNextPageOptions } from "@tanstack/react-query"; import { useEffect, useRef } from "react"; import { defaultRangeExtractor, useVirtualizer } from "@tanstack/react-virtual"; import { ExclamationTriangleIcon } from "@heroicons/react/24/outline"; import { SortDirection } from "../../../models/filters/sortDetails.model"; export function SimulationsDataGrid({ columns, Loading @@ -20,11 +21,7 @@ export function SimulationsDataGrid({ total_results, }: { columns: ColumnHeader[]; onSort: ( columnName: string, sorted: boolean, direction: "asc" | "desc", ) => void; onSort: (columnName: string, direction: SortDirection) => void; rows: Simulation[]; isLoading: boolean; isError: boolean; Loading src/components/simulations/list/SimulationsDataGridHeader.tsx +16 −19 Original line number Diff line number Diff line import { ArrowLongDownIcon } from "@heroicons/react/16/solid"; import { ColumnHeader } from "../../../models/dataGrid/columnHeader.model"; import { CSSProperties } from "react"; import { SortDirection } from "../../../models/filters/sortDetails.model"; function SimulationsDataGridHeaderCell({ column, Loading @@ -8,11 +9,7 @@ function SimulationsDataGridHeaderCell({ index, }: { column: ColumnHeader; onSort: ( columnString: string, sorted: boolean, direction: "asc" | "desc", ) => void; onSort: (columnName: string, direction: SortDirection) => void; index: number; }) { return ( Loading @@ -21,21 +18,25 @@ function SimulationsDataGridHeaderCell({ onClick={(e) => { e.preventDefault(); if (column.sort.sortable) { const direction = column.sort.sorted ? column.sort.direction === "asc" ? "desc" : "asc" : "asc"; onSort(column.name, column.sort.direction !== "desc", direction); // cycle between asc/desc/no-sort let direction: SortDirection; if (column.sort.direction == "asc") { direction = "desc" } else if (column.sort.direction == "desc") { direction = null; } else { direction = "asc"; } onSort(column.name, direction); } }} > <span>{column.name}</span> {column.sort.sortable && ( {column.sort.sortable && column.sort.direction ? ( <ArrowLongDownIcon className={`absolute right-2 h-4 w-4 bg-neutral-300 dark:bg-neutral-800 ${column.sort?.sorted && column.sort?.direction === "asc" && "rotate-180"} transition-opacity duration-300 ease-in-out group-hover:opacity-100 ${!column.sort?.sorted && "opacity-0"}`} className={`absolute right-2 h-4 w-4 bg-neutral-300 dark:bg-neutral-800 ${column.sort.direction === "desc" && "rotate-180"} transition-opacity duration-300 ease-in-out group-hover:opacity-100`} /> )} ) : ""} </button> ); } Loading @@ -46,11 +47,7 @@ export function SimulationsDataGridHeader({ style, }: { columns: ColumnHeader[]; onSort: ( columnName: string, sorted: boolean, direction: "asc" | "desc", ) => void; onSort: (columnName: string, direction: SortDirection) => void; style: CSSProperties; }) { return ( Loading Loading
src/components/jobs/JobList.tsx +5 −3 Original line number Diff line number Diff line Loading @@ -4,12 +4,12 @@ import { Job } from "../../models/Job.model"; import { formatDate } from "../../util/datetime"; import { JobListHeader } from "./list/JobListHeader"; import { ColumnHeader } from "../../models/dataGrid/columnHeader.model"; import { headers } from "./list/JobListColumns"; import { GridSizes, getGridSize } from "../../util/gridSizing"; import { FetchNextPageOptions } from "@tanstack/react-query"; import { Outlet, useNavigate } from "@tanstack/react-router"; import { Route as JobsRoute } from "../../routes/simulations.$simulationId.jobs"; import { computeJobState } from "../../util/jobs" import { SortDirection } from "../../models/filters/sortDetails.model"; function JobListColumn({ size, Loading @@ -34,21 +34,23 @@ function JobListColumn({ export function JobList({ jobs, columns, totalJobs, fetchNextPage, hasNextPage, onSort, }: { jobs: Job[]; columns: ColumnHeader[], totalJobs: number; fetchNextPage: (options?: FetchNextPageOptions | undefined) => void; hasNextPage: boolean; onSort: (header: string, sorted: boolean, direction: "asc" | "desc") => void; onSort: (columnName: string, direction: SortDirection) => void; }) { const navigate = useNavigate({ from: JobsRoute.fullPath }); const { simulationId } = JobsRoute.useParams(); const { currentTimestamp } = JobsRoute.useSearch(); const rows: (ColumnHeader[] | Job)[] = [headers, ...jobs]; const rows: (ColumnHeader[] | Job)[] = [columns, ...jobs]; const parentRef = useRef(null); Loading
src/components/jobs/list/JobListColumns.ts +8 −8 Original line number Diff line number Diff line Loading @@ -19,7 +19,7 @@ export const headers: ColumnHeader[] = [ FilterOperators.MaxiumumLength, ], propertyName: "job_id", sort: { sortable: true, sorted: true, direction: "asc" }, sort: { sortable: true, direction: "asc" }, size: "small", }, { Loading @@ -27,7 +27,7 @@ export const headers: ColumnHeader[] = [ inputType: "text", name: "Name", propertyName: "name", sort: { sortable: true, sorted: false, direction: null }, sort: { sortable: true, direction: null }, operators: [ FilterOperators.Contains, FilterOperators.DoesNotContain, Loading @@ -48,7 +48,7 @@ export const headers: ColumnHeader[] = [ name: "State", operators: [], propertyName: "state_current", sort: { sortable: false, sorted: false, direction: null }, sort: { sortable: false, direction: null }, size: "small", filterable: false, }, Loading @@ -67,7 +67,7 @@ export const headers: ColumnHeader[] = [ FilterOperators.OneOf, FilterOperators.NotOneOf, ], sort: { sortable: true, sorted: false, direction: null }, sort: { sortable: true, direction: null }, size: "small", }, { Loading @@ -85,7 +85,7 @@ export const headers: ColumnHeader[] = [ FilterOperators.OneOf, FilterOperators.NotOneOf, ], sort: { sortable: true, sorted: false, direction: null }, sort: { sortable: true, direction: null }, size: "large", }, { Loading @@ -103,7 +103,7 @@ export const headers: ColumnHeader[] = [ FilterOperators.OneOf, FilterOperators.NotOneOf, ], sort: { sortable: true, sorted: false, direction: null }, sort: { sortable: true, direction: null }, size: "small", }, { Loading @@ -121,7 +121,7 @@ export const headers: ColumnHeader[] = [ FilterOperators.OneOf, FilterOperators.NotOneOf, ], sort: { sortable: true, sorted: false, direction: null }, sort: { sortable: true, direction: null }, size: "medium", }, { Loading @@ -139,7 +139,7 @@ export const headers: ColumnHeader[] = [ FilterOperators.OneOf, FilterOperators.NotOneOf, ], sort: { sortable: true, sorted: false, direction: null }, sort: { sortable: true, direction: null }, size: "medium", }, ];
src/components/jobs/list/JobListHeader.tsx +16 −11 Original line number Diff line number Diff line import { CSSProperties, ReactNode } from "react"; import { ColumnHeader } from "../../../models/dataGrid/columnHeader.model"; import { GridSizes, getGridSize } from "../../../util/gridSizing"; import { SortDirection } from "../../../models/filters/sortDetails.model"; import { ArrowLongDownIcon } from "@heroicons/react/24/outline"; function JobListHeaderCell({ Loading @@ -13,7 +14,7 @@ function JobListHeaderCell({ size: GridSizes; children: ReactNode; lastIndex: boolean; onSort: (header: string, sorted: boolean, direction: "asc" | "desc") => void; onSort: (columnName: string, direction: SortDirection) => void; column: ColumnHeader; }) { return ( Loading @@ -22,21 +23,25 @@ function JobListHeaderCell({ onClick={(e) => { e.preventDefault(); if (column.sort.sortable) { const direction = column.sort.sorted ? column.sort.direction === "asc" ? "desc" : "asc" : "asc"; onSort(column.name, column.sort.direction !== "desc", direction); let direction: SortDirection; // cycle between asc/desc/no-sort if (column.sort.direction == "asc") { direction = "desc" } else if (column.sort.direction == "desc") { direction = null; } else { direction = "asc"; } onSort(column.name, direction); } }} > {children} {column.sort.sortable && ( {column.sort.sortable && column.sort.direction ? ( <ArrowLongDownIcon className={`absolute right-2 h-4 w-4 bg-neutral-300 dark:bg-neutral-800 ${column.sort?.sorted && column.sort?.direction === "asc" && "rotate-180"} transition-opacity duration-300 ease-in-out group-hover:opacity-100 ${!column.sort?.sorted && "opacity-0"}`} className={`absolute right-2 h-4 w-4 bg-neutral-300 dark:bg-neutral-800 ${column.sort.direction === "desc" && "rotate-180"} transition-opacity duration-300 ease-in-out group-hover:opacity-100`} /> )} ) : ""} </button> ); } Loading @@ -44,7 +49,7 @@ function JobListHeaderCell({ interface JobListHeaderProps { headers: ColumnHeader[]; style: CSSProperties; onSort: (header: string, sorted: boolean, direction: "asc" | "desc") => void; onSort: (columnName: string, direction: SortDirection) => void; } export function JobListHeader({ headers, style, onSort }: JobListHeaderProps) { Loading
src/components/simulations/list/SimulationsDataGrid.tsx +2 −5 Original line number Diff line number Diff line Loading @@ -7,6 +7,7 @@ import { FetchNextPageOptions } from "@tanstack/react-query"; import { useEffect, useRef } from "react"; import { defaultRangeExtractor, useVirtualizer } from "@tanstack/react-virtual"; import { ExclamationTriangleIcon } from "@heroicons/react/24/outline"; import { SortDirection } from "../../../models/filters/sortDetails.model"; export function SimulationsDataGrid({ columns, Loading @@ -20,11 +21,7 @@ export function SimulationsDataGrid({ total_results, }: { columns: ColumnHeader[]; onSort: ( columnName: string, sorted: boolean, direction: "asc" | "desc", ) => void; onSort: (columnName: string, direction: SortDirection) => void; rows: Simulation[]; isLoading: boolean; isError: boolean; Loading
src/components/simulations/list/SimulationsDataGridHeader.tsx +16 −19 Original line number Diff line number Diff line import { ArrowLongDownIcon } from "@heroicons/react/16/solid"; import { ColumnHeader } from "../../../models/dataGrid/columnHeader.model"; import { CSSProperties } from "react"; import { SortDirection } from "../../../models/filters/sortDetails.model"; function SimulationsDataGridHeaderCell({ column, Loading @@ -8,11 +9,7 @@ function SimulationsDataGridHeaderCell({ index, }: { column: ColumnHeader; onSort: ( columnString: string, sorted: boolean, direction: "asc" | "desc", ) => void; onSort: (columnName: string, direction: SortDirection) => void; index: number; }) { return ( Loading @@ -21,21 +18,25 @@ function SimulationsDataGridHeaderCell({ onClick={(e) => { e.preventDefault(); if (column.sort.sortable) { const direction = column.sort.sorted ? column.sort.direction === "asc" ? "desc" : "asc" : "asc"; onSort(column.name, column.sort.direction !== "desc", direction); // cycle between asc/desc/no-sort let direction: SortDirection; if (column.sort.direction == "asc") { direction = "desc" } else if (column.sort.direction == "desc") { direction = null; } else { direction = "asc"; } onSort(column.name, direction); } }} > <span>{column.name}</span> {column.sort.sortable && ( {column.sort.sortable && column.sort.direction ? ( <ArrowLongDownIcon className={`absolute right-2 h-4 w-4 bg-neutral-300 dark:bg-neutral-800 ${column.sort?.sorted && column.sort?.direction === "asc" && "rotate-180"} transition-opacity duration-300 ease-in-out group-hover:opacity-100 ${!column.sort?.sorted && "opacity-0"}`} className={`absolute right-2 h-4 w-4 bg-neutral-300 dark:bg-neutral-800 ${column.sort.direction === "desc" && "rotate-180"} transition-opacity duration-300 ease-in-out group-hover:opacity-100`} /> )} ) : ""} </button> ); } Loading @@ -46,11 +47,7 @@ export function SimulationsDataGridHeader({ style, }: { columns: ColumnHeader[]; onSort: ( columnName: string, sorted: boolean, direction: "asc" | "desc", ) => void; onSort: (columnName: string, direction: SortDirection) => void; style: CSSProperties; }) { return ( Loading