@ocelescope/resources 0.10.2 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/index.d.ts +19 -15
  2. package/dist/index.js +488 -175
  3. package/package.json +14 -13
package/dist/index.d.ts CHANGED
@@ -1,30 +1,35 @@
1
- import { Select } from "@mantine/core";
2
- import { GetResourceResponse } from "@ocelescope/api-base";
3
- import { ComponentProps } from "react";
4
- //#region src/components/ResourceModal/ResourceModal.d.ts
1
+ import { MultiSelectProps, SelectProps } from "@mantine/core";
2
+ import { resourceVisualization } from "@ocelescope/api-base";
3
+ import { ReactNode } from "react";
4
+ type Controlled<P extends SelectProps | MultiSelectProps> = Omit<P, "defaultValue"> & Required<Pick<P, "value" | "onChange">>;
5
+ type ActionSelectProps = {
6
+ actions?: ReactNode;
7
+ } & ((Controlled<SelectProps> & {
8
+ multiple?: false;
9
+ }) | (Controlled<MultiSelectProps> & {
10
+ multiple: true;
11
+ }));
12
+ export declare const ActionSelect: React.FC<ActionSelectProps>;
5
13
  export declare const ResourceModal: React.FC<{
6
14
  id: string;
7
15
  onClose: () => void;
8
16
  }>;
9
- //#endregion
10
- //#region src/components/ResourceSelect/ResourceSelect.d.ts
11
- export declare const ResourceSelect: React.FC<Omit<ComponentProps<typeof Select<string>>, "data"> & {
17
+ type ResourceSelectProps = ActionSelectProps & {
12
18
  type?: string;
13
- }>;
14
- //#endregion
15
- //#region src/types/index.d.ts
19
+ withUpload?: boolean;
20
+ withView?: boolean;
21
+ };
22
+ export declare const ResourceSelect: React.FC<ResourceSelectProps>;
16
23
  type RequireType<T> = T extends {
17
24
  type?: infer L;
18
25
  } ? Omit<T, "type"> & {
19
26
  type: L;
20
27
  } : T;
21
- type VisualizationsType = RequireType<NonNullable<GetResourceResponse["visualization"]>>;
28
+ type VisualizationsType = RequireType<NonNullable<Awaited<ReturnType<typeof resourceVisualization>>>>;
22
29
  type VisualizationsTypes = NonNullable<VisualizationsType["type"]>;
23
30
  type VisualizationByType<T extends VisualizationsTypes> = Extract<VisualizationsType, {
24
31
  type: T;
25
32
  }>;
26
- //#endregion
27
- //#region src/components/ResourceView/index.d.ts
28
33
  type ExtraMenuItem = {
29
34
  icon: React.ReactNode;
30
35
  label: string;
@@ -40,5 +45,4 @@ export declare const ResourceViewer: React.FC<{
40
45
  id: string;
41
46
  isPreview?: boolean;
42
47
  }>;
43
- //#endregion
44
- export type { VisualizationsType };
48
+ export type { ActionSelectProps, ResourceSelectProps, VisualizationsType };
package/dist/index.js CHANGED
@@ -1,9 +1,13 @@
1
- import { ActionIcon, Alert, Badge, Box, Button, ButtonGroup, Code, Group, LoadingOverlay, Menu, Modal, Popover, ScrollArea, Select, Stack, Text, ThemeIcon, Title } from "@mantine/core";
2
- import { useResource, useResources } from "@ocelescope/api-base";
3
- import { DownloadIcon, EyeOffIcon, Maximize2Icon, MaximizeIcon, MinusIcon, PlusIcon, XIcon } from "lucide-react";
4
- import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react";
5
- import dynamic from "next/dynamic.js";
1
+ import { ActionIcon, Alert, Autocomplete, Badge, Box, Button, ButtonGroup, Center, Code, FileButton, Group, LoadingOverlay, Menu, Modal, MultiSelect, Popover, ScrollArea, Scroller, Select, Stack, Tabs, Text, Title, Tooltip } from "@mantine/core";
6
2
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import { useResource, useResourceTableColumnValues, useResourceTableRows, useResourceTables, useResourceVisualization, useResources, useUpload } from "@ocelescope/api-base";
4
+ import { DownloadIcon, EyeIcon, EyeOffIcon, Maximize2Icon, MaximizeIcon, MinusIcon, PlusIcon, SearchIcon, UploadIcon, XIcon } from "lucide-react";
5
+ import { useDebouncedValue, useDisclosure } from "@mantine/hooks";
6
+ import { DataTable } from "mantine-datatable";
7
+ import { memo, useCallback, useEffect, useEffectEvent, useMemo, useRef, useState } from "react";
8
+ import dayjs from "dayjs";
9
+ import isBetween from "dayjs/plugin/isBetween.js";
10
+ import dynamic from "next/dynamic.js";
7
11
  import { Graphviz } from "@hpcc-js/wasm-graphviz";
8
12
  import FileSaver from "file-saver";
9
13
  import { TransformComponent, TransformWrapper } from "react-zoom-pan-pinch";
@@ -11,15 +15,302 @@ import { Background, BaseEdge, ControlButton, Controls, EdgeLabelRenderer, Handl
11
15
  import { toPng, toSvg } from "html-to-image";
12
16
  import { jsPDF } from "jspdf";
13
17
  import ELK from "elkjs/lib/elk.bundled.js";
14
- import { DataTable } from "mantine-datatable";
15
- import dayjs from "dayjs";
16
- import isBetween from "dayjs/plugin/isBetween.js";
17
- //#region src/components/ResourceView/Viewers/R4pm.tsx
18
+ // src/components/ActionSelect/ActionSelect.tsx
19
+ const attachedStyles = { input: {
20
+ borderTopRightRadius: 0,
21
+ borderBottomRightRadius: 0
22
+ } };
23
+ const renderSelect = (props) => {
24
+ const styles = props.actions ? attachedStyles : void 0;
25
+ if (props.multiple) {
26
+ const { multiple: _, actions: __, ...rest } = props;
27
+ return /* @__PURE__ */ jsx(MultiSelect, {
28
+ flex: 1,
29
+ miw: 0,
30
+ styles,
31
+ ...rest
32
+ });
33
+ }
34
+ const { multiple: _, actions: __, ...rest } = props;
35
+ return /* @__PURE__ */ jsx(Select, {
36
+ flex: 1,
37
+ miw: 0,
38
+ styles,
39
+ ...rest
40
+ });
41
+ };
42
+ const ActionSelect = (props) => /* @__PURE__ */ jsxs(Group, {
43
+ wrap: "nowrap",
44
+ gap: 0,
45
+ align: "flex-end",
46
+ children: [renderSelect(props), props.actions && /* @__PURE__ */ jsxs(ActionIcon.Group, { children: [/* @__PURE__ */ jsx(ActionIcon.GroupSection, { hidden: true }), props.actions] })]
47
+ });
48
+ // src/util/dayjs.ts
49
+ dayjs.extend(isBetween);
50
+ var dayjs_default = dayjs;
51
+ const formatDateTime = (dateString) => dayjs(dateString).format("YYYY-MM-DD HH:mm");
52
+ const formatDate = (dateString) => dayjs(dateString).format("YYYY-MM-DD");
53
+ // src/components/ResourceView/Viewers/Table.tsx
54
+ const formatCell = (value, dataType) => {
55
+ if (value == null) return "";
56
+ switch (dataType) {
57
+ case "boolean": return value ? "✅" : "❌";
58
+ case "date": return dayjs_default(value).isValid() ? formatDate(value) : String(value);
59
+ case "datetime": return dayjs_default(value).isValid() ? formatDateTime(value) : String(value);
60
+ default: return String(value);
61
+ }
62
+ };
63
+ const PAGE_SIZES$1 = [
64
+ 20,
65
+ 50,
66
+ 75
67
+ ];
68
+ const TableView = ({ visualization }) => {
69
+ const [pageSize, setPageSize] = useState(PAGE_SIZES$1[0]);
70
+ const columns = useMemo(() => visualization.columns.map((col) => ({
71
+ accessor: col.id,
72
+ title: col.label ?? col.id,
73
+ render: (record) => formatCell(record[col.id], col.data_type)
74
+ })), [visualization.columns]);
75
+ const [page, setPage] = useState(1);
76
+ const [records, setRecords] = useState(visualization.rows.slice(0, pageSize));
77
+ useEffect(() => {
78
+ const from = (page - 1) * pageSize;
79
+ const to = from + pageSize;
80
+ setRecords(visualization.rows.slice(from, to));
81
+ }, [
82
+ page,
83
+ pageSize,
84
+ visualization
85
+ ]);
86
+ const paginationProps = visualization.rows.length > PAGE_SIZES$1[0] ? {
87
+ totalRecords: visualization.rows.length,
88
+ recordsPerPage: pageSize,
89
+ onPageChange: (p) => setPage(p),
90
+ page,
91
+ recordsPerPageOptions: [...PAGE_SIZES$1],
92
+ onRecordsPerPageChange: (newPageSize) => {
93
+ setPageSize(newPageSize);
94
+ setPage(1);
95
+ }
96
+ } : {};
97
+ return /* @__PURE__ */ jsx(DataTable, {
98
+ records,
99
+ columns,
100
+ withTableBorder: true,
101
+ withColumnBorders: true,
102
+ withRowBorders: true,
103
+ ...paginationProps
104
+ });
105
+ };
106
+ // src/components/ResourceView/TabularView.tsx
107
+ const PAGE_SIZES = [
108
+ 20,
109
+ 50,
110
+ 100
111
+ ];
112
+ const UNSORTED = {
113
+ columnAccessor: "",
114
+ direction: "asc"
115
+ };
116
+ const VALUE_LIMIT = 50;
117
+ const ColumnFilter = ({ resourceId, tableName, columnId, selected, onChange }) => {
118
+ const [search, setSearch] = useState("");
119
+ const [debouncedSearch] = useDebouncedValue(search, 250);
120
+ const { data, isFetching } = useResourceTableColumnValues(resourceId, tableName, columnId, {
121
+ size: VALUE_LIMIT,
122
+ ...debouncedSearch && { search: debouncedSearch }
123
+ }, { query: { placeholderData: (previous) => previous } });
124
+ const options = useMemo(() => [.../* @__PURE__ */ new Set([...selected, ...data?.response ?? []])], [selected, data?.response]);
125
+ const total = data?.total_items ?? 0;
126
+ return /* @__PURE__ */ jsx(MultiSelect, {
127
+ w: 280,
128
+ searchable: true,
129
+ clearable: true,
130
+ data: options,
131
+ value: selected,
132
+ onChange,
133
+ searchValue: search,
134
+ onSearchChange: setSearch,
135
+ filter: ({ options: unfiltered }) => unfiltered,
136
+ placeholder: `Search ${columnId}`,
137
+ nothingFoundMessage: isFetching ? "Loading..." : "No values found",
138
+ description: total > VALUE_LIMIT ? `Showing ${VALUE_LIMIT} of ${total} values, type to narrow down` : void 0,
139
+ comboboxProps: { withinPortal: false }
140
+ });
141
+ };
142
+ const TableRows = ({ resourceId, table }) => {
143
+ const [page, setPage] = useState(1);
144
+ const [pageSize, setPageSize] = useState(PAGE_SIZES[0]);
145
+ const [sortStatus, setSortStatus] = useState(UNSORTED);
146
+ const [filters, setFilters] = useState({});
147
+ const hasFilters = Object.values(filters).some((values) => values.length > 0);
148
+ const { data, isError, isFetching } = useResourceTableRows(resourceId, table.name, {
149
+ page,
150
+ size: pageSize,
151
+ ...sortStatus.columnAccessor && {
152
+ sort_by: sortStatus.columnAccessor,
153
+ descending: sortStatus.direction === "desc"
154
+ },
155
+ ...hasFilters && { filters: JSON.stringify(filters) }
156
+ }, { query: { placeholderData: (previous) => previous } });
157
+ const columns = useMemo(() => table.columns.map((column) => ({
158
+ accessor: column.id,
159
+ title: column.id,
160
+ sortable: true,
161
+ render: (row) => formatCell(row[column.id], column.data_type),
162
+ filtering: (filters[column.id] ?? []).length > 0,
163
+ filter: /* @__PURE__ */ jsx(ColumnFilter, {
164
+ resourceId,
165
+ tableName: table.name,
166
+ columnId: column.id,
167
+ selected: filters[column.id] ?? [],
168
+ onChange: (values) => {
169
+ setFilters((current) => ({
170
+ ...current,
171
+ [column.id]: values
172
+ }));
173
+ setPage(1);
174
+ }
175
+ })
176
+ })), [
177
+ resourceId,
178
+ table.name,
179
+ table.columns,
180
+ filters
181
+ ]);
182
+ const records = useMemo(() => (data?.response ?? []).map((row, index) => ({
183
+ ...row,
184
+ rowKey: (page - 1) * pageSize + index
185
+ })), [
186
+ data?.response,
187
+ page,
188
+ pageSize
189
+ ]);
190
+ if (isError) return /* @__PURE__ */ jsx(Center, {
191
+ h: "100%",
192
+ p: "md",
193
+ children: /* @__PURE__ */ jsx(Text, {
194
+ c: "dimmed",
195
+ children: "Could not load the table"
196
+ })
197
+ });
198
+ return /* @__PURE__ */ jsx(DataTable, {
199
+ height: "100%",
200
+ idAccessor: "rowKey",
201
+ records,
202
+ columns,
203
+ fetching: isFetching,
204
+ withTableBorder: true,
205
+ withColumnBorders: true,
206
+ sortStatus,
207
+ onSortStatusChange: (status) => {
208
+ setSortStatus(status);
209
+ setPage(1);
210
+ },
211
+ totalRecords: data?.total_items ?? 0,
212
+ recordsPerPage: pageSize,
213
+ page,
214
+ onPageChange: setPage,
215
+ recordsPerPageOptions: PAGE_SIZES,
216
+ onRecordsPerPageChange: (size) => {
217
+ setPageSize(size);
218
+ setPage(1);
219
+ }
220
+ });
221
+ };
222
+ const TableTabs = ({ resourceId, tables }) => {
223
+ const [activeTable, setActiveTable] = useState(tables[0]?.name ?? null);
224
+ const [searchOpened, { toggle: toggleSearch, close: closeSearch }] = useDisclosure(false);
225
+ return /* @__PURE__ */ jsxs(Tabs, {
226
+ keepMounted: false,
227
+ h: "100%",
228
+ style: {
229
+ display: "flex",
230
+ flexDirection: "column"
231
+ },
232
+ value: activeTable,
233
+ onChange: setActiveTable,
234
+ children: [tables.length > 1 && /* @__PURE__ */ jsxs(Group, {
235
+ wrap: "nowrap",
236
+ gap: "0",
237
+ style: { flexShrink: 0 },
238
+ children: [/* @__PURE__ */ jsxs(Popover, {
239
+ width: 300,
240
+ position: "bottom-start",
241
+ withArrow: true,
242
+ shadow: "md",
243
+ opened: searchOpened,
244
+ onChange: closeSearch,
245
+ trapFocus: true,
246
+ returnFocus: true,
247
+ children: [/* @__PURE__ */ jsx(Popover.Target, { children: /* @__PURE__ */ jsx(ActionIcon, {
248
+ size: "lg",
249
+ h: "100%",
250
+ onClick: toggleSearch,
251
+ "aria-label": "Search tables",
252
+ bdrs: 0,
253
+ children: /* @__PURE__ */ jsx(SearchIcon, { size: 16 })
254
+ }) }), /* @__PURE__ */ jsx(Popover.Dropdown, { children: /* @__PURE__ */ jsx(Autocomplete, {
255
+ data: tables.map(({ name }) => name),
256
+ "aria-label": "Table",
257
+ placeholder: "Search tables",
258
+ selectFirstOptionOnChange: true,
259
+ comboboxProps: { withinPortal: false },
260
+ onOptionSubmit: (name) => {
261
+ setActiveTable(name);
262
+ closeSearch();
263
+ }
264
+ }) })]
265
+ }), /* @__PURE__ */ jsx(Tabs.List, {
266
+ flex: 1,
267
+ miw: 0,
268
+ children: /* @__PURE__ */ jsx(Scroller, { children: tables.map(({ name }) => /* @__PURE__ */ jsx(Tabs.Tab, {
269
+ value: name,
270
+ children: name
271
+ }, name)) })
272
+ })]
273
+ }), tables.map((table) => /* @__PURE__ */ jsx(Tabs.Panel, {
274
+ value: table.name,
275
+ flex: 1,
276
+ mih: 0,
277
+ children: /* @__PURE__ */ jsx(TableRows, {
278
+ resourceId,
279
+ table
280
+ })
281
+ }, table.name))]
282
+ });
283
+ };
284
+ const TabularView = ({ resourceId }) => {
285
+ const { data: tables, isError, isPending } = useResourceTables(resourceId);
286
+ if (isError) return /* @__PURE__ */ jsx(Center, {
287
+ h: "100%",
288
+ p: "md",
289
+ children: /* @__PURE__ */ jsx(Text, {
290
+ c: "dimmed",
291
+ children: "Could not load the tables"
292
+ })
293
+ });
294
+ if (isPending) return /* @__PURE__ */ jsx(LoadingOverlay, { visible: true });
295
+ if (tables.length === 0) return /* @__PURE__ */ jsx(Center, {
296
+ h: "100%",
297
+ p: "md",
298
+ children: /* @__PURE__ */ jsx(Text, {
299
+ c: "dimmed",
300
+ children: "This resource has no tables"
301
+ })
302
+ });
303
+ return /* @__PURE__ */ jsx(TableTabs, {
304
+ resourceId,
305
+ tables
306
+ });
307
+ };
308
+ // src/components/ResourceView/Viewers/R4pm.tsx
18
309
  const r4pmViewer = (pick) => dynamic(async () => {
19
- const [components, { wasmLayout }] = await Promise.all([import("@r4pm/components"), import("@r4pm/components/rust-layout/wasm")]);
310
+ const [components, { wasmViz }] = await Promise.all([import("@r4pm/components"), import("@r4pm/components/viz/wasm")]);
20
311
  const { ViewerConfigProvider } = components;
21
312
  const Viewer = pick(components);
22
- const viewerConfig = { layout: wasmLayout };
313
+ const viewerConfig = { viz: wasmViz };
23
314
  return (props) => /* @__PURE__ */ jsx(ViewerConfigProvider, {
24
315
  value: viewerConfig,
25
316
  children: /* @__PURE__ */ jsx(Viewer, { ...props })
@@ -37,8 +328,7 @@ const R4pmViewerContainer = ({ filename, children }) => /* @__PURE__ */ jsx(Box,
37
328
  children
38
329
  })
39
330
  });
40
- //#endregion
41
- //#region src/components/ResourceView/Viewers/DFG.tsx
331
+ // src/components/ResourceView/Viewers/DFG.tsx
42
332
  const R4pmDfg = r4pmViewer((c) => c.DFGViewer);
43
333
  const R4pmOcdfg = r4pmViewer((c) => c.OCDFGViewer);
44
334
  const toR4pmDfg = ({ activities, directly_follows_relations, start_activities, end_activities }) => ({
@@ -58,20 +348,17 @@ const DFGViewer = ({ visualization }) => {
58
348
  });
59
349
  };
60
350
  const OCDFGViewer = ({ visualization }) => {
61
- const ocdfg = useMemo(() => ({
62
- object_type_to_dfg: Object.fromEntries(Object.entries(visualization.object_type_to_dfg ?? {}).map(([objectType, dfg]) => [objectType, toR4pmDfg(dfg)])),
63
- object_counts: visualization.object_counts ?? {}
64
- }), [visualization]);
351
+ const ocdfg = useMemo(() => ({ object_type_to_dfg: Object.fromEntries(Object.entries(visualization.object_type_to_dfg ?? {}).map(([objectType, dfg]) => [objectType, toR4pmDfg(dfg)])) }), [visualization]);
65
352
  return /* @__PURE__ */ jsx(R4pmViewerContainer, {
66
353
  filename: "oc-dfg",
67
354
  children: /* @__PURE__ */ jsx(R4pmOcdfg, {
68
355
  actions: [],
69
- data: ocdfg
356
+ data: ocdfg,
357
+ objectCounts: visualization.object_counts
70
358
  })
71
359
  });
72
360
  };
73
- //#endregion
74
- //#region src/components/ResourceView/Viewers/SVG.tsx
361
+ // src/components/ResourceView/Viewers/SVG.tsx
75
362
  const { saveAs: saveAs$2 } = FileSaver;
76
363
  const SvgPanWrapper = ({ children, onDownload }) => {
77
364
  return /* @__PURE__ */ jsx(Box, {
@@ -143,8 +430,7 @@ const SvgViewer = ({ visualization, isPreview }) => {
143
430
  children: content
144
431
  });
145
432
  };
146
- //#endregion
147
- //#region src/components/ResourceView/Viewers/Dot.tsx
433
+ // src/components/ResourceView/Viewers/Dot.tsx
148
434
  const { saveAs: saveAs$1 } = FileSaver;
149
435
  const DotToSvgViewer = ({ isPreview, visualization }) => {
150
436
  const [svg, setSvg] = useState(null);
@@ -216,8 +502,7 @@ const DotToSvgViewer = ({ isPreview, visualization }) => {
216
502
  children: content
217
503
  });
218
504
  };
219
- //#endregion
220
- //#region src/components/ResourceView/Viewers/GraphFlow/GraphControls.tsx
505
+ // src/components/ResourceView/Viewers/GraphFlow/GraphControls.tsx
221
506
  const GraphControls = ({ onFitView, onDownloadPng, onDownloadSvg, onDownloadPdf, menuItems, isPreview }) => {
222
507
  if (isPreview) return null;
223
508
  return /* @__PURE__ */ jsxs(Controls, {
@@ -261,8 +546,7 @@ const GraphControls = ({ onFitView, onDownloadPng, onDownloadSvg, onDownloadPdf,
261
546
  ]
262
547
  });
263
548
  };
264
- //#endregion
265
- //#region src/components/ResourceView/Viewers/GraphFlow/utils/bounds.ts
549
+ // src/components/ResourceView/Viewers/GraphFlow/utils/bounds.ts
266
550
  function nodeBoundsFromData(nodes) {
267
551
  if (nodes.length === 0) return {
268
552
  x: 0,
@@ -387,8 +671,7 @@ function getContentBounds(nodes, viewportEl, getNodesBounds) {
387
671
  }
388
672
  return combined;
389
673
  }
390
- //#endregion
391
- //#region src/components/ResourceView/Viewers/GraphFlow/utils/download.ts
674
+ // src/components/ResourceView/Viewers/GraphFlow/utils/download.ts
392
675
  const { saveAs } = FileSaver;
393
676
  const MAX_PX = 2048;
394
677
  const EXPORT_PADDING = .05;
@@ -452,8 +735,7 @@ async function downloadPdf(container, nodes, getNodesBounds) {
452
735
  pdf.addImage(dataUrl, "PNG", 0, 0, imageWidth, imageHeight);
453
736
  pdf.save("graph.pdf");
454
737
  }
455
- //#endregion
456
- //#region src/components/ResourceView/Viewers/GraphFlow/hooks/useGraphExport.ts
738
+ // src/components/ResourceView/Viewers/GraphFlow/hooks/useGraphExport.ts
457
739
  const useGraphExport = (wrapperRef) => {
458
740
  const { getNodes, getNodesBounds } = useReactFlow();
459
741
  return {
@@ -483,8 +765,7 @@ const useGraphExport = (wrapperRef) => {
483
765
  ])
484
766
  };
485
767
  };
486
- //#endregion
487
- //#region src/components/ResourceView/Viewers/GraphFlow/model/types.ts
768
+ // src/components/ResourceView/Viewers/GraphFlow/model/types.ts
488
769
  var GraphError = class extends Error {
489
770
  details;
490
771
  constructor(message, details) {
@@ -502,8 +783,7 @@ const DEFAULT_COLORS = {
502
783
  text: "#1a1a1a"
503
784
  };
504
785
  const FIT_VIEW_PADDING = .15;
505
- //#endregion
506
- //#region src/components/ResourceView/Viewers/GraphFlow/layout/elk.ts
786
+ // src/components/ResourceView/Viewers/GraphFlow/layout/elk.ts
507
787
  const EDGE_ROUTINGS = /* @__PURE__ */ new Set([
508
788
  "SPLINES",
509
789
  "ORTHOGONAL",
@@ -653,8 +933,7 @@ var ElkEngine = class ElkEngine {
653
933
  return routes;
654
934
  }
655
935
  };
656
- //#endregion
657
- //#region src/components/ResourceView/Viewers/GraphFlow/layout/graphviz.ts
936
+ // src/components/ResourceView/Viewers/GraphFlow/layout/graphviz.ts
658
937
  const GRAPHVIZ_DPI = 72;
659
938
  const parsePoint = (value) => {
660
939
  if (!value) return null;
@@ -822,8 +1101,7 @@ var GraphvizEngine = class GraphvizEngine {
822
1101
  return Object.entries(ranks).map(([rank, ids]) => `{ rank=${["source", "sink"].includes(rank) ? rank : "same"}; ${(ids ?? []).join(" ")} }`);
823
1102
  }
824
1103
  };
825
- //#endregion
826
- //#region src/components/ResourceView/Viewers/GraphFlow/layout/engine.ts
1104
+ // src/components/ResourceView/Viewers/GraphFlow/layout/engine.ts
827
1105
  const selectEngine = (visualization) => {
828
1106
  const config = visualization.layout_config;
829
1107
  switch (config?.type) {
@@ -839,8 +1117,7 @@ const selectEngine = (visualization) => {
839
1117
  default: throw new GraphError("Invalid graph layout config.", ["Expected an ELK or Graphviz layout config from the backend."]);
840
1118
  }
841
1119
  };
842
- //#endregion
843
- //#region src/components/ResourceView/Viewers/GraphFlow/model/buildModel.ts
1120
+ // src/components/ResourceView/Viewers/GraphFlow/model/buildModel.ts
844
1121
  const requireNodeId = (node, index) => {
845
1122
  if (!node.id) throw new GraphError("Invalid graph node.", [`Node at index ${index} is missing an id.`]);
846
1123
  return {
@@ -859,8 +1136,7 @@ const buildGraphModel = (visualization) => ({
859
1136
  nodes: (visualization.nodes ?? []).map(requireNodeId),
860
1137
  edges: (visualization.edges ?? []).map(requireEdgeId)
861
1138
  });
862
- //#endregion
863
- //#region src/components/ResourceView/Viewers/GraphFlow/render/routeToPath.ts
1139
+ // src/components/ResourceView/Viewers/GraphFlow/render/routeToPath.ts
864
1140
  const buildPolylinePath = (points) => {
865
1141
  if (points.length < 2) return null;
866
1142
  return points.map((point, index) => `${index === 0 ? "M" : "L"} ${point.x},${point.y}`).join(" ");
@@ -905,8 +1181,7 @@ const straightEdgeLayout = (source, target) => ({
905
1181
  endPoint: target,
906
1182
  labelPosition: midpoint(source, target)
907
1183
  });
908
- //#endregion
909
- //#region src/components/ResourceView/Viewers/GraphFlow/render/project.ts
1184
+ // src/components/ResourceView/Viewers/GraphFlow/render/project.ts
910
1185
  const projectToRenderModel = (model, layout) => {
911
1186
  const centers = nodeCenters(model.nodes, layout.positions);
912
1187
  return {
@@ -966,8 +1241,7 @@ const routeToEdgeLayout = (route) => {
966
1241
  labelPosition: route.labelPosition
967
1242
  };
968
1243
  };
969
- //#endregion
970
- //#region src/components/ResourceView/Viewers/GraphFlow/hooks/useGraphLayout.ts
1244
+ // src/components/ResourceView/Viewers/GraphFlow/hooks/useGraphLayout.ts
971
1245
  const prepare = (visualization) => {
972
1246
  try {
973
1247
  return {
@@ -1029,8 +1303,7 @@ const useGraphLayout = (visualization) => {
1029
1303
  onNodesChange
1030
1304
  };
1031
1305
  };
1032
- //#endregion
1033
- //#region src/components/ResourceView/Viewers/GraphFlow/render/edgeArrows.tsx
1306
+ // src/components/ResourceView/Viewers/GraphFlow/render/edgeArrows.tsx
1034
1307
  const colorToId = (color) => color.replace(/[^a-zA-Z0-9]/g, "");
1035
1308
  const ArrowMarker = ({ id, type, color, isStart }) => {
1036
1309
  if (!type) return null;
@@ -1197,8 +1470,7 @@ const getMarkerIds = ({ color, startArrow, endArrow }) => {
1197
1470
  endMarkerId: endArrow ? `arrow-end-${endArrow}-${colorKey}` : null
1198
1471
  };
1199
1472
  };
1200
- //#endregion
1201
- //#region src/components/ResourceView/Viewers/GraphFlow/render/annotation.tsx
1473
+ // src/components/ResourceView/Viewers/GraphFlow/render/annotation.tsx
1202
1474
  const AnnotationBadge = () => /* @__PURE__ */ jsx(Badge, {
1203
1475
  size: "xs",
1204
1476
  variant: "filled",
@@ -1258,8 +1530,7 @@ const NodeAnnotation = ({ annotation }) => {
1258
1530
  })]
1259
1531
  });
1260
1532
  };
1261
- //#endregion
1262
- //#region src/components/ResourceView/Viewers/GraphFlow/render/edgeLabels.tsx
1533
+ // src/components/ResourceView/Viewers/GraphFlow/render/edgeLabels.tsx
1263
1534
  const EdgeLabel = ({ color, label, hasAnnotation, x, y }) => /* @__PURE__ */ jsx(EdgeLabelRenderer, { children: /* @__PURE__ */ jsxs("div", {
1264
1535
  style: {
1265
1536
  position: "absolute",
@@ -1313,8 +1584,7 @@ const endLabelPositions = (start, end) => {
1313
1584
  }
1314
1585
  };
1315
1586
  };
1316
- //#endregion
1317
- //#region src/components/ResourceView/Viewers/GraphFlow/render/Edge.tsx
1587
+ // src/components/ResourceView/Viewers/GraphFlow/render/Edge.tsx
1318
1588
  const centerOf = ({ sourceX, sourceY, targetX, targetY }) => ({
1319
1589
  x: (sourceX + targetX) / 2,
1320
1590
  y: (sourceY + targetY) / 2
@@ -1428,8 +1698,7 @@ const GraphFlowEdge = memo((props) => {
1428
1698
  ] });
1429
1699
  });
1430
1700
  GraphFlowEdge.displayName = "GraphFlowEdge";
1431
- //#endregion
1432
- //#region src/components/ResourceView/Viewers/GraphFlow/render/nodeShapes.tsx
1701
+ // src/components/ResourceView/Viewers/GraphFlow/render/nodeShapes.tsx
1433
1702
  const InnerSymbol = ({ symbol, color }) => {
1434
1703
  if (symbol === "triangle") return /* @__PURE__ */ jsx("div", { style: {
1435
1704
  width: 0,
@@ -1559,8 +1828,7 @@ const BoxShape = ({ shape, color, borderColor, doubleBorder, innerSymbol, width,
1559
1828
  } })]
1560
1829
  });
1561
1830
  };
1562
- //#endregion
1563
- //#region src/components/ResourceView/Viewers/GraphFlow/render/Node.tsx
1831
+ // src/components/ResourceView/Viewers/GraphFlow/render/Node.tsx
1564
1832
  const HIDDEN_HANDLE_STYLE = {
1565
1833
  opacity: 0,
1566
1834
  pointerEvents: "none"
@@ -1656,8 +1924,7 @@ const GraphFlowNode = memo(({ data }) => {
1656
1924
  });
1657
1925
  });
1658
1926
  GraphFlowNode.displayName = "GraphFlowNode";
1659
- //#endregion
1660
- //#region src/components/ResourceView/Viewers/GraphFlow/index.tsx
1927
+ // src/components/ResourceView/Viewers/GraphFlow/index.tsx
1661
1928
  const nodeTypes = { node: GraphFlowNode };
1662
1929
  const edgeTypes = { graphflow: GraphFlowEdge };
1663
1930
  const GraphFlowCanvas = ({ visualization, isPreview, menuItems }) => {
@@ -1735,8 +2002,7 @@ const GraphFlowCanvas = ({ visualization, isPreview, menuItems }) => {
1735
2002
  })] });
1736
2003
  };
1737
2004
  const GraphFlow = (props) => /* @__PURE__ */ jsx(ReactFlowProvider, { children: /* @__PURE__ */ jsx(GraphFlowCanvas, { ...props }) });
1738
- //#endregion
1739
- //#region src/components/ResourceView/Viewers/Graph.tsx
2005
+ // src/components/ResourceView/Viewers/Graph.tsx
1740
2006
  const GraphViewer = (props) => /* @__PURE__ */ jsx(Box, {
1741
2007
  h: "100%",
1742
2008
  w: "100%",
@@ -1744,8 +2010,7 @@ const GraphViewer = (props) => /* @__PURE__ */ jsx(Box, {
1744
2010
  style: { overflow: "hidden" },
1745
2011
  children: /* @__PURE__ */ jsx(GraphFlow, { ...props })
1746
2012
  });
1747
- //#endregion
1748
- //#region src/components/ResourceView/Viewers/PetriNet.tsx
2013
+ // src/components/ResourceView/Viewers/PetriNet.tsx
1749
2014
  const R4pmOcpn = r4pmViewer((c) => c.ObjectCentricPetriNetViewer);
1750
2015
  const R4pmPetriNet = r4pmViewer((c) => c.PetriNetViewer);
1751
2016
  const toR4pmPetriNet = (visualization) => ({
@@ -1759,22 +2024,24 @@ const toR4pmPetriNet = (visualization) => ({
1759
2024
  final_marking: visualization.final_marking ?? null
1760
2025
  });
1761
2026
  const OCPetriNetViewer = ({ visualization }) => {
1762
- const ocpnData = useMemo(() => {
1763
- const places = visualization.places ?? [];
1764
- const placeInOutMult = Object.fromEntries(places.map(({ id }) => [id, [{}, {}]]));
1765
- for (const { source, target, variable } of visualization.arcs) {
1766
- if (!variable) continue;
1767
- const incoming = placeInOutMult[target];
1768
- if (incoming) incoming[0][source] = true;
1769
- const outgoing = placeInOutMult[source];
1770
- if (outgoing) outgoing[1][target] = true;
1771
- }
1772
- return {
1773
- petri_net: toR4pmPetriNet(visualization),
1774
- place_object_type: Object.fromEntries(places.map(({ id, object_type }) => [id, object_type])),
1775
- place_in_out_mult: placeInOutMult
1776
- };
1777
- }, [visualization]);
2027
+ const ocpnData = useMemo(() => ({
2028
+ places: (visualization.places ?? []).map(({ id, object_type }) => ({
2029
+ name: id,
2030
+ object_type
2031
+ })),
2032
+ transitions: (visualization.transitions ?? []).map(({ id, label }) => ({
2033
+ name: id,
2034
+ label
2035
+ })),
2036
+ arcs: visualization.arcs.map(({ source, target, weight, variable }) => ({
2037
+ source,
2038
+ target,
2039
+ type: variable ? "variable" : "normal",
2040
+ ...weight != null && { weight }
2041
+ })),
2042
+ initial_marking: visualization.initial_marking ?? {},
2043
+ final_marking: visualization.final_marking ?? {}
2044
+ }), [visualization]);
1778
2045
  return /* @__PURE__ */ jsx(R4pmViewerContainer, {
1779
2046
  filename: "oc-petri-net",
1780
2047
  children: /* @__PURE__ */ jsx(R4pmOcpn, { data: ocpnData })
@@ -1787,8 +2054,7 @@ const PetriNetViewer = ({ visualization }) => {
1787
2054
  children: /* @__PURE__ */ jsx(R4pmPetriNet, { data: petriNet })
1788
2055
  });
1789
2056
  };
1790
- //#endregion
1791
- //#region src/components/ResourceView/Viewers/Plotly.tsx
2057
+ // src/components/ResourceView/Viewers/Plotly.tsx
1792
2058
  const Plot = dynamic(() => import("react-plotly.js"), { ssr: false });
1793
2059
  const PlotlyViewer = ({ visualization, isPreview }) => {
1794
2060
  const { data, layout } = visualization.data;
@@ -1813,68 +2079,7 @@ const PlotlyViewer = ({ visualization, isPreview }) => {
1813
2079
  }
1814
2080
  });
1815
2081
  };
1816
- //#endregion
1817
- //#region src/util/dayjs.ts
1818
- dayjs.extend(isBetween);
1819
- var dayjs_default = dayjs;
1820
- const formatDateTime = (dateString) => dayjs(dateString).format("YYYY-MM-DD HH:mm");
1821
- const formatDate = (dateString) => dayjs(dateString).format("YYYY-MM-DD");
1822
- //#endregion
1823
- //#region src/components/ResourceView/Viewers/Table.tsx
1824
- const formatCell = (value, dataType) => {
1825
- if (value == null) return "";
1826
- switch (dataType) {
1827
- case "boolean": return value ? "✅" : "❌";
1828
- case "date": return dayjs_default(value).isValid() ? formatDate(value) : String(value);
1829
- case "datetime": return dayjs_default(value).isValid() ? formatDateTime(value) : String(value);
1830
- default: return String(value);
1831
- }
1832
- };
1833
- const PAGE_SIZES = [
1834
- 20,
1835
- 50,
1836
- 75
1837
- ];
1838
- const TableView = ({ visualization }) => {
1839
- const [pageSize, setPageSize] = useState(PAGE_SIZES[0]);
1840
- const columns = useMemo(() => visualization.columns.map((col) => ({
1841
- accessor: col.id,
1842
- title: col.label ?? col.id,
1843
- render: (record) => formatCell(record[col.id], col.data_type)
1844
- })), [visualization.columns]);
1845
- const [page, setPage] = useState(1);
1846
- const [records, setRecords] = useState(visualization.rows.slice(0, pageSize));
1847
- useEffect(() => {
1848
- const from = (page - 1) * pageSize;
1849
- const to = from + pageSize;
1850
- setRecords(visualization.rows.slice(from, to));
1851
- }, [
1852
- page,
1853
- pageSize,
1854
- visualization
1855
- ]);
1856
- const paginationProps = visualization.rows.length > PAGE_SIZES[0] ? {
1857
- totalRecords: visualization.rows.length,
1858
- recordsPerPage: pageSize,
1859
- onPageChange: (p) => setPage(p),
1860
- page,
1861
- recordsPerPageOptions: [...PAGE_SIZES],
1862
- onRecordsPerPageChange: (newPageSize) => {
1863
- setPageSize(newPageSize);
1864
- setPage(1);
1865
- }
1866
- } : {};
1867
- return /* @__PURE__ */ jsx(DataTable, {
1868
- records,
1869
- columns,
1870
- withTableBorder: true,
1871
- withColumnBorders: true,
1872
- withRowBorders: true,
1873
- ...paginationProps
1874
- });
1875
- };
1876
- //#endregion
1877
- //#region src/components/ResourceView/index.tsx
2082
+ // src/components/ResourceView/index.tsx
1878
2083
  const visualizationMap = {
1879
2084
  table: TableView,
1880
2085
  svg: SvgViewer,
@@ -1894,34 +2099,72 @@ const Visualization = ({ visualization, isPreview = false, menuItems }) => {
1894
2099
  ...menuItems && { menuItems }
1895
2100
  });
1896
2101
  };
1897
- const ResourceViewer = ({ id, isPreview = false }) => {
1898
- const { data } = useResource(id);
1899
- if (!data) return /* @__PURE__ */ jsx(LoadingOverlay, {});
1900
- if (!data.visualization?.type) return /* @__PURE__ */ jsx(Stack, {
1901
- justify: "center",
2102
+ const LoadError = () => /* @__PURE__ */ jsx(Center, {
2103
+ h: "100%",
2104
+ p: "md",
2105
+ children: /* @__PURE__ */ jsx(Text, {
2106
+ c: "dimmed",
2107
+ children: "Could not load the visualization"
2108
+ })
2109
+ });
2110
+ const NoVisualization = ({ resourceTypeLabel }) => /* @__PURE__ */ jsx(Center, {
2111
+ h: "100%",
2112
+ p: "md",
2113
+ children: /* @__PURE__ */ jsxs(Stack, {
1902
2114
  align: "center",
1903
- h: "100%",
1904
- children: /* @__PURE__ */ jsx(ThemeIcon, {
1905
- w: 150,
1906
- h: 150,
1907
- variant: "transparent",
1908
- color: "gray",
1909
- children: /* @__PURE__ */ jsx(EyeOffIcon, {
1910
- width: 150,
1911
- height: 150
2115
+ gap: "xs",
2116
+ children: [
2117
+ /* @__PURE__ */ jsx(EyeOffIcon, {
2118
+ size: 64,
2119
+ strokeWidth: 1.5,
2120
+ color: "var(--mantine-color-dimmed)"
2121
+ }),
2122
+ /* @__PURE__ */ jsx(Text, {
2123
+ fw: 500,
2124
+ children: "No visualization available"
2125
+ }),
2126
+ /* @__PURE__ */ jsxs(Group, {
2127
+ gap: 6,
2128
+ justify: "center",
2129
+ children: [/* @__PURE__ */ jsx(Badge, {
2130
+ size: "sm",
2131
+ color: "gray",
2132
+ children: resourceTypeLabel
2133
+ }), /* @__PURE__ */ jsx(Text, {
2134
+ size: "sm",
2135
+ c: "dimmed",
2136
+ children: "does not provide a visualization"
2137
+ })]
1912
2138
  })
1913
- })
1914
- });
2139
+ ]
2140
+ })
2141
+ });
2142
+ const ResourceVisualization = ({ id, resourceTypeLabel, isPreview }) => {
2143
+ const { data, isError, isPending } = useResourceVisualization(id);
2144
+ if (isError) return /* @__PURE__ */ jsx(LoadError, {});
2145
+ if (isPending) return /* @__PURE__ */ jsx(LoadingOverlay, { visible: true });
2146
+ if (!data) return /* @__PURE__ */ jsx(NoVisualization, { resourceTypeLabel });
1915
2147
  return /* @__PURE__ */ jsx(Visualization, {
1916
- visualization: data.visualization,
2148
+ visualization: data,
1917
2149
  isPreview
1918
2150
  });
1919
2151
  };
1920
- //#endregion
1921
- //#region src/components/ResourceModal/ResourceModal.tsx
2152
+ const ResourceViewer = ({ id, isPreview = false }) => {
2153
+ const { data: resource, isError, isPending } = useResource(id);
2154
+ if (isError) return /* @__PURE__ */ jsx(LoadError, {});
2155
+ if (isPending) return /* @__PURE__ */ jsx(LoadingOverlay, { visible: true });
2156
+ if (resource.has_visualization) return /* @__PURE__ */ jsx(ResourceVisualization, {
2157
+ id,
2158
+ resourceTypeLabel: resource.resource_type_label,
2159
+ isPreview
2160
+ });
2161
+ if (resource.kind === "tabular") return /* @__PURE__ */ jsx(TabularView, { resourceId: id });
2162
+ return /* @__PURE__ */ jsx(NoVisualization, { resourceTypeLabel: resource.resource_type_label });
2163
+ };
2164
+ // src/components/ResourceModal/ResourceModal.tsx
1922
2165
  const ResourceModal = ({ id, onClose }) => {
1923
2166
  const { data } = useResource(id, { query: { enabled: !!id } });
1924
- return data?.resource.id && /* @__PURE__ */ jsx(Modal, {
2167
+ return data?.id && /* @__PURE__ */ jsx(Modal, {
1925
2168
  opened: !!data,
1926
2169
  onClose,
1927
2170
  fullScreen: true,
@@ -1942,7 +2185,7 @@ const ResourceModal = ({ id, onClose }) => {
1942
2185
  justify: "space-between",
1943
2186
  children: [/* @__PURE__ */ jsx(Title, {
1944
2187
  size: "h5",
1945
- children: data.resource.name
2188
+ children: data.name
1946
2189
  }), /* @__PURE__ */ jsx(ActionIcon, {
1947
2190
  variant: "subtle",
1948
2191
  color: "red",
@@ -1954,22 +2197,92 @@ const ResourceModal = ({ id, onClose }) => {
1954
2197
  h: "100%",
1955
2198
  flex: 1,
1956
2199
  mih: 0,
1957
- children: /* @__PURE__ */ jsx(ResourceViewer, { id: data.resource.id })
2200
+ children: /* @__PURE__ */ jsx(ResourceViewer, { id: data.id })
1958
2201
  })]
1959
2202
  })
1960
2203
  });
1961
2204
  };
1962
- //#endregion
1963
- //#region src/components/ResourceSelect/ResourceSelect.tsx
1964
- const ResourceSelect = ({ type, value, ...props }) => {
2205
+ // src/components/ResourceSelect/ResourceSelect.tsx
2206
+ const useResourceOptions = (type, onUploaded) => {
1965
2207
  const { data: resources = [] } = useResources({ schema_hash: type ?? null });
1966
- return /* @__PURE__ */ jsx(Select, {
1967
- ...props,
1968
- data: resources.map(({ name, id }) => ({
2208
+ const [pendingTaskIds, setPendingTaskIds] = useState([]);
2209
+ const options = useMemo(() => resources.map(({ name, id }) => ({
2210
+ value: id,
2211
+ label: name
2212
+ })), [resources]);
2213
+ const handleUploaded = useEffectEvent(onUploaded);
2214
+ useEffect(() => {
2215
+ const uploaded = resources.filter(({ source_id }) => source_id && pendingTaskIds.includes(source_id));
2216
+ if (!uploaded.length) return;
2217
+ setPendingTaskIds((taskIds) => taskIds.filter((taskId) => !uploaded.some(({ source_id }) => source_id === taskId)));
2218
+ handleUploaded(uploaded.map(({ id, name }) => ({
1969
2219
  value: id,
1970
2220
  label: name
1971
- }))
2221
+ })));
2222
+ }, [resources, pendingTaskIds]);
2223
+ const trackUpload = (taskIds) => setPendingTaskIds((pending) => [...pending, ...taskIds]);
2224
+ return {
2225
+ options,
2226
+ trackUpload
2227
+ };
2228
+ };
2229
+ const UploadButton = ({ disabled, onUpload }) => {
2230
+ const { mutate: upload, isPending } = useUpload({ mutation: { onSuccess: onUpload } });
2231
+ return /* @__PURE__ */ jsx(FileButton, {
2232
+ accept: ".ocelescope",
2233
+ multiple: true,
2234
+ onChange: (files) => {
2235
+ if (files.length) upload({ data: { files } });
2236
+ },
2237
+ children: (props) => /* @__PURE__ */ jsx(Tooltip, {
2238
+ label: "Upload resource",
2239
+ withArrow: true,
2240
+ children: /* @__PURE__ */ jsx(ActionIcon, {
2241
+ ...props,
2242
+ size: "input-sm",
2243
+ loading: isPending,
2244
+ disabled,
2245
+ "aria-label": "Upload resource",
2246
+ children: /* @__PURE__ */ jsx(UploadIcon, { size: 16 })
2247
+ })
2248
+ })
2249
+ });
2250
+ };
2251
+ const ViewButton = ({ resourceId, onView }) => /* @__PURE__ */ jsx(Tooltip, {
2252
+ label: resourceId ? "View resource" : "Select a resource to view it",
2253
+ withArrow: true,
2254
+ children: /* @__PURE__ */ jsx(ActionIcon, {
2255
+ variant: "default",
2256
+ size: "input-sm",
2257
+ "data-disabled": !resourceId || void 0,
2258
+ "aria-disabled": !resourceId,
2259
+ onClick: resourceId ? () => onView(resourceId) : void 0,
2260
+ "aria-label": "View resource",
2261
+ children: /* @__PURE__ */ jsx(EyeIcon, { size: 16 })
2262
+ })
2263
+ });
2264
+ const ResourceSelect = (props) => {
2265
+ const { type, withUpload = true, withView = true, ...selectProps } = props;
2266
+ const [viewedId, setViewedId] = useState();
2267
+ const { options, trackUpload } = useResourceOptions(type, (uploaded) => {
2268
+ if (props.multiple) props.onChange([.../* @__PURE__ */ new Set([...props.value, ...uploaded.map(({ value }) => value)])]);
2269
+ else if (uploaded[0]) props.onChange(uploaded[0].value, uploaded[0]);
1972
2270
  });
2271
+ const viewId = props.multiple ? null : props.value;
2272
+ const showView = withView && !props.multiple;
2273
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(ActionSelect, {
2274
+ ...selectProps,
2275
+ data: options,
2276
+ actions: (showView || withUpload) && /* @__PURE__ */ jsxs(Fragment, { children: [showView && /* @__PURE__ */ jsx(ViewButton, {
2277
+ resourceId: viewId,
2278
+ onView: setViewedId
2279
+ }), withUpload && /* @__PURE__ */ jsx(UploadButton, {
2280
+ disabled: props.disabled,
2281
+ onUpload: trackUpload
2282
+ })] })
2283
+ }), viewedId && /* @__PURE__ */ jsx(ResourceModal, {
2284
+ id: viewedId,
2285
+ onClose: () => setViewedId(void 0)
2286
+ })] });
1973
2287
  };
1974
- //#endregion
1975
- export { ResourceModal, ResourceSelect, ResourceViewer, Visualization };
2288
+ export { ActionSelect, ResourceModal, ResourceSelect, ResourceViewer, Visualization };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ocelescope/resources",
3
3
  "type": "module",
4
- "version": "0.10.2",
4
+ "version": "0.12.0",
5
5
  "description": "Ocelescope resources: helpers and UI components for rendering and exporting data.",
6
6
  "author": "Görkem-Emre Öztürk <goerkem.oeztuerk@rwth-aachen.de>",
7
7
  "license": "MIT",
@@ -28,29 +28,30 @@
28
28
  },
29
29
  "peerDependencies": {
30
30
  "@floating-ui/react": "^0.27.18",
31
- "@hpcc-js/wasm-graphviz": "^1.21.0",
32
- "@mantine/core": "^9.7.2",
33
- "@ocelescope/api-base": "^0.10.2",
34
- "@r4pm/components": "^0.3.2",
35
- "@xyflow/react": "^12.11.3",
31
+ "@hpcc-js/wasm-graphviz": "^1.30.0",
32
+ "@mantine/core": "^9.7.4",
33
+ "@mantine/hooks": "^9.7.4",
34
+ "@ocelescope/api-base": "^0.12.0",
35
+ "@r4pm/components": "^0.4.0",
36
+ "@xyflow/react": "^12.12.0",
36
37
  "dayjs": "^1.11.23",
37
38
  "elkjs": "^0.12.0",
38
39
  "file-saver": "^2.0.5",
39
- "lucide-react": "^1.56.0",
40
+ "lucide-react": "^1.63.0",
40
41
  "mantine-datatable": "^9.4.0",
41
- "next": "16.4.0",
42
- "react": "^19.3.0",
43
- "react-dom": "^19.3.0",
42
+ "next": "16.4.3",
43
+ "react": "^19.3.1",
44
+ "react-dom": "^19.3.1",
44
45
  "react-plotly.js": "^4.0.0",
45
46
  "react-zoom-pan-pinch": "^4.0.0"
46
47
  },
47
48
  "devDependencies": {
48
- "@tsdown/css": "^0.23.1",
49
+ "@tsdown/css": "^0.23.3",
49
50
  "@types/file-saver": "^2.0.7",
50
- "@types/node": "^26.6.1",
51
+ "@types/node": "^26.6.5",
51
52
  "@types/react": "^19.3.0",
52
53
  "@types/react-dom": "^19.3.0",
53
- "tsdown": "^0.23.1",
54
+ "tsdown": "^0.23.3",
54
55
  "typescript": "^6.0.3"
55
56
  },
56
57
  "dependencies": {