aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/frontend/src/table
diff options
context:
space:
mode:
Diffstat (limited to 'subprojects/frontend/src/table')
-rw-r--r--subprojects/frontend/src/table/RelationGrid.tsx109
-rw-r--r--subprojects/frontend/src/table/SymbolSelector.tsx65
-rw-r--r--subprojects/frontend/src/table/TableArea.tsx24
-rw-r--r--subprojects/frontend/src/table/TablePane.tsx22
-rw-r--r--subprojects/frontend/src/table/TableToolbar.tsx41
-rw-r--r--subprojects/frontend/src/table/ValueRenderer.tsx62
6 files changed, 323 insertions, 0 deletions
diff --git a/subprojects/frontend/src/table/RelationGrid.tsx b/subprojects/frontend/src/table/RelationGrid.tsx
new file mode 100644
index 00000000..004982c9
--- /dev/null
+++ b/subprojects/frontend/src/table/RelationGrid.tsx
@@ -0,0 +1,109 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
7import Box from '@mui/material/Box';
8import {
9 DataGrid,
10 type GridRenderCellParams,
11 type GridColDef,
12} from '@mui/x-data-grid';
13import { observer } from 'mobx-react-lite';
14import { useMemo } from 'react';
15
16import type GraphStore from '../graph/GraphStore';
17
18import TableToolbar from './TableToolbar';
19import ValueRenderer from './ValueRenderer';
20
21interface Row {
22 nodes: string[];
23 value: string;
24}
25
26function RelationGrid({ graph }: { graph: GraphStore }): JSX.Element {
27 const {
28 selectedSymbol,
29 semantics: { nodes, partialInterpretation },
30 } = graph;
31 const symbolName = selectedSymbol?.name;
32 const arity = selectedSymbol?.arity ?? 0;
33
34 const columns = useMemo<GridColDef<Row>[]>(() => {
35 const defs: GridColDef<Row>[] = [];
36 for (let i = 0; i < arity; i += 1) {
37 defs.push({
38 field: `n${i}`,
39 headerName: String(i + 1),
40 valueGetter: (row) => row.row.nodes[i] ?? '',
41 flex: 1,
42 });
43 }
44 defs.push({
45 field: 'value',
46 headerName: 'Value',
47 flex: 1,
48 renderCell: ({ value }: GridRenderCellParams<Row, string>) => (
49 <ValueRenderer value={value} />
50 ),
51 });
52 return defs;
53 }, [arity]);
54
55 const rows = useMemo<Row[]>(() => {
56 if (symbolName === undefined) {
57 return [];
58 }
59 const interpretation = partialInterpretation[symbolName] ?? [];
60 return interpretation.map((tuple) => {
61 const nodeNames: string[] = [];
62 for (let i = 0; i < arity; i += 1) {
63 const index = tuple[i];
64 if (typeof index === 'number') {
65 const node = nodes[index];
66 if (node !== undefined) {
67 nodeNames.push(node.name);
68 }
69 }
70 }
71 return {
72 nodes: nodeNames,
73 value: String(tuple[arity]),
74 };
75 });
76 }, [arity, nodes, partialInterpretation, symbolName]);
77
78 return (
79 <Box
80 width="100%"
81 height="100%"
82 p={1}
83 sx={(theme) => ({
84 '.MuiDataGrid-withBorderColor': {
85 borderColor:
86 theme.palette.mode === 'dark'
87 ? theme.palette.divider
88 : theme.palette.outer.border,
89 },
90 })}
91 >
92 <DataGrid
93 slots={{ toolbar: TableToolbar }}
94 slotProps={{
95 toolbar: {
96 graph,
97 },
98 }}
99 density="compact"
100 rowSelection={false}
101 columns={columns}
102 rows={rows}
103 getRowId={(row) => row.nodes.join(',')}
104 />
105 </Box>
106 );
107}
108
109export default observer(RelationGrid);
diff --git a/subprojects/frontend/src/table/SymbolSelector.tsx b/subprojects/frontend/src/table/SymbolSelector.tsx
new file mode 100644
index 00000000..5272f8ed
--- /dev/null
+++ b/subprojects/frontend/src/table/SymbolSelector.tsx
@@ -0,0 +1,65 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
7import Autocomplete from '@mui/material/Autocomplete';
8import Box from '@mui/material/Box';
9import TextField from '@mui/material/TextField';
10import { observer } from 'mobx-react-lite';
11
12import type GraphStore from '../graph/GraphStore';
13import RelationName from '../graph/RelationName';
14
15function SymbolSelector({ graph }: { graph: GraphStore }): JSX.Element {
16 const {
17 selectedSymbol,
18 semantics: { relations },
19 } = graph;
20
21 return (
22 <Autocomplete
23 renderInput={(params) => (
24 <TextField
25 {...{
26 ...params,
27 InputLabelProps: {
28 ...params.InputLabelProps,
29 // Workaround for type errors.
30 className: params.InputLabelProps.className ?? '',
31 style: params.InputLabelProps.style ?? {},
32 },
33 }}
34 variant="standard"
35 size="medium"
36 placeholder="Symbol"
37 />
38 )}
39 options={relations}
40 getOptionLabel={(option) => option.name}
41 renderOption={(props, option) => (
42 <Box component="li" {...props}>
43 <RelationName metadata={option} />
44 </Box>
45 )}
46 value={selectedSymbol ?? null}
47 isOptionEqualToValue={(option, value) => option.name === value.name}
48 onChange={(_event, value) => graph.setSelectedSymbol(value ?? undefined)}
49 sx={(theme) => ({
50 flexBasis: 200,
51 maxWidth: 600,
52 flexGrow: 1,
53 flexShrink: 1,
54 '.MuiInput-underline::before': {
55 borderColor:
56 theme.palette.mode === 'dark'
57 ? theme.palette.divider
58 : theme.palette.outer.border,
59 },
60 })}
61 />
62 );
63}
64
65export default observer(SymbolSelector);
diff --git a/subprojects/frontend/src/table/TableArea.tsx b/subprojects/frontend/src/table/TableArea.tsx
new file mode 100644
index 00000000..cf37b96a
--- /dev/null
+++ b/subprojects/frontend/src/table/TableArea.tsx
@@ -0,0 +1,24 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
7import { observer } from 'mobx-react-lite';
8
9import Loading from '../Loading';
10import { useRootStore } from '../RootStoreProvider';
11
12import RelationGrid from './RelationGrid';
13
14function TablePane(): JSX.Element {
15 const { editorStore } = useRootStore();
16
17 if (editorStore === undefined) {
18 return <Loading />;
19 }
20
21 return <RelationGrid graph={editorStore.graph} />;
22}
23
24export default observer(TablePane);
diff --git a/subprojects/frontend/src/table/TablePane.tsx b/subprojects/frontend/src/table/TablePane.tsx
new file mode 100644
index 00000000..01442c3a
--- /dev/null
+++ b/subprojects/frontend/src/table/TablePane.tsx
@@ -0,0 +1,22 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
7import Stack from '@mui/material/Stack';
8import { Suspense, lazy } from 'react';
9
10import Loading from '../Loading';
11
12const TableArea = lazy(() => import('./TableArea'));
13
14export default function TablePane(): JSX.Element {
15 return (
16 <Stack direction="column" height="100%" overflow="auto" alignItems="center">
17 <Suspense fallback={<Loading />}>
18 <TableArea />
19 </Suspense>
20 </Stack>
21 );
22}
diff --git a/subprojects/frontend/src/table/TableToolbar.tsx b/subprojects/frontend/src/table/TableToolbar.tsx
new file mode 100644
index 00000000..b14e73c5
--- /dev/null
+++ b/subprojects/frontend/src/table/TableToolbar.tsx
@@ -0,0 +1,41 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
7import Stack from '@mui/material/Stack';
8import {
9 GridToolbarColumnsButton,
10 GridToolbarContainer,
11 GridToolbarExport,
12 GridToolbarFilterButton,
13} from '@mui/x-data-grid';
14
15import type GraphStore from '../graph/GraphStore';
16
17import SymbolSelector from './SymbolSelector';
18
19export default function TableToolbar({
20 graph,
21}: {
22 graph: GraphStore;
23}): JSX.Element {
24 return (
25 <GridToolbarContainer
26 sx={{
27 display: 'flex',
28 flexDirection: 'row',
29 flexWrap: 'wrap-reverse',
30 justifyContent: 'space-between',
31 }}
32 >
33 <Stack direction="row" flexWrap="wrap">
34 <GridToolbarColumnsButton />
35 <GridToolbarFilterButton />
36 <GridToolbarExport />
37 </Stack>
38 <SymbolSelector graph={graph} />
39 </GridToolbarContainer>
40 );
41}
diff --git a/subprojects/frontend/src/table/ValueRenderer.tsx b/subprojects/frontend/src/table/ValueRenderer.tsx
new file mode 100644
index 00000000..ac5700e4
--- /dev/null
+++ b/subprojects/frontend/src/table/ValueRenderer.tsx
@@ -0,0 +1,62 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
7import CancelIcon from '@mui/icons-material/Cancel';
8import LabelIcon from '@mui/icons-material/Label';
9import LabelOutlinedIcon from '@mui/icons-material/LabelOutlined';
10import { styled } from '@mui/material/styles';
11
12const Label = styled('div', {
13 name: 'ValueRenderer-Label',
14 shouldForwardProp: (prop) => prop !== 'value',
15})<{
16 value: 'TRUE' | 'UNKNOWN' | 'ERROR';
17}>(({ theme, value }) => ({
18 display: 'flex',
19 alignItems: 'center',
20 ...(value === 'UNKNOWN'
21 ? {
22 color: theme.palette.text.secondary,
23 }
24 : {}),
25 ...(value === 'ERROR'
26 ? {
27 color: theme.palette.error.main,
28 }
29 : {}),
30 '& svg': {
31 marginRight: theme.spacing(0.5),
32 },
33}));
34
35export default function ValueRenderer({
36 value,
37}: {
38 value: string | undefined;
39}): React.ReactNode {
40 switch (value) {
41 case 'TRUE':
42 return (
43 <Label value={value}>
44 <LabelIcon fontSize="small" /> true
45 </Label>
46 );
47 case 'UNKNOWN':
48 return (
49 <Label value={value}>
50 <LabelOutlinedIcon fontSize="small" /> unknown
51 </Label>
52 );
53 case 'ERROR':
54 return (
55 <Label value={value}>
56 <CancelIcon fontSize="small" /> error
57 </Label>
58 );
59 default:
60 return value;
61 }
62}