Table fix
This commit is contained in:
parent
48b7a0d2ad
commit
8bd9c9e121
@ -20,7 +20,6 @@ import FolderIcon from '@mui/icons-material/Folder';
|
|||||||
import QueueIcon from '@mui/icons-material/Queue';
|
import QueueIcon from '@mui/icons-material/Queue';
|
||||||
import AppsIcon from '@mui/icons-material/Apps';
|
import AppsIcon from '@mui/icons-material/Apps';
|
||||||
import ConstructionIcon from '@mui/icons-material/Construction';
|
import ConstructionIcon from '@mui/icons-material/Construction';
|
||||||
import ProcesserTasksPage from './app/page/ProcesserTasksPage';
|
|
||||||
import DashboardIcon from '@mui/icons-material/Dashboard';
|
import DashboardIcon from '@mui/icons-material/Dashboard';
|
||||||
import GraphicEqIcon from '@mui/icons-material/GraphicEq';
|
import GraphicEqIcon from '@mui/icons-material/GraphicEq';
|
||||||
import HomeRepairServiceIcon from '@mui/icons-material/HomeRepairService';
|
import HomeRepairServiceIcon from '@mui/icons-material/HomeRepairService';
|
||||||
@ -110,7 +109,6 @@ function App() {
|
|||||||
}}>
|
}}>
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path='/tasks' element={<ProcesserTasksPage />} />
|
|
||||||
<Route path='/processer' element={<EventsPage />} />
|
<Route path='/processer' element={<EventsPage />} />
|
||||||
<Route path='/unprocessed' element={<UnprocessedFilesPage />} />
|
<Route path='/unprocessed' element={<UnprocessedFilesPage />} />
|
||||||
<Route path='/files' element={<ExplorePage />} />
|
<Route path='/files' element={<ExplorePage />} />
|
||||||
|
|||||||
@ -1,37 +1,28 @@
|
|||||||
import { Box, TableContainer, Table, TableHead, TableRow, TableCell, Typography, TableBody, useTheme } from "@mui/material";
|
import { Box, TableContainer, Table, TableHead, TableRow, TableCell, Typography, TableBody, useTheme } from "@mui/material";
|
||||||
import { useState, useEffect, useMemo } from "react";
|
import { useState, useEffect, useMemo } from "react";
|
||||||
import { TablePropetyConfig, TableCellCustomizer, TableRowActionEvents } from "./table";
|
import { TablePropetyConfig, TableCellCustomizer, TableRowActionEvents, SortByAccessor, TableRowItem, DefaultTableContainer, ITableRow, SortBy, TableSorter } from "./table";
|
||||||
import IconArrowUp from '@mui/icons-material/ArrowUpward';
|
import IconArrowUp from '@mui/icons-material/ArrowUpward';
|
||||||
import IconArrowDown from '@mui/icons-material/ArrowDownward';
|
import IconArrowDown from '@mui/icons-material/ArrowDownward';
|
||||||
|
|
||||||
export interface ExpandableItem<T> {
|
|
||||||
tag: string;
|
|
||||||
expandElement: JSX.Element | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type ExpandableRender<T> = (item: T) => ExpandableItem<T> | null;
|
export type ExpandableRender<T> = (item: T) => JSX.Element | null;
|
||||||
export interface ExpandableTableItem {
|
|
||||||
rowId: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SortByAccessor {
|
|
||||||
accessor: string
|
|
||||||
order: 'asc' | 'desc'
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function ExpandableTable<T extends ExpandableTableItem>({ items, columns, cellCustomizer: customizer, expandableRender, onRowClickedEvent, defaultSort}: { items: Array<T>, columns: Array<TablePropetyConfig>, cellCustomizer?: TableCellCustomizer<T>, expandableRender: ExpandableRender<T>, onRowClickedEvent?: TableRowActionEvents<T>, defaultSort?: SortByAccessor }) {
|
export default function ExpandableTable<R extends ITableRow<U>, U>({ items, columns, cellCustomizer: customizer, expandableRender, onRowClickedEvent, defaultSort, sorter }: { items: Array<R>, columns: Array<TablePropetyConfig>, cellCustomizer?: TableCellCustomizer<R>, expandableRender: ExpandableRender<R>, onRowClickedEvent?: TableRowActionEvents<R>, defaultSort?: SortByAccessor, sorter?: TableSorter<R> }) {
|
||||||
const muiTheme = useTheme();
|
const muiTheme = useTheme();
|
||||||
|
|
||||||
const [order, setOrder] = useState<'asc' | 'desc'>('asc');
|
const [order, setOrder] = useState<'asc' | 'desc'>(defaultSort?.order ?? 'asc');
|
||||||
const [orderBy, setOrderBy] = useState<string>('');
|
const [orderBy, setOrderBy] = useState<string>(defaultSort?.accessor ?? columns[0].accessor ?? '');
|
||||||
const [expandedRowIds, setExpandedRowIds] = useState<Set<string>>(new Set());
|
const [expandedRowIds, setExpandedRowIds] = useState<Set<string>>(new Set());
|
||||||
const [selectedRow, setSelectedRow] = useState<T | null>(null);
|
const [selectedRow, setSelectedRow] = useState<R | null>(null);
|
||||||
const [selectedRowId, setSelectedRowId] = useState<string | null>(null);
|
const [selectedRowId, setSelectedRowId] = useState<string | null>(null);
|
||||||
|
|
||||||
const tableRowSingleClicked = (row: T | null) => {
|
const tableRowSingleClicked = (row: R | null) => {
|
||||||
|
console.log("tableRowSingleClicked", row)
|
||||||
if (row != null && 'rowId' in row) {
|
if (row != null && 'rowId' in row) {
|
||||||
setExpandedRowIds(prev => {
|
setExpandedRowIds(prev => {
|
||||||
const newExpandedRows = new Set(prev);
|
const newExpandedRows = new Set(prev);
|
||||||
|
console.log("newExpandedRows", newExpandedRows)
|
||||||
if (newExpandedRows.has(row.rowId)) {
|
if (newExpandedRows.has(row.rowId)) {
|
||||||
newExpandedRows.delete(row.rowId);
|
newExpandedRows.delete(row.rowId);
|
||||||
} else {
|
} else {
|
||||||
@ -53,27 +44,23 @@ export default function ExpandableTable<T extends ExpandableTableItem>({ items,
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
const tableRowDoubleClicked = (row: T | null) => {
|
const tableRowDoubleClicked = (row: R | null) => {
|
||||||
setSelectedRow(row);
|
setSelectedRow(row);
|
||||||
if (row && onRowClickedEvent) {
|
if (row && onRowClickedEvent) {
|
||||||
onRowClickedEvent.doubleClick(row);
|
onRowClickedEvent.doubleClick(row);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const tableRowContextMenu = (e: React.MouseEvent<HTMLTableRowElement, MouseEvent> , row: T | null) => {
|
const tableRowContextMenu = (e: React.MouseEvent<HTMLTableRowElement, MouseEvent> , row: R | null) => {
|
||||||
if (row && onRowClickedEvent && onRowClickedEvent.contextMenu) {
|
if (row && onRowClickedEvent && onRowClickedEvent.contextMenu) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
onRowClickedEvent.contextMenu(row, e.pageX, e.pageY)
|
onRowClickedEvent.contextMenu(row, e.pageX, e.pageY)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleSort = (property: string) => {
|
|
||||||
const isAsc = orderBy === property && order === 'asc';
|
|
||||||
setOrder(isAsc ? 'desc' : 'asc');
|
|
||||||
setOrderBy(property);
|
|
||||||
};
|
|
||||||
|
|
||||||
const compareValues = (a: any, b: any, orderBy: string) => {
|
const compareValues = (a: any, b: any, orderBy: string) => {
|
||||||
|
console.log("compareValues", a, b, orderBy)
|
||||||
if (typeof a[orderBy] === 'string') {
|
if (typeof a[orderBy] === 'string') {
|
||||||
return a[orderBy].localeCompare(b[orderBy]);
|
return a[orderBy].localeCompare(b[orderBy]);
|
||||||
} else if (typeof a[orderBy] === 'number') {
|
} else if (typeof a[orderBy] === 'number') {
|
||||||
@ -84,22 +71,19 @@ export default function ExpandableTable<T extends ExpandableTableItem>({ items,
|
|||||||
|
|
||||||
|
|
||||||
const sortedData = useMemo(() => {
|
const sortedData = useMemo(() => {
|
||||||
return items.slice().sort((a, b) => {
|
return [...items].sort((a, b) => {
|
||||||
|
if (sorter) {
|
||||||
|
return sorter(a, b, order, orderBy);
|
||||||
|
} else {
|
||||||
if (order === 'asc') {
|
if (order === 'asc') {
|
||||||
return compareValues(a, b, orderBy);
|
return compareValues(a, b, orderBy);
|
||||||
} else {
|
} else {
|
||||||
return compareValues(b, a, orderBy);
|
return compareValues(b, a, orderBy);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}, [items, order, orderBy]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
handleSort(columns[0].accessor)
|
|
||||||
if (defaultSort) {
|
|
||||||
setOrder(defaultSort.order);
|
|
||||||
setOrderBy(defaultSort.accessor);
|
|
||||||
}
|
}
|
||||||
}, [defaultSort])
|
}
|
||||||
|
);
|
||||||
|
}, [items, order, orderBy]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (selectedRowId) {
|
if (selectedRowId) {
|
||||||
@ -113,19 +97,16 @@ export default function ExpandableTable<T extends ExpandableTableItem>({ items,
|
|||||||
}
|
}
|
||||||
}, [items, selectedRowId]);
|
}, [items, selectedRowId]);
|
||||||
|
|
||||||
|
|
||||||
|
const handleSort = (property: string) => {
|
||||||
|
const isAsc = orderBy === property && order === 'asc';
|
||||||
|
setOrder(isAsc ? 'desc' : 'asc');
|
||||||
|
setOrderBy(property);
|
||||||
|
console.log("handleSort", property, isAsc ? 'desc' : 'asc')
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box sx={{
|
<DefaultTableContainer>
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column", // Bruk column-fleksretning
|
|
||||||
height: "100%",
|
|
||||||
overflow: "hidden"
|
|
||||||
}}>
|
|
||||||
<TableContainer sx={{
|
|
||||||
flex: 1,
|
|
||||||
overflowY: "auto",
|
|
||||||
position: "relative", // Legg til denne linjen for å justere layout
|
|
||||||
maxHeight: "100%" // Legg til denne linjen for å begrense høyden
|
|
||||||
}}>
|
|
||||||
<Table>
|
<Table>
|
||||||
<TableHead sx={{
|
<TableHead sx={{
|
||||||
position: "sticky",
|
position: "sticky",
|
||||||
@ -150,7 +131,7 @@ export default function ExpandableTable<T extends ExpandableTableItem>({ items,
|
|||||||
<TableBody sx={{
|
<TableBody sx={{
|
||||||
overflowY: "scroll"
|
overflowY: "scroll"
|
||||||
}}>
|
}}>
|
||||||
{sortedData?.map((row: T, rowIndex: number) => [
|
{sortedData?.map((row: R, rowIndex: number) => [
|
||||||
<TableRow key={row.rowId}
|
<TableRow key={row.rowId}
|
||||||
onClick={() => tableRowSingleClicked(row)}
|
onClick={() => tableRowSingleClicked(row)}
|
||||||
onDoubleClick={() => tableRowDoubleClicked(row)}
|
onDoubleClick={() => tableRowDoubleClicked(row)}
|
||||||
@ -172,7 +153,7 @@ export default function ExpandableTable<T extends ExpandableTableItem>({ items,
|
|||||||
(<TableRow key={row.rowId + "-expanded"}>
|
(<TableRow key={row.rowId + "-expanded"}>
|
||||||
<TableCell colSpan={columns.length}>
|
<TableCell colSpan={columns.length}>
|
||||||
{
|
{
|
||||||
expandableRender(row)?.expandElement
|
expandableRender(row)
|
||||||
}
|
}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>): null
|
</TableRow>): null
|
||||||
@ -180,7 +161,6 @@ export default function ExpandableTable<T extends ExpandableTableItem>({ items,
|
|||||||
])}
|
])}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
</TableContainer>
|
</DefaultTableContainer>
|
||||||
</Box>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -4,16 +4,12 @@ import { RootState } from "../../store";
|
|||||||
import IconArrowUp from '@mui/icons-material/ArrowUpward';
|
import IconArrowUp from '@mui/icons-material/ArrowUpward';
|
||||||
import IconArrowDown from '@mui/icons-material/ArrowDownward';
|
import IconArrowDown from '@mui/icons-material/ArrowDownward';
|
||||||
import { Table, TableHead, TableRow, TableCell, TableBody, Typography, Box, useTheme, TableContainer, IconButton } from "@mui/material";
|
import { Table, TableHead, TableRow, TableCell, TableBody, Typography, Box, useTheme, TableContainer, IconButton } from "@mui/material";
|
||||||
import { TablePropetyConfig, TableCellCustomizer, TableRowActionEvents } from "./table";
|
import { TablePropetyConfig, TableCellCustomizer, TableRowActionEvents, TableRowGroupedItem, DefaultTableContainer } from "./table";
|
||||||
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
||||||
import ExpandLessIcon from '@mui/icons-material/ExpandLess';
|
import ExpandLessIcon from '@mui/icons-material/ExpandLess';
|
||||||
|
|
||||||
export interface TableItemGroup<T> {
|
|
||||||
title: string
|
|
||||||
items: Array<T>
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function SortableGroupedTable<T>({ items, columns, customizer, onRowClickedEvent }: { items: Array<TableItemGroup<T>>, columns: Array<TablePropetyConfig>, customizer?: TableCellCustomizer<T>, onRowClickedEvent?: TableRowActionEvents<T> }) {
|
export default function SortableGroupedTable<T extends TableRowGroupedItem<T>>({ items, columns, customizer, onRowClickedEvent }: { items: Array<T>, columns: Array<TablePropetyConfig>, customizer?: TableCellCustomizer<T>, onRowClickedEvent?: TableRowActionEvents<T> }) {
|
||||||
const muiTheme = useTheme();
|
const muiTheme = useTheme();
|
||||||
|
|
||||||
const [order, setOrder] = useState<'asc' | 'desc'>('asc');
|
const [order, setOrder] = useState<'asc' | 'desc'>('asc');
|
||||||
@ -67,7 +63,11 @@ export default function SortableGroupedTable<T>({ items, columns, customizer, on
|
|||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
const sortedData: Array<TableItemGroup<T>> = items.map((item: TableItemGroup<T>) => {
|
/*const sortedData: Array<RowTableItem<T>> = items.map((item: RowTableItem<T>) => {
|
||||||
|
if (items.length === 0 || !item.items) {
|
||||||
|
console.log(item);
|
||||||
|
return item; // Return the item as is if there are no items to sort
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
title: item.title,
|
title: item.title,
|
||||||
items: item.items.slice().sort((a, b) => {
|
items: item.items.slice().sort((a, b) => {
|
||||||
@ -78,8 +78,20 @@ export default function SortableGroupedTable<T>({ items, columns, customizer, on
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
});
|
});*/
|
||||||
|
|
||||||
|
const sortedData: Array<TableRowGroupedItem<T>> = items.map((item: TableRowGroupedItem<T>) => {
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
items: item.items?.slice().sort((a, b) => {
|
||||||
|
if (order === 'asc') {
|
||||||
|
return compareValues(a, b, orderBy);
|
||||||
|
} else {
|
||||||
|
return compareValues(b, a, orderBy);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -88,18 +100,7 @@ export default function SortableGroupedTable<T>({ items, columns, customizer, on
|
|||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box sx={{
|
<DefaultTableContainer>
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column", // Bruk column-fleksretning
|
|
||||||
height: "100%",
|
|
||||||
overflow: "hidden"
|
|
||||||
}}>
|
|
||||||
<TableContainer sx={{
|
|
||||||
flex: 1,
|
|
||||||
overflowY: "auto",
|
|
||||||
position: "relative", // Legg til denne linjen for å justere layout
|
|
||||||
maxHeight: "100%" // Legg til denne linjen for å begrense høyden
|
|
||||||
}}>
|
|
||||||
<Table>
|
<Table>
|
||||||
<TableHead sx={{
|
<TableHead sx={{
|
||||||
position: "sticky",
|
position: "sticky",
|
||||||
@ -167,7 +168,6 @@ export default function SortableGroupedTable<T>({ items, columns, customizer, on
|
|||||||
))}
|
))}
|
||||||
|
|
||||||
</Table>
|
</Table>
|
||||||
</TableContainer>
|
</DefaultTableContainer>
|
||||||
</Box>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -1,17 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
export interface TablePropetyConfig {
|
|
||||||
label: string
|
|
||||||
accessor: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TableCellCustomizer<T> {
|
|
||||||
(accessor: string, data: T): JSX.Element | null
|
|
||||||
}
|
|
||||||
|
|
||||||
type NullableTableRowActionEvents<T> = TableRowActionEvents<T> | null;
|
|
||||||
export interface TableRowActionEvents<T> {
|
|
||||||
click: (row: T) => void;
|
|
||||||
doubleClick: (row: T) => void;
|
|
||||||
contextMenu?: (row: T, x: number, y: number) => void;
|
|
||||||
}
|
|
||||||
@ -9,10 +9,12 @@ import { Box, Button, Typography, useTheme } from "@mui/material";
|
|||||||
import { Tree } from "react-d3-tree";
|
import { Tree } from "react-d3-tree";
|
||||||
import { EventChain, EventGroup, EventGroups, set } from "../store/chained-events-slice";
|
import { EventChain, EventGroup, EventGroups, set } from "../store/chained-events-slice";
|
||||||
import { toUnixTimestamp, UnixTimestamp } from "../features/UxTc";
|
import { toUnixTimestamp, UnixTimestamp } from "../features/UxTc";
|
||||||
import { TableCellCustomizer, TablePropetyConfig } from "../features/table/table";
|
import { TableCellCustomizer, TablePropetyConfig, TableRowGroupedItem } from "../features/table/table";
|
||||||
import ExpandableTable, { ExpandableItem } from "../features/table/expandableTable";
|
import ExpandableTable from "../features/table/expandableTable";
|
||||||
import { CustomNodeElementProps } from 'react-d3-tree';
|
import { CustomNodeElementProps } from 'react-d3-tree';
|
||||||
|
|
||||||
|
export type ExpandableItemRow = TableRowGroupedItem<EventChain> & EventGroup
|
||||||
|
|
||||||
|
|
||||||
interface RawNodeDatum {
|
interface RawNodeDatum {
|
||||||
name: string;
|
name: string;
|
||||||
@ -37,12 +39,8 @@ const transformEventChain = (eventChain: EventChain): RawNodeDatum => ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Transformasjonsfunksjon for EventGroups
|
// Transformasjonsfunksjon for EventGroups
|
||||||
const transformEventGroups = (group: EventGroup): RawNodeDatum[] => {
|
const transformEventGroups = (group: ExpandableItemRow): RawNodeDatum[] => {
|
||||||
return group.events.map(transformEventChain);
|
return group.items.map(transformEventChain);
|
||||||
}
|
|
||||||
|
|
||||||
interface EventGroupToTreeView extends EventGroup {
|
|
||||||
underView: JSX.Element
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function EventsChainPage() {
|
export default function EventsChainPage() {
|
||||||
@ -51,12 +49,25 @@ export default function EventsChainPage() {
|
|||||||
const client = useStompClient();
|
const client = useStompClient();
|
||||||
const cursor = useSelector((state: RootState) => state.chained)
|
const cursor = useSelector((state: RootState) => state.chained)
|
||||||
const [useReferenceId, setUseReferenceId] = useState<string | null>(null);
|
const [useReferenceId, setUseReferenceId] = useState<string | null>(null);
|
||||||
const [treeData, setTreeData] = useState<RawNodeDatum[] | null>(null);
|
const [tableItems, setTableItems] = useState<Array<ExpandableItemRow>>([]);
|
||||||
|
|
||||||
useWsSubscription<Array<EventGroup>>("/topic/chained/all", (response) => {
|
useWsSubscription<Array<EventGroup>>("/topic/chained/all", (response) => {
|
||||||
dispatch(set(response))
|
dispatch(set(response))
|
||||||
|
console.log(response)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const items = cursor.groups.map((group: EventGroup) => {
|
||||||
|
return {
|
||||||
|
rowId: group.referenceId,
|
||||||
|
title: group.fileName ?? group.referenceId,
|
||||||
|
items: group.events,
|
||||||
|
referenceId: group.referenceId,
|
||||||
|
} as ExpandableItemRow
|
||||||
|
});
|
||||||
|
setTableItems(items);
|
||||||
|
console.log("tableItems", items)
|
||||||
|
}, [cursor]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
client?.publish({
|
client?.publish({
|
||||||
@ -67,23 +78,10 @@ export default function EventsChainPage() {
|
|||||||
const onRefresh = () => {
|
const onRefresh = () => {
|
||||||
client?.publish({
|
client?.publish({
|
||||||
"destination": "/app/chained/all",
|
"destination": "/app/chained/all",
|
||||||
"body": "Potato"
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (useReferenceId) {
|
|
||||||
const eventGroup = cursor.groups.find((group) => group.referenceId === useReferenceId);
|
|
||||||
if (eventGroup) {
|
|
||||||
const data = transformEventGroups(eventGroup);
|
|
||||||
console.log({
|
|
||||||
"info": "Tree data",
|
|
||||||
"data": data
|
|
||||||
})
|
|
||||||
setTreeData(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [useReferenceId, cursor])
|
|
||||||
|
|
||||||
const createTableCell: TableCellCustomizer<EventGroup> = (accessor, data) => {
|
const createTableCell: TableCellCustomizer<EventGroup> = (accessor, data) => {
|
||||||
switch (accessor) {
|
switch (accessor) {
|
||||||
@ -101,7 +99,7 @@ export default function EventsChainPage() {
|
|||||||
|
|
||||||
const columns: Array<TablePropetyConfig> = [
|
const columns: Array<TablePropetyConfig> = [
|
||||||
{ label: "ReferenceId", accessor: "referenceId" },
|
{ label: "ReferenceId", accessor: "referenceId" },
|
||||||
{ label: "File", accessor: "fileName" },
|
{ label: "File", accessor: "title" },
|
||||||
{ label: "Created", accessor: "created" },
|
{ label: "Created", accessor: "created" },
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -144,10 +142,8 @@ export default function EventsChainPage() {
|
|||||||
</>);
|
</>);
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderExpandableItem(item: EventGroup): ExpandableItem<EventGroup> | null {
|
function renderExpandableItem(item: ExpandableItemRow): JSX.Element | null {
|
||||||
return {
|
console.log(item);
|
||||||
tag: item.referenceId,
|
|
||||||
expandElement: (() => {
|
|
||||||
const data = transformEventGroups(item);
|
const data = transformEventGroups(item);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -163,8 +159,6 @@ export default function EventsChainPage() {
|
|||||||
) : <Typography>Tree data not available</Typography>}
|
) : <Typography>Tree data not available</Typography>}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
})()
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -185,7 +179,7 @@ export default function EventsChainPage() {
|
|||||||
position: "absolute",
|
position: "absolute",
|
||||||
width: "100%"
|
width: "100%"
|
||||||
}}>
|
}}>
|
||||||
<ExpandableTable items={cursor?.groups ?? []} columns={columns} cellCustomizer={createTableCell} expandableRender={renderExpandableItem} />
|
<ExpandableTable items={tableItems ?? []} columns={columns} cellCustomizer={createTableCell} expandableRender={renderExpandableItem} />
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@ -17,10 +17,10 @@ import AutoAwesomeMotionIcon from '@mui/icons-material/AutoAwesomeMotion';
|
|||||||
import { client } from "stompjs";
|
import { client } from "stompjs";
|
||||||
import { useStompClient } from "react-stomp-hooks";
|
import { useStompClient } from "react-stomp-hooks";
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import { ContentEventState, ProcesserEventInfo, Status, update, updateEncodeProgress, WorkStatus } from "../store/work-slice";
|
import { ContentEventState, ContentEventStateItems, ProcesserEventInfo, Status, update, updateEncodeProgress, WorkStatus } from "../store/work-slice";
|
||||||
import ExpandableTable, { ExpandableItem } from "../features/table/expandableTable";
|
import ExpandableTable from "../features/table/expandableTable";
|
||||||
import { RootState } from "../store";
|
import { RootState } from "../store";
|
||||||
import { TableCellCustomizer, TablePropetyConfig } from "../features/table/table";
|
import { KeybasedComparator, SortBy, TableCellCustomizer, TablePropetyConfig, TableRowItem } from "../features/table/table";
|
||||||
import SimpleTable from "../features/table/sortableTable";
|
import SimpleTable from "../features/table/sortableTable";
|
||||||
import { UnixTimestamp } from "../features/UxTc";
|
import { UnixTimestamp } from "../features/UxTc";
|
||||||
import ProgressbarWithLabel from "../features/components/ProgressbarWithLabel";
|
import ProgressbarWithLabel from "../features/components/ProgressbarWithLabel";
|
||||||
@ -169,12 +169,24 @@ const transformToSteps = (state: ContentEventState): RawNodeDatum => ({
|
|||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export type ExpandableItemRow = TableRowItem<ContentEventState>
|
||||||
|
|
||||||
export default function EventsPage() {
|
export default function EventsPage() {
|
||||||
const client = useStompClient();
|
const client = useStompClient();
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const events = useSelector((state: RootState) => state.work);
|
const events: ContentEventStateItems = useSelector((state: RootState) => state.work);
|
||||||
|
const [tableItems, setTableItems] = useState<Array<ExpandableItemRow>>([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const items = events.items.map((event: ContentEventState) => {
|
||||||
|
return {
|
||||||
|
rowId: event.referenceId,
|
||||||
|
title: event.referenceId,
|
||||||
|
item: event
|
||||||
|
} as ExpandableItemRow
|
||||||
|
});
|
||||||
|
setTableItems(items);
|
||||||
|
}, [events]);
|
||||||
|
|
||||||
useWsSubscription<Array<ContentEventState>>("/topic/tasks/all", (response) => {
|
useWsSubscription<Array<ContentEventState>>("/topic/tasks/all", (response) => {
|
||||||
console.log(response)
|
console.log(response)
|
||||||
@ -192,7 +204,7 @@ export default function EventsPage() {
|
|||||||
})
|
})
|
||||||
}, [client]);
|
}, [client]);
|
||||||
|
|
||||||
const createCellTable: TableCellCustomizer<ContentEventState> = (accessor, data) => {
|
const createCellTable: TableCellCustomizer<ExpandableItemRow> = (accessor, data) => {
|
||||||
switch (accessor) {
|
switch (accessor) {
|
||||||
case "runners": {
|
case "runners": {
|
||||||
return (<>
|
return (<>
|
||||||
@ -206,7 +218,7 @@ export default function EventsPage() {
|
|||||||
x: 24,
|
x: 24,
|
||||||
y: 24
|
y: 24
|
||||||
}}
|
}}
|
||||||
data={transformToSteps(data)}
|
data={transformToSteps(data.item)}
|
||||||
orientation="horizontal"
|
orientation="horizontal"
|
||||||
separation={{
|
separation={{
|
||||||
nonSiblings: 1,
|
nonSiblings: 1,
|
||||||
@ -226,8 +238,8 @@ export default function EventsPage() {
|
|||||||
</>)
|
</>)
|
||||||
};
|
};
|
||||||
case "created": {
|
case "created": {
|
||||||
if (typeof data[accessor] === "number") {
|
if (typeof data.item[accessor] === "number") {
|
||||||
return UnixTimestamp({ timestamp: data[accessor] });
|
return UnixTimestamp({ timestamp: data.item[accessor] });
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -235,33 +247,36 @@ export default function EventsPage() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function renderExpandableItem(item: ContentEventState): ExpandableItem<ContentEventState> | null {
|
const sorter = (a: ExpandableItemRow, b: ExpandableItemRow, orderBy: SortBy, accessor: string) => {
|
||||||
const progress = item.encodeWork?.progress?.progress ?? undefined;
|
if (orderBy === "asc") {
|
||||||
const showProgressbar = [WorkStatus.Pending, WorkStatus.Started, WorkStatus.Working, WorkStatus.Completed].includes(item?.encodeWork?.status)
|
return KeybasedComparator(a.item, b.item, "created")
|
||||||
|
} else {
|
||||||
|
return KeybasedComparator(b.item, a.item, "created")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const processer = item.encodeWork // events.encodeWork[item.referenceId];
|
function renderExpandableItem(item: ExpandableItemRow): JSX.Element | null {
|
||||||
|
const data = item.item;
|
||||||
|
const progress = data.encodeWork?.progress?.progress ?? undefined;
|
||||||
|
const showProgressbar = [WorkStatus.Pending, WorkStatus.Started, WorkStatus.Working, WorkStatus.Completed].includes(data?.encodeWork?.status)
|
||||||
|
|
||||||
|
const processer = data.encodeWork // events.encodeWork[item.referenceId];
|
||||||
const showIndeterminate = processer?.status in [WorkStatus.Pending, WorkStatus.Started] || processer?.progress?.progress <= 0
|
const showIndeterminate = processer?.status in [WorkStatus.Pending, WorkStatus.Started] || processer?.progress?.progress <= 0
|
||||||
console.log({
|
console.log({
|
||||||
type: "info",
|
type: "info",
|
||||||
processer: processer,
|
processer: processer,
|
||||||
showIndeterminate: showIndeterminate,
|
showIndeterminate: showIndeterminate,
|
||||||
showProgressbar: showProgressbar,
|
showProgressbar: showProgressbar,
|
||||||
isWorking: item.encodeWork?.status == WorkStatus.Working
|
isWorking: data.encodeWork?.status == WorkStatus.Working
|
||||||
});
|
});
|
||||||
return {
|
|
||||||
tag: item.referenceId,
|
|
||||||
expandElement: (() => {
|
|
||||||
//const data = transformEventGroups(item);
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Typography>{item.encodeWork?.progress?.timeLeft}</Typography>
|
<Typography>{data.encodeWork?.progress?.timeLeft}</Typography>
|
||||||
{(showProgressbar) ?
|
{(showProgressbar) ?
|
||||||
<ProgressbarWithLabel indeterminateText={"Waiting"} progress={progress} /> : null
|
<ProgressbarWithLabel indeterminateText={"Waiting"} progress={progress} /> : null
|
||||||
}
|
}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
})()
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const columns: Array<TablePropetyConfig> = [
|
const columns: Array<TablePropetyConfig> = [
|
||||||
@ -279,10 +294,10 @@ export default function EventsPage() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ExpandableTable items={events.items} columns={columns} cellCustomizer={createCellTable} expandableRender={renderExpandableItem} defaultSort={{
|
<ExpandableTable items={tableItems} columns={columns} cellCustomizer={createCellTable} expandableRender={renderExpandableItem} defaultSort={{
|
||||||
order: 'desc',
|
order: 'desc',
|
||||||
accessor: "created"
|
accessor: "created"
|
||||||
}} />
|
}} sorter={sorter} />
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -1,102 +0,0 @@
|
|||||||
import { useEffect, useState } from "react";
|
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
|
||||||
import { useStompClient } from "react-stomp-hooks";
|
|
||||||
import { Box, Button, Grid, TextField, Typography, useTheme } from '@mui/material';
|
|
||||||
import { ExplorerItem } from "../../types";
|
|
||||||
import { ContextMenuItem } from "../features/ContextMenu";
|
|
||||||
import { RootState } from "../store";
|
|
||||||
import { useWsSubscription } from "../ws/subscriptions";
|
|
||||||
import SimpleTable from "../features/table/sortableTable";
|
|
||||||
import { TableCellCustomizer, TablePropetyConfig } from "../features/table/table";
|
|
||||||
import MultiListSortedTable from "../features/table/multiListSortedTable";
|
|
||||||
import { TableTaskGroup, Task, TaskGroup, update } from "../store/tasks-slice";
|
|
||||||
import SortableGroupedTable from "../features/table/sortableGroupedTable";
|
|
||||||
import { UnixTimestamp } from "../features/UxTc";
|
|
||||||
|
|
||||||
const columns: Array<TablePropetyConfig> = [
|
|
||||||
{ label: "Name", accessor: "data.inputFile" },
|
|
||||||
{ label: "Task", accessor: "task" },
|
|
||||||
{ label: "Status", accessor: "status" },
|
|
||||||
{ label: "Created", accessor: "created" },
|
|
||||||
];
|
|
||||||
|
|
||||||
const createTableCell: TableCellCustomizer<Task> = (accessor, data) => {
|
|
||||||
switch (accessor) {
|
|
||||||
case "created": {
|
|
||||||
if (typeof data[accessor] === "string") {
|
|
||||||
return UnixTimestamp({ timestamp: Date.parse(data[accessor]) });
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
case "data.inputFile": {
|
|
||||||
const parts = data.data?.inputFile.split("/") ?? [];
|
|
||||||
return <Typography>{parts[parts?.length - 1]}</Typography>
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
export default function ProcesserTasksPage() {
|
|
||||||
const muiTheme = useTheme();
|
|
||||||
const dispatch = useDispatch();
|
|
||||||
const client = useStompClient();
|
|
||||||
const taskGroups = useSelector((state: RootState) => state.tasks);
|
|
||||||
|
|
||||||
useWsSubscription<Array<TaskGroup>>("/topic/tasks/all", (response) => {
|
|
||||||
console.log(response)
|
|
||||||
dispatch(update(response))
|
|
||||||
});
|
|
||||||
|
|
||||||
useWsSubscription<any>("/topic/processer/encode/progress", (response) => {
|
|
||||||
console.log(response)
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
client?.publish({
|
|
||||||
destination: "/app/tasks/all"
|
|
||||||
});
|
|
||||||
}, [client, dispatch]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Box display="block">
|
|
||||||
<Grid container sx={{
|
|
||||||
height: 50,
|
|
||||||
width: "100%",
|
|
||||||
maxHeight: "100%",
|
|
||||||
overflow: "hidden",
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
backgroundColor: muiTheme.palette.background.paper
|
|
||||||
}}>
|
|
||||||
<Grid item xs={2}>
|
|
||||||
<Typography variant="h6">Tasks</Typography>
|
|
||||||
</Grid>
|
|
||||||
<Grid item xs={10}>
|
|
||||||
<TextField
|
|
||||||
hiddenLabel
|
|
||||||
placeholder="Search"
|
|
||||||
fullWidth={true}
|
|
||||||
id="search-field"
|
|
||||||
variant="filled"
|
|
||||||
/>
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
|
|
||||||
<Box sx={{
|
|
||||||
display: "block",
|
|
||||||
height: "calc(100% - 120px)",
|
|
||||||
overflow: "hidden",
|
|
||||||
position: "absolute",
|
|
||||||
width: "100%"
|
|
||||||
}}>
|
|
||||||
<SortableGroupedTable items={taskGroups.items ?? []} columns={columns} customizer={createTableCell} />
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@ -1,10 +1,9 @@
|
|||||||
import { createSlice, PayloadAction } from "@reduxjs/toolkit"
|
import { createSlice, PayloadAction } from "@reduxjs/toolkit"
|
||||||
import { ExpandableTableItem } from "../features/table/expandableTable";
|
|
||||||
|
|
||||||
export interface EventGroup extends ExpandableTableItem {
|
export interface EventGroup {
|
||||||
referenceId: string,
|
referenceId: string,
|
||||||
created: number,
|
created: number,
|
||||||
fileName: string|null,
|
fileName?: string,
|
||||||
events: EventChain[]
|
events: EventChain[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -66,6 +66,7 @@ export interface TaskGroupList {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface TableTaskGroup extends TableItemGroup<Task> {
|
export interface TableTaskGroup extends TableItemGroup<Task> {
|
||||||
|
referenceId: string
|
||||||
title: string
|
title: string
|
||||||
items: Array<Task>
|
items: Array<Task>
|
||||||
}
|
}
|
||||||
@ -84,6 +85,7 @@ const tasksSlice = createSlice({
|
|||||||
reducers: {
|
reducers: {
|
||||||
update(state, action: PayloadAction<Array<TaskGroup>>) {
|
update(state, action: PayloadAction<Array<TaskGroup>>) {
|
||||||
state.items = action.payload.map((value) => ({
|
state.items = action.payload.map((value) => ({
|
||||||
|
referenceId: value.referenceId,
|
||||||
title: value.referenceId,
|
title: value.referenceId,
|
||||||
items: value.tasks
|
items: value.tasks
|
||||||
})) ?? []
|
})) ?? []
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import { createSlice, PayloadAction } from "@reduxjs/toolkit"
|
import { createSlice, PayloadAction } from "@reduxjs/toolkit"
|
||||||
import { ExpandableTableItem } from "../features/table/expandableTable"
|
|
||||||
|
|
||||||
export enum WorkStatus {
|
export enum WorkStatus {
|
||||||
Pending = "Pending",
|
Pending = "Pending",
|
||||||
@ -38,7 +37,7 @@ export enum Status {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
export interface ContentEventState extends ExpandableTableItem {
|
export interface ContentEventState {
|
||||||
referenceId: string
|
referenceId: string
|
||||||
title: string
|
title: string
|
||||||
encode: Status
|
encode: Status
|
||||||
|
|||||||
@ -29,8 +29,8 @@ root.render(
|
|||||||
<StompSessionProvider url={wsUrl()} connectHeaders={{}} logRawCommunication={true}
|
<StompSessionProvider url={wsUrl()} connectHeaders={{}} logRawCommunication={true}
|
||||||
debug={(str) => {
|
debug={(str) => {
|
||||||
if (str === "Opening Web Socket...") {
|
if (str === "Opening Web Socket...") {
|
||||||
|
console.log("Connecting with Web Socket...")
|
||||||
}
|
}
|
||||||
console.log(str);
|
|
||||||
}}
|
}}
|
||||||
onUnhandledMessage={(val) => {
|
onUnhandledMessage={(val) => {
|
||||||
console.log("Unhandled message", val)
|
console.log("Unhandled message", val)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user