@ocelescope/ocelot 0.0.0 → 0.1.3

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.
package/README.md CHANGED
@@ -1,29 +1,47 @@
1
- # react-components-starter
1
+ # @ocelescope/ocelot
2
2
 
3
- A starter for creating a React component library.
3
+ The **Ocelot** module for [Ocelescope](https://github.com/promi4s/ocelescope).
4
4
 
5
- ## Development
5
+ A tool for exploring object-centric event logs, allowing you to search events and objects and visualize their relationships and attributes.
6
6
 
7
- - Install dependencies:
7
+ It is a frontend module that plugs into the Ocelescope app shell via
8
+ `@ocelescope/core`'s `defineModule`.
8
9
 
9
- ```bash
10
- npm install
11
- ```
10
+ It pairs with the [`ocelescope-module-ocelot`](https://pypi.org/project/ocelescope-module-ocelot/)
11
+ backend module, which provides its API.
12
12
 
13
- - Run the playground:
13
+ ## Installation
14
14
 
15
15
  ```bash
16
- npm run play
16
+ pnpm add @ocelescope/ocelot
17
17
  ```
18
18
 
19
- - Run the unit tests:
19
+ ## Integration
20
20
 
21
- ```bash
22
- npm run test
21
+ Register the module in your `ocelescope.config.ts` by adding its default
22
+ export to the `modules` array:
23
+
24
+ ```ts
25
+ // ocelescope.config.ts
26
+ import type { OcelescopeConfig } from "@ocelescope/core";
27
+ import ocelot from "@ocelescope/ocelot";
28
+
29
+ export default {
30
+ modules: [ocelot],
31
+ } satisfies OcelescopeConfig;
23
32
  ```
24
33
 
25
- - Build the library:
34
+ This module ships its own styles, so also import them once in your app
35
+ entry point (`pages/_app.tsx`):
26
36
 
27
- ```bash
28
- npm run build
37
+ ```tsx
38
+ import "@ocelescope/ocelot/styles.css";
29
39
  ```
40
+
41
+ ## About
42
+
43
+ Part of [Ocelescope](https://github.com/promi4s/ocelescope), a framework for
44
+ working with Object-Centric Event Logs (OCEL) developed at the Chair of Process
45
+ and Data Science (PADS), RWTH Aachen University.
46
+
47
+ 📖 Documentation: <https://www.ocelescope.org>
package/dist/index.d.ts CHANGED
@@ -1,6 +1,4 @@
1
- import * as _ocelescope_core0 from "@ocelescope/core";
2
-
3
1
  //#region src/config.d.ts
4
- declare const _default: _ocelescope_core0.ModuleDefinition;
2
+ declare const _default: import("@ocelescope/core").ModuleDefinition;
5
3
  //#endregion
6
4
  export { _default as default };
package/dist/index.js CHANGED
@@ -1,56 +1,345 @@
1
1
  import { defineModule, defineModuleRoute, useCurrentOcel } from "@ocelescope/core";
2
- import { ActionIcon, Box, Button, Divider, Flex, Group, Input, LoadingOverlay, ScrollArea, SegmentedControl, SimpleGrid, Stack, Table, Tabs, Text } from "@mantine/core";
3
- import { useE2o, useEventAttributes, useEventCounts, useO2o, useObjectAttributes, useObjectCounts, useOcelotPaginatedEvents, useOcelotPaginatedObjects } from "@ocelescope/api-base";
4
- import { keepPreviousData } from "@tanstack/react-query";
5
- import { memo, useCallback, useEffect, useMemo, useState } from "react";
6
- import { DataTable } from "mantine-datatable";
7
2
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import { ActionIcon, Box, Button, Divider, Flex, Group, Input, LoadingOverlay, ScrollArea, SegmentedControl, SimpleGrid, Stack, Table, Tabs, Text, Title } from "@mantine/core";
8
4
  import { useDebouncedState, useScrollIntoView } from "@mantine/hooks";
5
+ import { useE2o, useEventAttributes, useEventCounts, useO2o, useObjectAttributes, useObjectCounts } from "@ocelescope/api-base";
9
6
  import { ChevronLeftIcon, ChevronRightIcon, DownloadIcon, SearchIcon } from "lucide-react";
7
+ import { memo, useCallback, useEffect, useMemo, useState } from "react";
8
+ import { keepPreviousData, useQuery } from "@tanstack/react-query";
9
+ import { customFetch } from "@ocelescope/api-client";
10
+ import { DataTable } from "mantine-datatable";
10
11
  import { BaseEdge, Controls, EdgeLabelRenderer, Handle, MarkerType, Position, ReactFlow, ReactFlowProvider, applyNodeChanges, getSmoothStepPath, getStraightPath, useEdgesState, useInternalNode, useReactFlow } from "@xyflow/react";
11
- import { saveAs } from "file-saver";
12
+ import FileSaver from "file-saver";
12
13
  import { toPng } from "html-to-image";
13
14
  import dagre from "@dagrejs/dagre";
14
15
  import ELK from "elkjs/lib/elk.bundled.js";
15
-
16
- //#region src/components/EntityTable.tsx
17
- const EntityTable = ({ entities, withTimestamp, attributes = [], relations = [], onPageChange, onPageSizeChange, sortStatus, onStartStatusChange }) => {
18
- const columns = useMemo(() => [
19
- {
20
- accessor: "id",
21
- title: "#",
22
- sortable: true
16
+ //#region src/components/OcelotIcon.tsx
17
+ const OcelotIcon = (props) => /* @__PURE__ */ jsxs("svg", {
18
+ xmlns: "http://www.w3.org/2000/svg",
19
+ width: 128,
20
+ height: 128,
21
+ viewBox: "0 0 96 96",
22
+ ...props,
23
+ fill: "currentColor",
24
+ children: [
25
+ /* @__PURE__ */ jsx("title", { children: "Ocelot" }),
26
+ /* @__PURE__ */ jsx("path", { d: "M2.5 8.2c-2.2 5.6-2.3 18-.2 23 .9 2.1 2.7 5.3 4.1 7.1C8.2 40.6 8.6 42 8 43c-2 3.2-1.1 9.1 2.4 14.8 1.9 3.2 4 8.4 4.6 11.7 1.6 8 2.9 9.9 9.4 12.8 3 1.4 7.1 4.2 9.1 6.1l3.6 3.6h21.8l3.6-3.6c2-1.9 6-4.7 8.9-6 3-1.4 5.9-3.1 6.6-3.9.6-.8 2-4.9 3.1-9.1 1.1-4.3 3.3-9.9 4.9-12.4 3.1-4.8 4-10.9 2-14-.6-1-.2-2.4 1.6-4.7 1.4-1.8 3.2-5 4.1-7.1 2.1-5 2-17.4-.2-23C91.8 4.1 91.7 4 87 4c-5.6 0-12 2.1-17.3 5.6-3.9 2.5-3.9 2.5-7.5.7-2.9-1.4-6-1.8-14.2-1.8s-11.3.4-14.2 1.8c-3.6 1.8-3.6 1.8-7.5-.7C21 6.1 14.6 4 9 4c-4.7 0-4.8.1-6.5 4.2zM19 11.1c2.5 1.1 6.1 3.3 8.2 4.9 3.2 2.6 3.8 2.8 4.9 1.4 2.9-3.5 7.3-4.8 15.9-4.8 6.9 0 9.3.4 12.8 2.2 2.3 1.2 4.2 2.7 4.2 3.3 0 .5 1.7-.4 3.8-2 4.3-3.5 11.1-6.7 16.3-7.6 3.6-.7 3.7-.6 4.9 3.1 3 8.9.5 19.7-5.9 25.8l-2.9 2.8 1.9 3.2c2.5 4.2 2.4 6.5-.6 10.7-1.4 1.9-3.3 5.8-4.1 8.6-.9 2.9-1.8 5.3-2.1 5.3-.9 0 .6-8.1 2.8-14.6 1.9-5.6 1.9-6.3.5-9.7-1.6-4-2.7-4.5-4.6-2.2-1 1.2-1 1.8 0 3 1.3 1.6 1.1 3.8-1.5 12.5-.9 3.3-1.4 8.3-1.3 12.5l.3 7-4.9 2.8c-2.7 1.5-5.1 2.5-5.4 2.2-.2-.2.7-1.8 2.2-3.5 2.2-2.7 2.6-4.1 2.6-9.5 0-7.6-.9-10.1-5.5-16.2-4.5-5.8-4.6-8.1-.5-7.5 1.9.3 4.3-.4 6.6-1.7 2-1.2 3.9-1.9 4.2-1.7.5.6 3.1-2.4 3.2-3.5 0-1.1-7.9-3.9-11.1-3.9-7.1 0-11.8 5.6-10.5 12.5.4 1.9 2.3 5.6 4.3 8.2 5.5 7.2 6.6 17.9 2.2 21.9-1.4 1.3-2.6 1.4-5.6.7-3.5-.8-3.8-1.1-4.1-4.8-.3-3.7 0-4.1 2.8-5.2 2.3-.9 3-1.7 3-3.9 0-2.5-.1-2.6-1.7-1.2-2.2 1.8-10.4 1.8-12.6-.1-1.5-1.2-1.7-1-1.7 1.4 0 2.1.7 2.9 3 3.8 2.8 1.1 3.1 1.5 2.8 5.2-.3 3.7-.6 4-4.1 4.8-3.3.8-4.2.6-5.9-1.1-1.7-1.7-2.1-3.2-2-8.8.1-4.3.7-7.4 1.7-8.8 5.1-6.9 7.5-11.3 7.5-13.7C43 38.5 38.5 34 32.1 34 28.9 34 21 36.8 21 37.9c.1 1.1 2.7 4.1 3.2 3.5.3-.2 2.2.5 4.2 1.7 2.3 1.3 4.7 2 6.6 1.7 4.1-.6 4 1.7-.5 7.5-4.6 6.1-5.5 8.6-5.5 16.2 0 5.4.4 6.8 2.6 9.5 1.5 1.7 2.4 3.3 2.2 3.5-.3.3-2.7-.7-5.4-2.2l-4.9-2.8.3-7.7c.2-5.6-.2-9.2-1.8-13.7-2.3-6.9-2.5-9.2-.8-10.9.8-.8.8-1.5-.2-2.7-1.9-2.3-3-1.8-4.6 2.2-1.4 3.4-1.4 4.1.5 9.7 2.2 6.5 3.7 14.6 2.8 14.6-.3 0-1.2-2.4-2.1-5.3-.8-2.8-2.7-6.7-4.1-8.6-3-4.2-3.1-6.5-.6-10.7l1.9-3.2-2.9-2.8C5.5 31.3 3 20.5 6 11.6c1.2-3.7 1.3-3.8 4.9-3.1 2 .4 5.6 1.5 8.1 2.6zm39.2 72.8C60.6 86.3 56.3 88 48 88c-12.3 0-15-4.2-4.2-6.5 5.1-1.1 12.2 0 14.4 2.4z" }),
27
+ /* @__PURE__ */ jsx("path", { d: "M8.6 15.1c-1.3 6.8.1 13.2 4 17.9l2.6 3 2.7-4.2c1.5-2.4 4.3-5.8 6.1-7.7 3.3-3.2 3.3-3.4 1.4-4.8-2.5-1.9-13.6-7.3-15-7.3-.6 0-1.4 1.4-1.8 3.1zm8.9 4.1c3.1 1.4 3.1 2.5.2 6.2-2.8 3.4-4.4 2.9-5.3-1.9-1-5.3.4-6.5 5.1-4.3zM78.5 14.9c-3.3 1.6-6.9 3.6-7.9 4.4-1.9 1.4-1.9 1.6 1.4 4.8 1.8 1.9 4.6 5.3 6.1 7.7l2.7 4.2 2.6-3c2.5-3.1 4.6-8.7 4.6-12.6 0-4-1.2-8.4-2.4-8.4-.6 0-3.8 1.3-7.1 2.9zm5.2 7.2c-.8 6.1-2.3 7-5.3 3.4-1.3-1.7-2.4-3.5-2.4-4.1 0-1.3 3.7-3.2 6.4-3.3 1.6-.1 1.8.4 1.3 4z" })
28
+ ]
29
+ });
30
+ //#endregion
31
+ //#region src/components/EntityCard.tsx
32
+ const EntityCard = ({ name, count, attributeSummaries = [], relationSummaries = [], maw }) => {
33
+ return /* @__PURE__ */ jsxs(Flex, {
34
+ w: "100%",
35
+ bd: "1px solid black",
36
+ bg: "white",
37
+ miw: 200,
38
+ maw,
39
+ mih: 100,
40
+ direction: "column",
41
+ children: [
42
+ /* @__PURE__ */ jsx(Text, {
43
+ fw: 700,
44
+ size: "sm",
45
+ ta: "center",
46
+ py: "4",
47
+ px: "xs",
48
+ style: { wordBreak: "break-word" },
49
+ children: `${name} (${count})`
50
+ }),
51
+ /* @__PURE__ */ jsx(Divider, {
52
+ c: "black",
53
+ size: "md"
54
+ }),
55
+ attributeSummaries.length !== 0 && /* @__PURE__ */ jsxs(Table, {
56
+ withRowBorders: false,
57
+ captionSide: "top",
58
+ layout: "fixed",
59
+ children: [/* @__PURE__ */ jsx(Table.Caption, {
60
+ mb: 0,
61
+ children: "Attributes"
62
+ }), /* @__PURE__ */ jsx(Table.Tbody, { children: attributeSummaries.map((attribute) => /* @__PURE__ */ jsxs(Table.Tr, { children: [/* @__PURE__ */ jsx(Table.Td, {
63
+ style: { wordBreak: "break-word" },
64
+ children: attribute.name
65
+ }), /* @__PURE__ */ jsx(Table.Td, {
66
+ ta: "end",
67
+ style: { wordBreak: "break-word" },
68
+ children: attribute.type
69
+ })] }, attribute.name)) })]
70
+ }),
71
+ relationSummaries.length !== 0 && /* @__PURE__ */ jsxs(Table, {
72
+ withRowBorders: false,
73
+ captionSide: "top",
74
+ layout: "fixed",
75
+ children: [/* @__PURE__ */ jsx(Table.Caption, {
76
+ mb: 0,
77
+ children: "Relations"
78
+ }), /* @__PURE__ */ jsx(Table.Tbody, { children: relationSummaries.map(({ target, qualifier, min_count, max_count }) => /* @__PURE__ */ jsxs(Table.Tr, { children: [
79
+ /* @__PURE__ */ jsx(Table.Td, {
80
+ style: { wordBreak: "break-word" },
81
+ children: target
82
+ }),
83
+ /* @__PURE__ */ jsx(Table.Td, {
84
+ style: { wordBreak: "break-word" },
85
+ children: qualifier ?? "None"
86
+ }),
87
+ /* @__PURE__ */ jsx(Table.Td, {
88
+ ta: "end",
89
+ w: 70,
90
+ style: { whiteSpace: "nowrap" },
91
+ children: min_count < max_count ? `${min_count}-${max_count}` : min_count
92
+ })
93
+ ] }, `${target}-${qualifier}`)) })]
94
+ })
95
+ ]
96
+ });
97
+ };
98
+ //#endregion
99
+ //#region src/components/EntityOverview.tsx
100
+ const EntityOverview = ({ attributes, relations, entityCounts, search = "" }) => {
101
+ const relationMap = useMemo(() => {
102
+ return relations.reduce((relationMap, currentRelation) => {
103
+ if (currentRelation.source in relationMap) relationMap[currentRelation.source]?.push(currentRelation);
104
+ else relationMap[currentRelation.source] = [currentRelation];
105
+ return relationMap;
106
+ }, {});
107
+ }, [relations]);
108
+ return /* @__PURE__ */ jsx(SimpleGrid, {
109
+ cols: {
110
+ base: 1,
111
+ sm: 2,
112
+ md: 4
23
113
  },
24
- ...withTimestamp ? [{
25
- accessor: "timestamp",
26
- title: "date",
27
- sortable: true
28
- }] : [],
29
- ...attributes.map(({ attribute }) => ({
30
- accessor: attribute,
31
- sortable: true
32
- })),
33
- ...relations.map(({ qualifier, target }) => ({
34
- accessor: `${qualifier}::${target}`,
35
- title: `${qualifier} (${target})`
36
- }))
37
- ], [
38
- withTimestamp,
39
- attributes,
40
- relations
41
- ]);
114
+ children: useMemo(() => {
115
+ const toSearch = search.toLowerCase();
116
+ return Object.entries(entityCounts).filter(([event, _]) => event.toLowerCase().includes(search.toLowerCase()) || relationMap[event]?.some(({ target, qualifier }) => target.toLowerCase().includes(toSearch) || qualifier.toLowerCase().includes(toSearch)) || attributes?.some(({ name, entity_type }) => event === entity_type && name.toLowerCase().includes(toSearch)));
117
+ }, [
118
+ search,
119
+ relationMap,
120
+ entityCounts,
121
+ attributes
122
+ ]).map(([name, count]) => {
123
+ return /* @__PURE__ */ jsx(EntityCard, {
124
+ count,
125
+ name,
126
+ attributeSummaries: attributes.filter(({ entity_type }) => entity_type === name) ?? [],
127
+ relationSummaries: relationMap[name] ?? []
128
+ }, name);
129
+ })
130
+ });
131
+ };
132
+ //#endregion
133
+ //#region src/routes/eventOverview.tsx
134
+ const EventOverview = () => {
135
+ const { id } = useCurrentOcel();
136
+ const { data: eventsAttributes = [] } = useEventAttributes(id);
137
+ const { data: e2o } = useE2o(id);
138
+ const { data: eventCounts, isLoading: isEventCountsLoading } = useEventCounts(id);
139
+ const [searchValue, setSearchValue] = useDebouncedState("", 200);
140
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(LoadingOverlay, { visible: isEventCountsLoading }), /* @__PURE__ */ jsxs(Stack, { children: [
141
+ /* @__PURE__ */ jsx(Title, {
142
+ order: 2,
143
+ children: "Event Overview"
144
+ }),
145
+ /* @__PURE__ */ jsx(Text, {
146
+ c: "dimmed",
147
+ size: "sm",
148
+ children: "Get an overview of all event types in this log. Search through them and see how often each type occurs, what attributes it carries, and which objects it has a relation with."
149
+ }),
150
+ /* @__PURE__ */ jsx(Input, {
151
+ leftSection: /* @__PURE__ */ jsx(SearchIcon, {}),
152
+ defaultValue: searchValue,
153
+ onChange: (newSearch) => setSearchValue(newSearch.target.value)
154
+ }),
155
+ eventCounts && /* @__PURE__ */ jsx(EntityOverview, {
156
+ relations: e2o?.response ?? [],
157
+ entityCounts: eventCounts,
158
+ attributes: eventsAttributes,
159
+ search: searchValue
160
+ })
161
+ ] })] });
162
+ };
163
+ var eventOverview_default = defineModuleRoute({
164
+ component: EventOverview,
165
+ label: "Event Overview",
166
+ name: "eventOverview",
167
+ requiresOcel: true
168
+ });
169
+ //#endregion
170
+ //#region src/lib/fetcher.ts
171
+ const customFetch$1 = async (config, options) => customFetch(config, options);
172
+ //#endregion
173
+ //#region src/api/base.ts
174
+ /**
175
+ * Generated by orval v8.19.0 🍺
176
+ * Do not edit manually.
177
+ * Ocelot
178
+ * OpenAPI spec version: 1.0
179
+ */
180
+ const withQueryKey = (query, queryKey) => {
181
+ const result = { queryKey };
182
+ for (const key of Object.keys(query)) {
183
+ if (key === "queryKey") continue;
184
+ Object.defineProperty(result, key, {
185
+ enumerable: true,
186
+ configurable: true,
187
+ get: () => query[key]
188
+ });
189
+ }
190
+ return result;
191
+ };
192
+ /**
193
+ * @summary Get Events
194
+ */
195
+ const paginatedEvents = (ocelId, params, options, signal) => {
196
+ return customFetch$1({
197
+ url: `/api/external/modules/ocelot/v1/${ocelId}/events`,
198
+ method: "GET",
199
+ params,
200
+ signal
201
+ }, options);
202
+ };
203
+ const getPaginatedEventsQueryKey = (ocelId, params) => {
204
+ return [`/api/external/modules/ocelot/v1/${ocelId}/events`, ...params ? [params] : []];
205
+ };
206
+ const getPaginatedEventsQueryOptions = (ocelId, params, options) => {
207
+ const { query: queryOptions, request: requestOptions } = options ?? {};
208
+ const queryKey = queryOptions?.queryKey ?? getPaginatedEventsQueryKey(ocelId, params);
209
+ const queryFn = ({ signal }) => paginatedEvents(ocelId, params, requestOptions, signal);
210
+ return {
211
+ queryKey,
212
+ queryFn,
213
+ enabled: ocelId !== null && ocelId !== void 0,
214
+ staleTime: 3e5,
215
+ ...queryOptions
216
+ };
217
+ };
218
+ /**
219
+ * @summary Get Events
220
+ */
221
+ function usePaginatedEvents(ocelId, params, options, queryClient) {
222
+ const queryOptions = getPaginatedEventsQueryOptions(ocelId, params, options);
223
+ return withQueryKey(useQuery(queryOptions, queryClient), queryOptions.queryKey);
224
+ }
225
+ /**
226
+ * @summary Get Objects
227
+ */
228
+ const paginatedObjects = (ocelId, params, options, signal) => {
229
+ return customFetch$1({
230
+ url: `/api/external/modules/ocelot/v1/${ocelId}/objects`,
231
+ method: "GET",
232
+ params,
233
+ signal
234
+ }, options);
235
+ };
236
+ const getPaginatedObjectsQueryKey = (ocelId, params) => {
237
+ return [`/api/external/modules/ocelot/v1/${ocelId}/objects`, ...params ? [params] : []];
238
+ };
239
+ const getPaginatedObjectsQueryOptions = (ocelId, params, options) => {
240
+ const { query: queryOptions, request: requestOptions } = options ?? {};
241
+ const queryKey = queryOptions?.queryKey ?? getPaginatedObjectsQueryKey(ocelId, params);
242
+ const queryFn = ({ signal }) => paginatedObjects(ocelId, params, requestOptions, signal);
243
+ return {
244
+ queryKey,
245
+ queryFn,
246
+ enabled: ocelId !== null && ocelId !== void 0,
247
+ staleTime: 3e5,
248
+ ...queryOptions
249
+ };
250
+ };
251
+ /**
252
+ * @summary Get Objects
253
+ */
254
+ function usePaginatedObjects(ocelId, params, options, queryClient) {
255
+ const queryOptions = getPaginatedObjectsQueryOptions(ocelId, params, options);
256
+ return withQueryKey(useQuery(queryOptions, queryClient), queryOptions.queryKey);
257
+ }
258
+ /**
259
+ * @summary Get Object Columns
260
+ */
261
+ const objectColumns = (ocelId, params, options, signal) => {
262
+ return customFetch$1({
263
+ url: `/api/external/modules/ocelot/v1/${ocelId}/objects/columns`,
264
+ method: "GET",
265
+ params,
266
+ signal
267
+ }, options);
268
+ };
269
+ const getObjectColumnsQueryKey = (ocelId, params) => {
270
+ return [`/api/external/modules/ocelot/v1/${ocelId}/objects/columns`, ...params ? [params] : []];
271
+ };
272
+ const getObjectColumnsQueryOptions = (ocelId, params, options) => {
273
+ const { query: queryOptions, request: requestOptions } = options ?? {};
274
+ const queryKey = queryOptions?.queryKey ?? getObjectColumnsQueryKey(ocelId, params);
275
+ const queryFn = ({ signal }) => objectColumns(ocelId, params, requestOptions, signal);
276
+ return {
277
+ queryKey,
278
+ queryFn,
279
+ enabled: ocelId !== null && ocelId !== void 0,
280
+ staleTime: 3e5,
281
+ ...queryOptions
282
+ };
283
+ };
284
+ /**
285
+ * @summary Get Object Columns
286
+ */
287
+ function useObjectColumns(ocelId, params, options, queryClient) {
288
+ const queryOptions = getObjectColumnsQueryOptions(ocelId, params, options);
289
+ return withQueryKey(useQuery(queryOptions, queryClient), queryOptions.queryKey);
290
+ }
291
+ /**
292
+ * @summary Get Activity Columns
293
+ */
294
+ const activityColumns = (ocelId, params, options, signal) => {
295
+ return customFetch$1({
296
+ url: `/api/external/modules/ocelot/v1/${ocelId}/events/columns`,
297
+ method: "GET",
298
+ params,
299
+ signal
300
+ }, options);
301
+ };
302
+ const getActivityColumnsQueryKey = (ocelId, params) => {
303
+ return [`/api/external/modules/ocelot/v1/${ocelId}/events/columns`, ...params ? [params] : []];
304
+ };
305
+ const getActivityColumnsQueryOptions = (ocelId, params, options) => {
306
+ const { query: queryOptions, request: requestOptions } = options ?? {};
307
+ const queryKey = queryOptions?.queryKey ?? getActivityColumnsQueryKey(ocelId, params);
308
+ const queryFn = ({ signal }) => activityColumns(ocelId, params, requestOptions, signal);
309
+ return {
310
+ queryKey,
311
+ queryFn,
312
+ enabled: ocelId !== null && ocelId !== void 0,
313
+ staleTime: 3e5,
314
+ ...queryOptions
315
+ };
316
+ };
317
+ /**
318
+ * @summary Get Activity Columns
319
+ */
320
+ function useActivityColumns(ocelId, params, options, queryClient) {
321
+ const queryOptions = getActivityColumnsQueryOptions(ocelId, params, options);
322
+ return withQueryKey(useQuery(queryOptions, queryClient), queryOptions.queryKey);
323
+ }
324
+ //#endregion
325
+ //#region src/components/EntityTable.tsx
326
+ const EntityTable = ({ entities, columns, onPageChange, onPageSizeChange, sortStatus, onStartStatusChange }) => {
42
327
  const records = useMemo(() => entities.items.map((entity) => ({
43
328
  ...entity,
44
329
  ...entity.attributes,
45
330
  ...Object.assign({}, ...Object.entries(entity.relations).map(([qualifierName, entityIds]) => ({ [qualifierName]: entityIds.join(", ") })))
46
331
  })), [entities]);
332
+ const transformedColumns = useMemo(() => columns.map((column) => ({
333
+ ...column,
334
+ sortable: column.type === "attribute"
335
+ })), [columns]);
47
336
  return /* @__PURE__ */ jsx(DataTable, {
48
337
  page: entities.page,
49
338
  totalRecords: entities.total_items,
50
339
  recordsPerPage: entities.page_size,
51
340
  onPageChange,
52
341
  withColumnBorders: true,
53
- columns,
342
+ columns: transformedColumns,
54
343
  records,
55
344
  recordsPerPageOptions: [
56
345
  20,
@@ -65,8 +354,6 @@ const EntityTable = ({ entities, withTimestamp, attributes = [], relations = [],
65
354
  onSortStatusChange: onStartStatusChange
66
355
  });
67
356
  };
68
- var EntityTable_default = EntityTable;
69
-
70
357
  //#endregion
71
358
  //#region src/components/SingleLineTabs/SingleLineTabs.tsx
72
359
  const SingleLineTabs = ({ setCurrentTab, currentTab, tabs }) => {
@@ -79,7 +366,7 @@ const SingleLineTabs = ({ setCurrentTab, currentTab, tabs }) => {
79
366
  setCurrentTab(newTab);
80
367
  scrollIntoView({ alignment: "center" });
81
368
  }, [scrollIntoView, setCurrentTab]);
82
- return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs(Flex, {
369
+ return /* @__PURE__ */ jsxs(Flex, {
83
370
  align: "center",
84
371
  justify: "center",
85
372
  children: [
@@ -125,29 +412,20 @@ const SingleLineTabs = ({ setCurrentTab, currentTab, tabs }) => {
125
412
  children: /* @__PURE__ */ jsx(ChevronRightIcon, {})
126
413
  })
127
414
  ]
128
- }) });
415
+ });
129
416
  };
130
- var SingleLineTabs_default = SingleLineTabs;
131
-
132
417
  //#endregion
133
418
  //#region src/components/EntityPage.tsx
134
- const EntityPage = ({ type }) => {
135
- const { id } = useCurrentOcel();
419
+ const EntityPage = ({ ocelId, type, title, description }) => {
136
420
  const areEntitiesEvents = type === "events";
137
- const { data: entityCounts } = (areEntitiesEvents ? useEventCounts : useObjectCounts)({ ocel_id: id });
138
- const { data: attributes } = (areEntitiesEvents ? useEventAttributes : useObjectAttributes)({ ocel_id: id });
139
- const [currentTab, setCurrentTab] = useState("");
421
+ const { data: entityCounts } = (areEntitiesEvents ? useEventCounts : useObjectCounts)(ocelId);
422
+ const [currentTab, setCurrentTab] = useState(null);
140
423
  const [page, setPage] = useState(1);
141
424
  const [sort, setSort] = useState(void 0);
142
425
  const [pageSize, setPageSize] = useState(20);
143
426
  const entityNames = useMemo(() => Object.keys(entityCounts ?? {}), [entityCounts]);
144
- const { data: unfilteredRelations = [] } = (areEntitiesEvents ? useE2o : useO2o)({ ocel_id: id });
145
- const relations = useMemo(() => {
146
- return unfilteredRelations.filter(({ source }) => source === currentTab);
147
- }, [unfilteredRelations, currentTab]);
148
- const { data: entities } = (areEntitiesEvents ? useOcelotPaginatedEvents : useOcelotPaginatedObjects)({
149
- ocel_id: id,
150
- type: currentTab,
427
+ const { data: entities } = (areEntitiesEvents ? usePaginatedEvents : usePaginatedObjects)(ocelId, {
428
+ type: currentTab ?? "",
151
429
  page_size: pageSize,
152
430
  page,
153
431
  ...sort && {
@@ -155,9 +433,11 @@ const EntityPage = ({ type }) => {
155
433
  ascending: sort.direction === "asc"
156
434
  }
157
435
  }, { query: {
436
+ enabled: !!currentTab,
158
437
  placeholderData: keepPreviousData,
159
438
  staleTime: 5e3
160
439
  } });
440
+ const { data } = (areEntitiesEvents ? useActivityColumns : useObjectColumns)(ocelId, { type_name: currentTab ?? "" }, { query: { enabled: !!currentTab } });
161
441
  useEffect(() => {
162
442
  if (!currentTab && entityNames.length > 0) setCurrentTab(entityNames[0]);
163
443
  }, [currentTab, entityNames]);
@@ -165,172 +445,58 @@ const EntityPage = ({ type }) => {
165
445
  return /* @__PURE__ */ jsxs(Flex, {
166
446
  direction: "column",
167
447
  h: "100%",
168
- children: [/* @__PURE__ */ jsx(SingleLineTabs_default, {
169
- tabs: Object.entries(entityCounts ?? {}).map(([entityName, count]) => ({
170
- value: entityName,
171
- label: `${entityName} (${count})`
172
- })),
173
- setCurrentTab: (newTab) => {
174
- setCurrentTab(newTab);
175
- setPage(1);
176
- setSort(void 0);
177
- },
178
- currentTab: currentTab ?? entityNames[0]
179
- }), entities && /* @__PURE__ */ jsx(EntityTable_default, {
180
- entities,
181
- attributes: attributes?.[currentTab ?? entityNames[0]],
182
- withTimestamp: type === "events",
183
- onPageChange: (newPage) => setPage(newPage),
184
- onPageSizeChange: (newPageSize) => setPageSize(newPageSize),
185
- relations,
186
- sortStatus: sort,
187
- onStartStatusChange: (sortStatus) => setSort(sortStatus)
188
- })]
189
- });
190
- };
191
- var EntityPage_default = EntityPage;
192
-
193
- //#endregion
194
- //#region src/routes/events.tsx
195
- const EventPage = () => /* @__PURE__ */ jsx(EntityPage_default, { type: "events" });
196
- var events_default = defineModuleRoute({
197
- component: EventPage,
198
- label: "Events",
199
- name: "events",
200
- requiresOcel: true
201
- });
202
-
203
- //#endregion
204
- //#region src/routes/objects.tsx
205
- const ObjectPage = () => /* @__PURE__ */ jsx(EntityPage_default, { type: "objects" });
206
- var objects_default = defineModuleRoute({
207
- component: ObjectPage,
208
- label: "Objects",
209
- name: "objects",
210
- requiresOcel: true
211
- });
212
-
213
- //#endregion
214
- //#region src/components/EntityCard.tsx
215
- const EntityCard = ({ name, count, attributeSummaries = [], relationSummaries = [] }) => {
216
- return /* @__PURE__ */ jsxs(Flex, {
217
- w: "100%",
218
- bd: "1px solid black",
219
- bg: "white",
220
- miw: 200,
221
- mih: 100,
222
- direction: "column",
223
448
  children: [
224
- /* @__PURE__ */ jsx(Text, {
225
- fw: 700,
226
- size: "sm",
227
- ta: "center",
228
- py: "4",
229
- children: `${name} (${count})`
449
+ title && /* @__PURE__ */ jsx(Title, {
450
+ order: 2,
451
+ children: title
230
452
  }),
231
- /* @__PURE__ */ jsx(Divider, {
232
- c: "black",
233
- size: "md"
453
+ description && /* @__PURE__ */ jsx(Text, {
454
+ c: "dimmed",
455
+ size: "sm",
456
+ mb: "xs",
457
+ children: description
234
458
  }),
235
- attributeSummaries.length !== 0 && /* @__PURE__ */ jsxs(Table, {
236
- withRowBorders: false,
237
- captionSide: "top",
238
- style: {
239
- overflow: "hidden",
240
- textOverflow: "ellipsis"
459
+ /* @__PURE__ */ jsx(SingleLineTabs, {
460
+ tabs: Object.entries(entityCounts ?? {}).map(([entityName, count]) => ({
461
+ value: entityName,
462
+ label: `${entityName} (${count})`
463
+ })),
464
+ setCurrentTab: (newTab) => {
465
+ setCurrentTab(newTab);
466
+ setPage(1);
467
+ setSort(void 0);
241
468
  },
242
- children: [/* @__PURE__ */ jsx(Table.Caption, {
243
- mb: 0,
244
- children: "Attributes"
245
- }), /* @__PURE__ */ jsx(Table.Tbody, { children: attributeSummaries.map((attribute) => /* @__PURE__ */ jsxs(Table.Tr, { children: [/* @__PURE__ */ jsxs(Table.Td, { children: [" ", attribute.attribute] }), /* @__PURE__ */ jsx(Table.Td, {
246
- ta: "end",
247
- children: attribute.type
248
- })] }, attribute.attribute)) })]
469
+ currentTab: currentTab ?? entityNames[0] ?? ""
249
470
  }),
250
- relationSummaries.length !== 0 && /* @__PURE__ */ jsxs(Table, {
251
- withRowBorders: false,
252
- captionSide: "top",
253
- style: {
254
- overflow: "hidden",
255
- textOverflow: "ellipsis"
256
- },
257
- children: [/* @__PURE__ */ jsx(Table.Caption, {
258
- mb: 0,
259
- children: "Relations"
260
- }), /* @__PURE__ */ jsx(Table.Tbody, { children: relationSummaries.map(({ target, qualifier, min_count, max_count }) => /* @__PURE__ */ jsxs(Table.Tr, { children: [
261
- /* @__PURE__ */ jsx(Table.Td, { children: target }),
262
- /* @__PURE__ */ jsx(Table.Td, { children: qualifier ?? "None" }),
263
- /* @__PURE__ */ jsx(Table.Td, { children: min_count < max_count ? `${min_count}-${max_count}` : min_count })
264
- ] }, `${target}-${qualifier}`)) })]
471
+ entities && /* @__PURE__ */ jsx(EntityTable, {
472
+ entities,
473
+ columns: data ?? [],
474
+ withTimestamp: type === "events",
475
+ onPageChange: (newPage) => setPage(newPage),
476
+ onPageSizeChange: (newPageSize) => setPageSize(newPageSize),
477
+ sortStatus: sort,
478
+ onStartStatusChange: (sortStatus) => setSort(sortStatus)
265
479
  })
266
480
  ]
267
481
  });
268
482
  };
269
- var EntityCard_default = EntityCard;
270
-
271
- //#endregion
272
- //#region src/components/EntityOverview.tsx
273
- const EntityOverview = ({ attributes, relations, entityCounts, search = "" }) => {
274
- const relationMap = useMemo(() => {
275
- return relations.reduce((relationMap$1, currentRelation) => {
276
- if (currentRelation.source in relationMap$1) relationMap$1[currentRelation.source]?.push(currentRelation);
277
- else relationMap$1[currentRelation.source] = [currentRelation];
278
- return relationMap$1;
279
- }, {});
280
- }, [relations]);
281
- return /* @__PURE__ */ jsx(SimpleGrid, {
282
- cols: {
283
- base: 1,
284
- sm: 2,
285
- md: 4,
286
- lg: 5
287
- },
288
- children: useMemo(() => {
289
- const toSearch = search.toLowerCase();
290
- return Object.entries(entityCounts).filter(([event, _]) => event.toLowerCase().includes(search.toLowerCase()) || relationMap[event]?.some(({ target, qualifier }) => target.toLowerCase().includes(toSearch) || qualifier.toLowerCase().includes(toSearch)) || attributes[event]?.some(({ attribute }) => attribute.toLowerCase().includes(toSearch)));
291
- }, [
292
- search,
293
- relationMap,
294
- entityCounts,
295
- attributes
296
- ]).map(([name, count]) => {
297
- return /* @__PURE__ */ jsx(EntityCard_default, {
298
- count,
299
- name,
300
- attributeSummaries: attributes[name] ?? [],
301
- relationSummaries: relationMap[name] ?? []
302
- }, name);
303
- })
304
- });
305
- };
306
- var EntityOverview_default = EntityOverview;
307
-
308
483
  //#endregion
309
- //#region src/routes/eventOverview.tsx
310
- const EventOverview = () => {
484
+ //#region src/routes/events.tsx
485
+ const EventPage = () => {
311
486
  const { id } = useCurrentOcel();
312
- const { data: eventsAttributes = {} } = useEventAttributes({ ocel_id: id });
313
- const { data: e2o = [] } = useE2o({ ocel_id: id });
314
- const { data: eventCounts, isLoading: isEventCountsLoading } = useEventCounts({ ocel_id: id });
315
- const [searchValue, setSearchValue] = useDebouncedState("", 200);
316
- return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(LoadingOverlay, { visible: isEventCountsLoading }), /* @__PURE__ */ jsxs(Stack, { children: [/* @__PURE__ */ jsx(Input, {
317
- leftSection: /* @__PURE__ */ jsx(SearchIcon, {}),
318
- defaultValue: searchValue,
319
- onChange: (newSearch) => setSearchValue(newSearch.target.value)
320
- }), eventCounts && /* @__PURE__ */ jsx(EntityOverview_default, {
321
- relations: e2o,
322
- entityCounts: eventCounts,
323
- attributes: eventsAttributes,
324
- search: searchValue
325
- })] })] });
487
+ return /* @__PURE__ */ jsx(EntityPage, {
488
+ ocelId: id ?? "",
489
+ type: "events",
490
+ title: "Event Inspector",
491
+ description: "Browse the individual events in this log. Pick an event type to see its records in a table, with their attributes and the objects they have a relation with."
492
+ }, id);
326
493
  };
327
- var eventOverview_default = defineModuleRoute({
328
- component: EventOverview,
329
- label: "Event Overview",
330
- name: "eventOverview",
494
+ var events_default = defineModuleRoute({
495
+ component: EventPage,
496
+ label: "Events",
497
+ name: "events",
331
498
  requiresOcel: true
332
499
  });
333
-
334
500
  //#endregion
335
501
  //#region src/components/Graph/util/getEdgeParams.tsx
336
502
  const getRectangleIntersection = (targetNode, sourceNode) => {
@@ -404,7 +570,6 @@ function getEdgeParams(source, target) {
404
570
  targetPos
405
571
  };
406
572
  }
407
-
408
573
  //#endregion
409
574
  //#region src/components/Graph/edges/BaseEdge.tsx
410
575
  const EdgeLabel = ({ transform, label }) => {
@@ -422,7 +587,7 @@ const EdgeLabel = ({ transform, label }) => {
422
587
  children: label
423
588
  });
424
589
  };
425
- const customMarkes = ["url('#double-rect')", "url('#rect')"];
590
+ const customMarkers = ["url('#double-rect')", "url('#rect')"];
426
591
  const BaseEdge$1 = ({ labels = [], markerEnd, path, ...rest }) => {
427
592
  return /* @__PURE__ */ jsxs(Fragment, { children: [
428
593
  /* @__PURE__ */ jsx("svg", {
@@ -521,14 +686,12 @@ const BaseEdge$1 = ({ labels = [], markerEnd, path, ...rest }) => {
521
686
  }),
522
687
  /* @__PURE__ */ jsx(BaseEdge, {
523
688
  path,
524
- markerEnd: customMarkes.includes(markerEnd ?? "") ? markerEnd?.replace("rect", "rect-end") : markerEnd,
689
+ markerEnd: customMarkers.includes(markerEnd ?? "") ? markerEnd?.replace("rect", "rect-end") : markerEnd,
525
690
  ...rest
526
691
  }),
527
692
  /* @__PURE__ */ jsx(EdgeLabelRenderer, { children: labels.map((props, index) => /* @__PURE__ */ jsx(EdgeLabel, { ...props }, index)) })
528
693
  ] });
529
694
  };
530
- var BaseEdge_default = BaseEdge$1;
531
-
532
695
  //#endregion
533
696
  //#region src/components/Graph/edges/FloatingEdge.tsx
534
697
  const FloatingEdge = ({ data, source, target, ...props }) => {
@@ -543,17 +706,15 @@ const FloatingEdge = ({ data, source, target, ...props }) => {
543
706
  targetY: ty
544
707
  });
545
708
  const angle = Math.atan2((sy > ty ? -1 : 1) * offsetY, offsetX) * (180 / Math.PI);
546
- return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(BaseEdge_default, {
709
+ return /* @__PURE__ */ jsx(BaseEdge$1, {
547
710
  path: edgePath,
548
711
  ...props,
549
712
  labels: data?.mid ? [{
550
713
  transform: `translate(-50% , -50%) translate(${labelX}px, ${labelY}px) rotate(${angle}deg)`,
551
714
  label: data.mid
552
715
  }] : []
553
- }) });
716
+ });
554
717
  };
555
- var FloatingEdge_default = FloatingEdge;
556
-
557
718
  //#endregion
558
719
  //#region src/components/Graph/edges/LoopEdge.tsx
559
720
  const LoopingEdge = ({ data, source, ...props }) => {
@@ -573,7 +734,7 @@ const LoopingEdge = ({ data, source, ...props }) => {
573
734
  targetPosition: Position.Top,
574
735
  offset: (data?.offset ?? 0) * 15
575
736
  });
576
- return /* @__PURE__ */ jsx(BaseEdge_default, {
737
+ return /* @__PURE__ */ jsx(BaseEdge$1, {
577
738
  path: edgePath,
578
739
  ...props,
579
740
  labels: data?.mid ? [{
@@ -582,8 +743,6 @@ const LoopingEdge = ({ data, source, ...props }) => {
582
743
  }] : []
583
744
  });
584
745
  };
585
- var LoopEdge_default = LoopingEdge;
586
-
587
746
  //#endregion
588
747
  //#region src/components/Graph/layout/dagre.ts
589
748
  const useDagreLayout = () => {
@@ -617,7 +776,6 @@ const useDagreLayout = () => {
617
776
  fitView
618
777
  ]) };
619
778
  };
620
-
621
779
  //#endregion
622
780
  //#region src/components/Graph/layout/elk.ts
623
781
  const elk = new ELK();
@@ -635,7 +793,7 @@ const useElkLayout = () => {
635
793
  "elk.edgeRouting": "ORTHOGONAL",
636
794
  "elk.layered.nodePlacement.strategy": "NETWORK_SIMPLEX"
637
795
  };
638
- return { layout: useCallback(async (options) => {
796
+ return { layout: useCallback(async (_options) => {
639
797
  const nodes = getNodes();
640
798
  const edges = getEdges();
641
799
  const graph = {
@@ -654,7 +812,7 @@ const useElkLayout = () => {
654
812
  id: edge.id,
655
813
  sources: [edge.source],
656
814
  targets: [edge.target],
657
- layoutOptions: edge?.data?.["mid"] ? { "elk.edge.minimalLength": edge.data["mid"].toString() } : void 0
815
+ layoutOptions: edge?.data?.mid ? { "elk.edge.minimalLength": edge.data.mid.toString() } : void 0
658
816
  }))
659
817
  };
660
818
  try {
@@ -685,7 +843,7 @@ const useElkLayout = () => {
685
843
  };
686
844
  }));
687
845
  fitView();
688
- } catch (error) {}
846
+ } catch (_error) {}
689
847
  }, [
690
848
  setEdges,
691
849
  setNodes,
@@ -694,7 +852,6 @@ const useElkLayout = () => {
694
852
  fitView
695
853
  ]) };
696
854
  };
697
-
698
855
  //#endregion
699
856
  //#region src/components/Graph/nodes/CircleNode.tsx
700
857
  const CircleNode = memo(({ data: { color, label, inner, diameter = 50 } }) => {
@@ -737,8 +894,6 @@ const CircleNode = memo(({ data: { color, label, inner, diameter = 50 } }) => {
737
894
  })
738
895
  ] });
739
896
  });
740
- var CircleNode_default = CircleNode;
741
-
742
897
  //#endregion
743
898
  //#region src/components/Graph/nodes/RectangleNode.tsx
744
899
  var RectangleNode_default = memo(({ data: { color, label, inner } }) => {
@@ -780,21 +935,15 @@ var RectangleNode_default = memo(({ data: { color, label, inner } }) => {
780
935
  })
781
936
  ] });
782
937
  });
783
-
784
- //#endregion
785
- //#region src/components/Graph/Graph.module.css?css_module
786
- const classes = { "test": "_79UKFW_test" };
787
- var Graph_module_default = classes;
788
- const _test0 = classes["test"];
789
-
790
938
  //#endregion
791
939
  //#region src/components/Graph/index.tsx
940
+ const { saveAs } = FileSaver;
792
941
  const edgeTypes = {
793
- floating: FloatingEdge_default,
794
- looping: LoopEdge_default
942
+ floating: FloatingEdge,
943
+ looping: LoopingEdge
795
944
  };
796
945
  const nodeTypes = {
797
- circle: CircleNode_default,
946
+ circle: CircleNode,
798
947
  rectangle: RectangleNode_default
799
948
  };
800
949
  const layoutToHook = {
@@ -829,15 +978,35 @@ const InnerFlow = ({ initialNodes, initialEdges, layoutOptions = { type: "dagre"
829
978
  } }
830
979
  };
831
980
  }));
981
+ useEffect(() => {
982
+ setNodes((prev) => {
983
+ const prevById = new Map(prev.map((node) => [node.id, node]));
984
+ return initialNodes.map((node) => {
985
+ const existing = prevById.get(node.id);
986
+ if (existing) return {
987
+ ...existing,
988
+ data: node.data
989
+ };
990
+ return {
991
+ ...node,
992
+ type: node.data.type,
993
+ position: {
994
+ x: 0,
995
+ y: 0
996
+ }
997
+ };
998
+ });
999
+ });
1000
+ }, [initialNodes]);
832
1001
  const onNodesChange = useCallback((changes) => {
833
1002
  const positionChange = changes.filter((change) => change.type === "position");
834
1003
  if (positionChange.length > 0) {
835
1004
  const movedNodes = positionChange.map((change) => change.id);
836
- setEdges((edges$1) => edges$1.map((edge) => ({
1005
+ setEdges((edges) => edges.map((edge) => ({
837
1006
  ...edge,
838
1007
  data: {
839
1008
  ...edge.data,
840
- position: movedNodes.includes(edge.target) || movedNodes.includes(edge.source) ? void 0 : edge.data?.["position"]
1009
+ position: movedNodes.includes(edge.target) || movedNodes.includes(edge.source) ? void 0 : edge.data?.position
841
1010
  }
842
1011
  })));
843
1012
  }
@@ -853,7 +1022,6 @@ const InnerFlow = ({ initialNodes, initialEdges, layoutOptions = { type: "dagre"
853
1022
  hasMeasuredNodes
854
1023
  ]);
855
1024
  return /* @__PURE__ */ jsx(ReactFlow, {
856
- className: Graph_module_default["test"],
857
1025
  style: { height: "100%" },
858
1026
  nodes,
859
1027
  edges,
@@ -870,9 +1038,8 @@ const InnerFlow = ({ initialNodes, initialEdges, layoutOptions = { type: "dagre"
870
1038
  children: /* @__PURE__ */ jsx(ActionIcon, {
871
1039
  variant: "transparent",
872
1040
  onClick: () => handleDownload("ocelot"),
873
- className: "test",
874
1041
  children: /* @__PURE__ */ jsx(DownloadIcon, {
875
- className: "test",
1042
+ color: "black",
876
1043
  size: 18
877
1044
  })
878
1045
  })
@@ -880,27 +1047,26 @@ const InnerFlow = ({ initialNodes, initialEdges, layoutOptions = { type: "dagre"
880
1047
  });
881
1048
  };
882
1049
  const Graph = (props) => /* @__PURE__ */ jsx(ReactFlowProvider, { children: /* @__PURE__ */ jsx(InnerFlow, { ...props }) });
883
- var Graph_default = Graph;
884
-
885
1050
  //#endregion
886
1051
  //#region src/routes/objectOverview.tsx
887
1052
  const ObjectGraph = () => {
888
1053
  const { id: ocelId } = useCurrentOcel();
889
- const { data: o2o } = useO2o({ ocel_id: ocelId });
890
- const { data: objectAttributes } = useObjectAttributes({ ocel_id: ocelId });
891
- const { data: objectCounts } = useObjectCounts({ ocel_id: ocelId });
1054
+ const { data: o2o } = useO2o(ocelId);
1055
+ const { data: objectAttributes = [] } = useObjectAttributes(ocelId);
1056
+ const { data: objectCounts } = useObjectCounts(ocelId);
892
1057
  const [searchValue, setSearchValue] = useDebouncedState("", 200);
893
- const [vizualization, setVizualization] = useState("graph");
1058
+ const [visualization, setVisualization] = useState("graph");
894
1059
  const nodes = useMemo(() => {
895
1060
  if (!objectCounts || !objectAttributes) return [];
896
1061
  return Object.entries(objectCounts).map(([objectName, count]) => ({
897
1062
  id: objectName,
898
1063
  data: {
899
1064
  type: "rectangle",
900
- inner: /* @__PURE__ */ jsx(EntityCard_default, {
1065
+ inner: /* @__PURE__ */ jsx(EntityCard, {
901
1066
  count,
902
1067
  name: objectName,
903
- attributeSummaries: objectAttributes[objectName]
1068
+ maw: 300,
1069
+ attributeSummaries: objectAttributes.filter(({ entity_type }) => entity_type === objectName)
904
1070
  }, objectName)
905
1071
  }
906
1072
  }));
@@ -909,15 +1075,24 @@ const ObjectGraph = () => {
909
1075
  w: "100%",
910
1076
  h: "100%",
911
1077
  children: [
1078
+ /* @__PURE__ */ jsx(Title, {
1079
+ order: 2,
1080
+ children: "Object Overview"
1081
+ }),
1082
+ /* @__PURE__ */ jsx(Text, {
1083
+ c: "dimmed",
1084
+ size: "sm",
1085
+ children: "Get an overview of all object types in this log. Switch between an interactive graph and a card grid to see how many objects of each type exist, what attributes they have, and how they relate to one another."
1086
+ }),
912
1087
  /* @__PURE__ */ jsxs(Group, {
913
1088
  justify: "end",
914
- children: [vizualization === "cards" && /* @__PURE__ */ jsx(Input, {
1089
+ children: [visualization === "cards" && /* @__PURE__ */ jsx(Input, {
915
1090
  leftSection: /* @__PURE__ */ jsx(SearchIcon, {}),
916
1091
  defaultValue: searchValue,
917
1092
  onChange: (newSearch) => setSearchValue(newSearch.target.value)
918
1093
  }), /* @__PURE__ */ jsx(SegmentedControl, {
919
- onChange: (newViz) => setVizualization(newViz),
920
- value: vizualization,
1094
+ onChange: (newViz) => setVisualization(newViz),
1095
+ value: visualization,
921
1096
  data: [{
922
1097
  label: "Graph",
923
1098
  value: "graph"
@@ -927,9 +1102,9 @@ const ObjectGraph = () => {
927
1102
  }]
928
1103
  })]
929
1104
  }),
930
- vizualization === "graph" && o2o && objectAttributes && /* @__PURE__ */ jsx(Graph_default, {
1105
+ visualization === "graph" && o2o && objectAttributes && /* @__PURE__ */ jsx(Graph, {
931
1106
  initialNodes: nodes,
932
- initialEdges: o2o.map(({ source, target, sum, qualifier }) => ({
1107
+ initialEdges: o2o.response.map(({ source, target, sum, qualifier }) => ({
933
1108
  source,
934
1109
  target,
935
1110
  markerEnd: { type: MarkerType.ArrowClosed },
@@ -946,10 +1121,10 @@ const ObjectGraph = () => {
946
1121
  }
947
1122
  }
948
1123
  }, ocelId),
949
- vizualization === "cards" && objectCounts && /* @__PURE__ */ jsx(EntityOverview_default, {
1124
+ visualization === "cards" && objectCounts && /* @__PURE__ */ jsx(EntityOverview, {
950
1125
  entityCounts: objectCounts,
951
- attributes: objectAttributes ?? {},
952
- relations: o2o ?? [],
1126
+ attributes: objectAttributes,
1127
+ relations: o2o?.response ?? [],
953
1128
  search: searchValue
954
1129
  })
955
1130
  ]
@@ -961,43 +1136,36 @@ var objectOverview_default = defineModuleRoute({
961
1136
  name: "objectOverview",
962
1137
  requiresOcel: true
963
1138
  });
964
-
965
1139
  //#endregion
966
- //#region src/components/OcelotIcon.tsx
967
- const OcelotIcon = (props) => /* @__PURE__ */ jsxs("svg", {
968
- xmlns: "http://www.w3.org/2000/svg",
969
- width: 128,
970
- height: 128,
971
- viewBox: "0 0 96 96",
972
- ...props,
973
- fill: "currentColor",
974
- children: [
975
- /* @__PURE__ */ jsx("title", { children: "Ocelot" }),
976
- /* @__PURE__ */ jsx("path", { d: "M2.5 8.2c-2.2 5.6-2.3 18-.2 23 .9 2.1 2.7 5.3 4.1 7.1C8.2 40.6 8.6 42 8 43c-2 3.2-1.1 9.1 2.4 14.8 1.9 3.2 4 8.4 4.6 11.7 1.6 8 2.9 9.9 9.4 12.8 3 1.4 7.1 4.2 9.1 6.1l3.6 3.6h21.8l3.6-3.6c2-1.9 6-4.7 8.9-6 3-1.4 5.9-3.1 6.6-3.9.6-.8 2-4.9 3.1-9.1 1.1-4.3 3.3-9.9 4.9-12.4 3.1-4.8 4-10.9 2-14-.6-1-.2-2.4 1.6-4.7 1.4-1.8 3.2-5 4.1-7.1 2.1-5 2-17.4-.2-23C91.8 4.1 91.7 4 87 4c-5.6 0-12 2.1-17.3 5.6-3.9 2.5-3.9 2.5-7.5.7-2.9-1.4-6-1.8-14.2-1.8s-11.3.4-14.2 1.8c-3.6 1.8-3.6 1.8-7.5-.7C21 6.1 14.6 4 9 4c-4.7 0-4.8.1-6.5 4.2zM19 11.1c2.5 1.1 6.1 3.3 8.2 4.9 3.2 2.6 3.8 2.8 4.9 1.4 2.9-3.5 7.3-4.8 15.9-4.8 6.9 0 9.3.4 12.8 2.2 2.3 1.2 4.2 2.7 4.2 3.3 0 .5 1.7-.4 3.8-2 4.3-3.5 11.1-6.7 16.3-7.6 3.6-.7 3.7-.6 4.9 3.1 3 8.9.5 19.7-5.9 25.8l-2.9 2.8 1.9 3.2c2.5 4.2 2.4 6.5-.6 10.7-1.4 1.9-3.3 5.8-4.1 8.6-.9 2.9-1.8 5.3-2.1 5.3-.9 0 .6-8.1 2.8-14.6 1.9-5.6 1.9-6.3.5-9.7-1.6-4-2.7-4.5-4.6-2.2-1 1.2-1 1.8 0 3 1.3 1.6 1.1 3.8-1.5 12.5-.9 3.3-1.4 8.3-1.3 12.5l.3 7-4.9 2.8c-2.7 1.5-5.1 2.5-5.4 2.2-.2-.2.7-1.8 2.2-3.5 2.2-2.7 2.6-4.1 2.6-9.5 0-7.6-.9-10.1-5.5-16.2-4.5-5.8-4.6-8.1-.5-7.5 1.9.3 4.3-.4 6.6-1.7 2-1.2 3.9-1.9 4.2-1.7.5.6 3.1-2.4 3.2-3.5 0-1.1-7.9-3.9-11.1-3.9-7.1 0-11.8 5.6-10.5 12.5.4 1.9 2.3 5.6 4.3 8.2 5.5 7.2 6.6 17.9 2.2 21.9-1.4 1.3-2.6 1.4-5.6.7-3.5-.8-3.8-1.1-4.1-4.8-.3-3.7 0-4.1 2.8-5.2 2.3-.9 3-1.7 3-3.9 0-2.5-.1-2.6-1.7-1.2-2.2 1.8-10.4 1.8-12.6-.1-1.5-1.2-1.7-1-1.7 1.4 0 2.1.7 2.9 3 3.8 2.8 1.1 3.1 1.5 2.8 5.2-.3 3.7-.6 4-4.1 4.8-3.3.8-4.2.6-5.9-1.1-1.7-1.7-2.1-3.2-2-8.8.1-4.3.7-7.4 1.7-8.8 5.1-6.9 7.5-11.3 7.5-13.7C43 38.5 38.5 34 32.1 34 28.9 34 21 36.8 21 37.9c.1 1.1 2.7 4.1 3.2 3.5.3-.2 2.2.5 4.2 1.7 2.3 1.3 4.7 2 6.6 1.7 4.1-.6 4 1.7-.5 7.5-4.6 6.1-5.5 8.6-5.5 16.2 0 5.4.4 6.8 2.6 9.5 1.5 1.7 2.4 3.3 2.2 3.5-.3.3-2.7-.7-5.4-2.2l-4.9-2.8.3-7.7c.2-5.6-.2-9.2-1.8-13.7-2.3-6.9-2.5-9.2-.8-10.9.8-.8.8-1.5-.2-2.7-1.9-2.3-3-1.8-4.6 2.2-1.4 3.4-1.4 4.1.5 9.7 2.2 6.5 3.7 14.6 2.8 14.6-.3 0-1.2-2.4-2.1-5.3-.8-2.8-2.7-6.7-4.1-8.6-3-4.2-3.1-6.5-.6-10.7l1.9-3.2-2.9-2.8C5.5 31.3 3 20.5 6 11.6c1.2-3.7 1.3-3.8 4.9-3.1 2 .4 5.6 1.5 8.1 2.6zm39.2 72.8C60.6 86.3 56.3 88 48 88c-12.3 0-15-4.2-4.2-6.5 5.1-1.1 12.2 0 14.4 2.4z" }),
977
- /* @__PURE__ */ jsx("path", { d: "M8.6 15.1c-1.3 6.8.1 13.2 4 17.9l2.6 3 2.7-4.2c1.5-2.4 4.3-5.8 6.1-7.7 3.3-3.2 3.3-3.4 1.4-4.8-2.5-1.9-13.6-7.3-15-7.3-.6 0-1.4 1.4-1.8 3.1zm8.9 4.1c3.1 1.4 3.1 2.5.2 6.2-2.8 3.4-4.4 2.9-5.3-1.9-1-5.3.4-6.5 5.1-4.3zM78.5 14.9c-3.3 1.6-6.9 3.6-7.9 4.4-1.9 1.4-1.9 1.6 1.4 4.8 1.8 1.9 4.6 5.3 6.1 7.7l2.7 4.2 2.6-3c2.5-3.1 4.6-8.7 4.6-12.6 0-4-1.2-8.4-2.4-8.4-.6 0-3.8 1.3-7.1 2.9zm5.2 7.2c-.8 6.1-2.3 7-5.3 3.4-1.3-1.7-2.4-3.5-2.4-4.1 0-1.3 3.7-3.2 6.4-3.3 1.6-.1 1.8.4 1.3 4z" })
978
- ]
979
- });
980
- var OcelotIcon_default = OcelotIcon;
981
-
1140
+ //#region src/routes/objects.tsx
1141
+ const ObjectPage = () => {
1142
+ const { id } = useCurrentOcel();
1143
+ return /* @__PURE__ */ jsx(EntityPage, {
1144
+ ocelId: id ?? "",
1145
+ type: "objects",
1146
+ title: "Object Inspector",
1147
+ description: "Browse the individual objects in this log. Pick an object type to see its records in a table, with their attributes and the objects they have a relation with."
1148
+ }, id);
1149
+ };
982
1150
  //#endregion
983
- //#region src/config.ts
984
- var config_default = defineModule({
1151
+ //#region src/index.ts
1152
+ var src_default = defineModule({
985
1153
  name: "ocelot",
986
- description: "A tool for exploring object-centric event logs, allowing yout to search events and objects and visualize their relationships and attributes.",
1154
+ description: "A tool for exploring object-centric event logs, allowing you to search events and objects and visualize their relationships and attributes.",
987
1155
  label: "Ocelot",
988
1156
  authors: [{ name: "Öztürk, Görkem-Emre" }],
989
1157
  routes: [
990
1158
  events_default,
991
- objects_default,
1159
+ defineModuleRoute({
1160
+ component: ObjectPage,
1161
+ label: "Objects",
1162
+ name: "objects",
1163
+ requiresOcel: true
1164
+ }),
992
1165
  eventOverview_default,
993
1166
  objectOverview_default
994
1167
  ],
995
- icon: OcelotIcon_default
1168
+ icon: OcelotIcon
996
1169
  });
997
-
998
- //#endregion
999
- //#region src/index.ts
1000
- var src_default = config_default;
1001
-
1002
1170
  //#endregion
1003
- export { src_default as default };
1171
+ export { src_default as default };
package/dist/style.css ADDED
@@ -0,0 +1,9 @@
1
+ .floating-edges {
2
+ width: 100%;
3
+ height: 100vh;
4
+ margin: 1rem;
5
+ }
6
+
7
+ .react-flow__handle {
8
+ opacity: 0;
9
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ocelescope/ocelot",
3
3
  "type": "module",
4
- "version": "0.0.0",
4
+ "version": "0.1.3",
5
5
  "description": "A module for inspections of OCELs",
6
6
  "author": "Görkem-Emre Öztürk <goerkem.oeztuerk@rwth-aachen.de>",
7
7
  "license": "MIT",
@@ -16,7 +16,7 @@
16
16
  "exports": {
17
17
  ".": "./dist/index.js",
18
18
  "./package.json": "./package.json",
19
- "./styles": "./dist/styles/styles.js"
19
+ "./styles.css": "./dist/style.css"
20
20
  },
21
21
  "main": "./dist/index.js",
22
22
  "module": "./dist/index.js",
@@ -28,35 +28,42 @@
28
28
  "access": "public"
29
29
  },
30
30
  "peerDependencies": {
31
- "@dagrejs/dagre": "^2.0.4",
32
- "@mantine/core": "^8.3.14",
33
- "@mantine/hooks": "^8.3.14",
31
+ "@dagrejs/dagre": "^3.0.0",
32
+ "@mantine/core": "^9.4.0",
33
+ "@mantine/hooks": "^9.4.0",
34
+ "@ocelescope/api-base": "^0.2.0",
35
+ "@ocelescope/core": "^0.1.2",
34
36
  "@tanstack/react-query": "^5.90.21",
35
37
  "@xyflow/react": "^12.10.1",
38
+ "dayjs": "^1.11.19",
39
+ "elkjs": "^0.11.0",
36
40
  "file-saver": "^2.0.5",
37
- "html-to-image": "^1.11.13",
38
- "lucide-react": "^0.563.0",
39
- "mantine-datatable": "^8.3.13",
41
+ "html-to-image": "1.11.13",
42
+ "lucide-react": "^1.0.0",
43
+ "mantine-datatable": "^9.3.1",
40
44
  "react": "^19.2.0",
41
45
  "react-dom": "^19.2.0",
42
- "@ocelescope/core": "0.0.0",
43
- "@ocelescope/api-base": "0.0.0"
46
+ "recharts": "^3.2.1",
47
+ "axios": "^1.18.0",
48
+ "@ocelescope/api-client": "^0.1.0"
44
49
  },
45
50
  "devDependencies": {
51
+ "@tsdown/css": "^0.22.0",
52
+ "@types/css-modules": "^1.0.5",
46
53
  "@tsconfig/strictest": "^2.0.8",
47
54
  "@types/file-saver": "^2.0.7",
48
55
  "@types/node": "^25.0.3",
49
56
  "@types/react": "^19.2.7",
50
57
  "@types/react-dom": "^19.2.3",
51
- "tsdown": "^0.18.1",
52
- "typescript": "^5.9.3"
53
- },
54
- "dependencies": {
55
- "elkjs": "^0.11.0"
58
+ "@ocelescope/api-config": "^0.1.0",
59
+ "tsdown": "^0.22.0",
60
+ "typescript": "^5.9.3",
61
+ "orval": "^8.5.2"
56
62
  },
57
63
  "scripts": {
58
- "build": "tsdown",
59
- "dev": "tsdown --watch",
60
- "typecheck": "tsc --noEmit"
64
+ "dev": "tsdown --watch ./src",
65
+ "typecheck": "tsc --noEmit",
66
+ "build": "pnpm generate:api && orval && tsdown",
67
+ "generate:api": "uv run ocelescope-backend openapi --module ocelot"
61
68
  }
62
69
  }
package/dist/index.css DELETED
@@ -1 +0,0 @@
1
- ._79UKFW_test{color:#00f;background-color:red}
@@ -1 +0,0 @@
1
- .test{color:red;background-color:red}.floating-edges{width:100%;height:100vh;margin:1rem}.react-flow__handle{opacity:0}
@@ -1 +0,0 @@
1
- import "@xyflow/react/dist/style.css";
@@ -1 +0,0 @@
1
- import "@xyflow/react/dist/style.css";