@ocelescope/discovery 0.7.0 → 0.8.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 (2) hide show
  1. package/dist/index.js +129 -478
  2. package/package.json +13 -12
package/dist/index.js CHANGED
@@ -1,495 +1,151 @@
1
1
  import { defineModule, defineModuleRoute, useCurrentOcel } from "@ocelescope/core";
2
- import { BookmarkIcon, ChartNetwork, SettingsIcon } from "lucide-react";
3
- import { ActionIcon, Alert, Box, Card, Center, Divider, Drawer, Input, LoadingOverlay, MultiSelect, NumberInput, Select, Slider, Stack, Text, Tooltip } from "@mantine/core";
4
- import { useLocalStorage } from "@mantine/hooks";
5
- import { useCreateDiscoveryTask, useDiscoveryTask, useEventCounts, useListDiscoveryFilters, useListDiscoveryMethods, useObjectCounts, useSaveDiscovery } from "@ocelescope/api-base";
6
- import { Visualization } from "@ocelescope/resources";
7
- import { memo, useEffect, useMemo, useState } from "react";
8
- import { create } from "zustand";
9
- import { persist } from "zustand/middleware";
10
- import validator from "@rjsf/validator-ajv8";
11
- import dynamic from "next/dynamic.js";
12
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
13
- //#region src/stores/discoveryStore.ts
14
- const EMPTY = {
15
- selectedMethodId: null,
16
- formDataByMethod: {},
17
- filters: [],
18
- filtersInitialized: false
19
- };
20
- const updateOcel = (state, ocelId, patch) => ({ byOcel: {
21
- ...state.byOcel,
22
- [ocelId]: {
23
- ...state.byOcel[ocelId] ?? EMPTY,
24
- ...patch
25
- }
26
- } });
27
- const useDiscoveryStore = create()(persist((set) => ({
28
- byOcel: {},
29
- setSelectedMethodId: (ocelId, methodId) => set((s) => updateOcel(s, ocelId, { selectedMethodId: methodId })),
30
- setFormData: (ocelId, methodId, data) => set((s) => {
31
- const current = s.byOcel[ocelId] ?? EMPTY;
32
- return updateOcel(s, ocelId, { formDataByMethod: {
33
- ...current.formDataByMethod,
34
- [methodId]: data
35
- } });
36
- }),
37
- setFilters: (ocelId, filters) => set((s) => updateOcel(s, ocelId, { filters })),
38
- initializeFilters: (ocelId, filters) => set((s) => {
39
- if (s.byOcel[ocelId]?.filtersInitialized) return s;
40
- return updateOcel(s, ocelId, {
41
- filters,
42
- filtersInitialized: true
43
- });
44
- })
45
- }), { name: "ocelescope:discovery" }));
46
- const selectOcelFormState = (ocelId) => (s) => s.byOcel[ocelId] ?? EMPTY;
47
- //#endregion
48
- //#region src/utils/discoveryState.ts
49
- const getInitialFormData = (schema) => {
50
- const initial = {};
51
- for (const [name, property] of Object.entries(schema?.properties ?? {})) {
52
- if (property.default !== void 0) {
53
- initial[name] = property.default;
54
- continue;
55
- }
56
- if (property.type === "array") initial[name] = [];
57
- }
58
- return initial;
59
- };
60
- const normalizeFormData = (formData) => Object.fromEntries(Object.entries(formData).filter(([_, value]) => {
61
- if (value === void 0 || value === null || value === "") return false;
62
- if (Array.isArray(value) && value.length === 0) return false;
63
- return true;
64
- }));
65
- //#endregion
66
- //#region src/components/DiscoveryForm.tsx
67
- const Form = dynamic(() => import("@rjsf/mantine").then((m) => m.Form), { ssr: false });
68
- const MantineSliderWidget = ({ value, onChange, schema, label, required }) => {
69
- const min = schema.minimum ?? schema.exclusiveMinimum;
70
- const max = schema.maximum ?? schema.exclusiveMaximum;
71
- const description = schema.description;
72
- return /* @__PURE__ */ jsxs(Fragment, { children: [
73
- /* @__PURE__ */ jsx(Input.Label, {
74
- required,
75
- children: label
76
- }),
77
- description && /* @__PURE__ */ jsx(Input.Description, { children: description }),
78
- /* @__PURE__ */ jsx(NumberInput, {
79
- mt: "5px",
80
- min,
81
- max,
82
- step: 1e-4,
83
- decimalScale: 4,
84
- hideControls: true,
85
- value: typeof value === "number" ? value : schema.default ?? min,
86
- onChange: (v) => typeof v === "number" && onChange(v)
87
- }),
88
- /* @__PURE__ */ jsx(Slider, {
89
- min,
90
- max,
91
- step: 1e-4,
92
- label: (v) => v.toFixed(4),
93
- value: typeof value === "number" ? value : schema.default ?? min,
94
- onChange
95
- })
96
- ] });
97
- };
98
- const WIDGETS = { "mantine-slider": MantineSliderWidget };
99
- const FieldTemplate = ({ children, errors, help, hidden }) => {
100
- if (hidden) return /* @__PURE__ */ jsx("div", {
101
- style: { display: "none" },
102
- children
103
- });
104
- return /* @__PURE__ */ jsxs("div", { children: [
105
- children,
106
- errors,
107
- help
108
- ] });
109
- };
110
- const DescriptionFieldTemplate = ({ id, description }) => description ? /* @__PURE__ */ jsx(Input.Description, {
111
- id,
112
- mt: -8,
113
- mb: 8,
114
- children: description
115
- }) : null;
116
- const TEMPLATES = {
117
- DescriptionFieldTemplate,
118
- FieldTemplate
119
- };
120
- const UI_SCHEMA_BASE = { "ui:submitButtonOptions": { norender: true } };
121
- const buildUiSchema = (schema) => {
122
- const uiSchema = { ...UI_SCHEMA_BASE };
123
- for (const [key, prop] of Object.entries(schema.properties ?? {})) if (prop.fieldType) uiSchema[key] = { "ui:field": prop.fieldType };
124
- else if ((prop.type === "number" || prop.type === "integer") && (prop.minimum !== void 0 || prop.exclusiveMinimum !== void 0) && (prop.maximum !== void 0 || prop.exclusiveMaximum !== void 0)) uiSchema[key] = { "ui:widget": "mantine-slider" };
125
- return uiSchema;
126
- };
127
- const makeOcelFields = (eventTypeOptions, objectTypeOptions) => {
128
- const OcelTypeField = (options) => memo(({ schema, formData, onChange, required, fieldPathId: { path } }) => {
129
- return /* @__PURE__ */ jsx(schema.type === "array" ? MultiSelect : Select, {
130
- label: schema.title,
131
- description: schema.description,
132
- required,
133
- value: formData ?? (schema.type === "array" ? [] : null),
134
- onChange: (v) => onChange(v, path),
135
- data: options,
136
- clearable: true,
137
- searchable: true
138
- });
139
- });
2
+ import { ChartNetwork, Settings } from "lucide-react";
3
+ import { ActionIcon, Box, LoadingOverlay, ScrollArea, Select, Splitter, Stack, Text, Tooltip } from "@mantine/core";
4
+ import { useDebouncedValue } from "@mantine/hooks";
5
+ import { usePlugins, useRunPlugin } from "@ocelescope/api-base";
6
+ import { PluginForm, ResultSection } from "@ocelescope/plugin-components";
7
+ import { useEffect, useEffectEvent, useMemo, useRef, useState } from "react";
8
+ import { jsx, jsxs } from "react/jsx-runtime";
9
+ //#region src/hooks/useDiscoveryMethods.tsx
10
+ const useDiscoveryMethods = () => {
11
+ const { data: plugins, isLoading } = usePlugins({ include_base: true });
12
+ const discoveryGroups = useMemo(() => {
13
+ return (plugins ?? []).map(({ methods, ...plugin }) => ({
14
+ ...plugin,
15
+ methods: methods.filter(({ inputs, outputs }) => inputs.length === 1 && outputs.length === 1 && inputs[0]?.type === "ocel" && outputs[0]?.type === "resource").map(({ outputs, inputs, ...rest }) => ({
16
+ ...rest,
17
+ id: `${plugin.id}:${rest.name}`,
18
+ input: inputs[0],
19
+ pluginId: plugin.id,
20
+ output: outputs[0]
21
+ }))
22
+ }));
23
+ }, [plugins]);
140
24
  return {
141
- event_type: OcelTypeField(eventTypeOptions),
142
- object_type: OcelTypeField(objectTypeOptions)
25
+ discoveryGroups,
26
+ discoveryMethods: useMemo(() => discoveryGroups.flatMap(({ methods }) => methods), [discoveryGroups]),
27
+ isLoading
143
28
  };
144
29
  };
145
- const DiscoveryForm = ({ schema, formData, onChange, eventTypeOptions, objectTypeOptions }) => {
146
- const uiSchema = useMemo(() => buildUiSchema(schema), [schema]);
147
- const fields = useMemo(() => makeOcelFields(eventTypeOptions, objectTypeOptions), [eventTypeOptions, objectTypeOptions]);
148
- return /* @__PURE__ */ jsx(Form, {
149
- schema: {
150
- ...schema,
151
- title: ""
152
- },
153
- formData,
154
- validator,
155
- uiSchema,
156
- fields,
157
- widgets: WIDGETS,
158
- templates: TEMPLATES,
159
- onChange: (data) => onChange(data.formData ?? {})
160
- });
161
- };
162
30
  //#endregion
163
- //#region src/components/DiscoveryFiltersSection.tsx
164
- const DiscoveryFiltersSection = ({ availableFilters, filters, onFiltersChange, eventTypeOptions, objectTypeOptions }) => {
165
- const handleChange = (filterName, data) => {
166
- if (filters.some((f) => f.name === filterName)) onFiltersChange(filters.map((f) => f.name === filterName ? {
167
- ...f,
168
- payload: data
169
- } : f));
170
- else onFiltersChange([...filters, {
171
- name: filterName,
172
- payload: data
173
- }]);
174
- };
175
- return /* @__PURE__ */ jsxs(Stack, {
176
- gap: "xs",
177
- children: [/* @__PURE__ */ jsx(Text, {
178
- fw: 500,
179
- children: "Filters"
180
- }), availableFilters.map((filterSchema) => {
181
- const schema = filterSchema.json_schema;
182
- const payload = filters.find((f) => f.name === filterSchema.name)?.payload ?? {};
183
- return /* @__PURE__ */ jsxs(Card, {
184
- withBorder: true,
185
- padding: "sm",
186
- radius: "sm",
187
- children: [/* @__PURE__ */ jsx(Text, {
188
- size: "sm",
189
- fw: 500,
190
- mb: "xs",
191
- children: filterSchema.name
192
- }), /* @__PURE__ */ jsx(DiscoveryForm, {
193
- schema,
194
- formData: payload,
195
- onChange: (data) => handleChange(filterSchema.name, data),
196
- eventTypeOptions,
197
- objectTypeOptions
198
- })]
199
- }, filterSchema.name);
200
- })]
31
+ //#region src/components/DiscoveryPage.tsx
32
+ const uiSchema = { "ui:submitButtonOptions": { norender: true } };
33
+ const DiscoveryConfiguration = ({ method, ocelId, onSuccess }) => {
34
+ const [input, setInput] = useState({});
35
+ const [debouncedInput] = useDebouncedValue(input, 1e3);
36
+ const ref = useRef(null);
37
+ const { mutate } = useRunPlugin({ mutation: { onSuccess } });
38
+ const run = useEffectEvent((data) => {
39
+ if (method.configuration_schema && ref.current?.validate(data).errors.length !== 0) return;
40
+ mutate({
41
+ methodName: method.name,
42
+ pluginId: method.pluginId,
43
+ data: {
44
+ input_resources: { [method.input.name]: ocelId },
45
+ input: data
46
+ }
47
+ });
48
+ });
49
+ useEffect(() => {
50
+ run(debouncedInput);
51
+ }, [debouncedInput]);
52
+ return method.configuration_schema && /* @__PURE__ */ jsx(ScrollArea, {
53
+ h: "100%",
54
+ offsetScrollbars: true,
55
+ children: /* @__PURE__ */ jsx(PluginForm, {
56
+ methodName: method.name,
57
+ pluginId: method.pluginId,
58
+ schema: method.configuration_schema,
59
+ inputResources: { [method.input.name]: ocelId },
60
+ onChange: ({ formData }) => setInput(formData),
61
+ formData: input,
62
+ ref,
63
+ uiSchema
64
+ })
201
65
  });
202
66
  };
203
- //#endregion
204
- //#region src/components/DiscoverySettingsContent.tsx
205
- const DiscoverySettingsContent = ({ methods, selectedMethodId, setSelectedMethodId, selectedMethod, selectedSchema, activeFormData, setActiveFormData, eventCounts, objectCounts, errorMessage, availableFilters, filters, setFilters }) => {
206
- const selectedVariants = selectedMethod?.variants ?? [];
67
+ const DiscoverySideBar = ({ onSuccess }) => {
68
+ const { discoveryGroups, discoveryMethods, isLoading } = useDiscoveryMethods();
69
+ const { id } = useCurrentOcel();
70
+ const [currentMethod, setCurrentMethod] = useState(void 0);
71
+ useEffect(() => {
72
+ if (discoveryMethods.length > 0 && !currentMethod) setCurrentMethod(discoveryMethods[0]);
73
+ }, [discoveryMethods]);
207
74
  return /* @__PURE__ */ jsxs(Stack, {
208
- gap: "xl",
75
+ maw: 400,
76
+ px: "md",
77
+ pt: "xs",
78
+ h: "100%",
209
79
  children: [
210
- /* @__PURE__ */ jsxs(Stack, {
211
- gap: "xs",
212
- children: [
213
- /* @__PURE__ */ jsx(Select, {
214
- label: "Discovery Method",
215
- value: selectedMethod?.name ?? null,
216
- onChange: (name) => {
217
- setSelectedMethodId(methods.find((m) => m.name === name)?.variants[0]?.methodId ?? null);
218
- },
219
- data: methods.map((m) => ({
220
- value: m.name,
221
- label: m.name
222
- })),
223
- allowDeselect: false
224
- }),
225
- selectedVariants.find((v) => v.methodId === selectedMethodId)?.description && /* @__PURE__ */ jsx(Text, {
226
- size: "sm",
227
- c: "dimmed",
228
- children: selectedVariants.find((v) => v.methodId === selectedMethodId)?.description
229
- }),
230
- selectedVariants.length > 1 && /* @__PURE__ */ jsx(Select, {
231
- label: "Output Format",
232
- value: selectedMethodId,
233
- onChange: setSelectedMethodId,
234
- data: selectedVariants.map((v) => ({
235
- value: v.methodId,
236
- label: v.resourceType
237
- })),
238
- allowDeselect: false
239
- }),
240
- /* @__PURE__ */ jsx(DiscoveryForm, {
241
- schema: selectedSchema,
242
- formData: activeFormData,
243
- onChange: setActiveFormData,
244
- eventTypeOptions: Object.keys(eventCounts),
245
- objectTypeOptions: Object.keys(objectCounts)
246
- })
247
- ]
80
+ /* @__PURE__ */ jsx(Select, {
81
+ label: "Discovery Method",
82
+ searchable: true,
83
+ value: currentMethod?.id,
84
+ onChange: (newMethod) => setCurrentMethod(discoveryMethods.find(({ id }) => id === newMethod)),
85
+ data: discoveryGroups.filter(({ methods }) => methods.length > 0).map(({ label, methods }) => ({
86
+ group: label,
87
+ items: methods.map(({ label, id }) => ({
88
+ value: id,
89
+ label
90
+ }))
91
+ })),
92
+ loading: isLoading
248
93
  }),
249
- /* @__PURE__ */ jsx(Divider, {}),
250
- /* @__PURE__ */ jsx(DiscoveryFiltersSection, {
251
- availableFilters,
252
- filters,
253
- onFiltersChange: setFilters,
254
- eventTypeOptions: Object.keys(eventCounts),
255
- objectTypeOptions: Object.keys(objectCounts)
94
+ currentMethod && /* @__PURE__ */ jsx(Text, {
95
+ c: "dimmed",
96
+ children: currentMethod.description
256
97
  }),
257
- errorMessage && /* @__PURE__ */ jsx(Alert, {
258
- color: "red",
259
- title: "Discovery failed",
260
- children: errorMessage
98
+ /* @__PURE__ */ jsxs(Box, {
99
+ pos: "relative",
100
+ flex: 1,
101
+ mih: 0,
102
+ children: [/* @__PURE__ */ jsx(LoadingOverlay, { visible: isLoading }), currentMethod && id && /* @__PURE__ */ jsx(DiscoveryConfiguration, {
103
+ method: currentMethod,
104
+ ocelId: id,
105
+ onSuccess
106
+ }, `${currentMethod.id}:${id}`)]
261
107
  })
262
108
  ]
263
109
  });
264
110
  };
265
- //#endregion
266
- //#region src/components/DiscoveryPage.tsx
267
- const PANEL_OPEN_KEY = "ocelescope:discovery:panel-open";
268
- const DiscoveryPageContent = ({ ocelId }) => {
269
- const { selectedMethodId, formDataByMethod, filters, filtersInitialized } = useDiscoveryStore(selectOcelFormState(ocelId));
270
- const setSelectedMethodId = useDiscoveryStore((s) => s.setSelectedMethodId);
271
- const setFormData = useDiscoveryStore((s) => s.setFormData);
272
- const setFiltersInStore = useDiscoveryStore((s) => s.setFilters);
273
- const initializeFilters = useDiscoveryStore((s) => s.initializeFilters);
274
- const [taskId, setTaskId] = useState();
275
- const [savedTaskId, setSavedTaskId] = useState();
276
- const [submitError, setSubmitError] = useState();
277
- const [panelOpen, setPanelOpen] = useLocalStorage({
278
- key: PANEL_OPEN_KEY,
279
- defaultValue: true
280
- });
281
- const { data: rawMethods = [], isLoading: isMethodsLoading, error: methodsError } = useListDiscoveryMethods();
282
- const methods = useMemo(() => rawMethods.map((m) => ({
283
- ...m,
284
- variants: m.variants.filter((v) => v.enabled)
285
- })).filter((m) => m.variants.length), [rawMethods]);
286
- const { data: availableFilters = [] } = useListDiscoveryFilters();
287
- const { data: eventCounts = {} } = useEventCounts(ocelId, void 0, { query: { enabled: true } });
288
- const { data: objectCounts = {} } = useObjectCounts(ocelId, void 0, { query: { enabled: true } });
289
- useEffect(() => {
290
- if (filtersInitialized || availableFilters.length === 0) return;
291
- initializeFilters(ocelId, availableFilters.map((f) => ({
292
- name: f.name,
293
- payload: getInitialFormData(f.json_schema)
294
- })));
295
- }, [
296
- filtersInitialized,
297
- availableFilters,
298
- ocelId,
299
- initializeFilters
300
- ]);
301
- useEffect(() => {
302
- if (!selectedMethodId || isMethodsLoading) return;
303
- if (!methods.flatMap((m) => m.variants.map((v) => v.methodId)).includes(selectedMethodId)) setSelectedMethodId(ocelId, null);
304
- }, [
305
- methods,
306
- selectedMethodId,
307
- isMethodsLoading,
308
- ocelId,
309
- setSelectedMethodId
310
- ]);
311
- useEffect(() => {
312
- if (selectedMethodId || methods.length === 0) return;
313
- setSelectedMethodId(ocelId, methods.flatMap((m) => m.variants).find((v) => v.resourceType === "DirectlyFollowsGraph")?.methodId ?? methods[0]?.variants[0]?.methodId ?? null);
314
- }, [
315
- methods,
316
- selectedMethodId,
317
- ocelId,
318
- setSelectedMethodId
319
- ]);
320
- const selectedMethod = useMemo(() => methods.find((m) => m.variants.some((v) => v.methodId === selectedMethodId)) ?? null, [methods, selectedMethodId]);
321
- const selectedSchema = useMemo(() => selectedMethod?.variants.find((v) => v.methodId === selectedMethodId) ?? null, [selectedMethod, selectedMethodId])?.inputSchema ?? {};
322
- useEffect(() => {
323
- if (!selectedMethodId || !selectedMethod) return;
324
- if (formDataByMethod[selectedMethodId]) return;
325
- setFormData(ocelId, selectedMethodId, getInitialFormData(selectedSchema));
326
- }, [
327
- selectedMethod,
328
- selectedMethodId,
329
- selectedSchema,
330
- formDataByMethod,
331
- ocelId,
332
- setFormData
333
- ]);
334
- const activeFormData = selectedMethodId ? formDataByMethod[selectedMethodId] ?? {} : {};
335
- const { mutate: runDiscovery, isPending: isSubmittingDiscovery } = useCreateDiscoveryTask({ mutation: {
336
- onSuccess: (newTaskId) => {
337
- setSubmitError(void 0);
338
- setTaskId(newTaskId);
339
- },
340
- onError: (error) => {
341
- setSubmitError(error instanceof Error ? error.message : "Discovery failed");
342
- }
343
- } });
344
- const { data: task, error: taskError } = useDiscoveryTask(taskId ?? "", { query: {
345
- enabled: !!taskId,
346
- refetchInterval: ({ state }) => {
347
- if (state.data?.state === "PENDING" || state.data?.state === "STARTED") return 1e3;
348
- return false;
349
- }
350
- } });
351
- const { mutate: saveDiscovery, isPending: isSaving } = useSaveDiscovery({ mutation: { onSuccess: (_data, { taskId: savedId }) => setSavedTaskId(savedId) } });
352
- const isSaved = !!taskId && savedTaskId === taskId;
353
- const requestPayload = useMemo(() => normalizeFormData(activeFormData), [activeFormData]);
354
- useEffect(() => {
355
- if (!selectedMethodId) return;
356
- const timeoutId = window.setTimeout(() => {
357
- runDiscovery({
358
- ocelId,
359
- data: {
360
- methodId: selectedMethodId,
361
- parameters: requestPayload,
362
- filters
363
- }
364
- });
365
- }, 650);
366
- return () => window.clearTimeout(timeoutId);
367
- }, [
368
- ocelId,
369
- runDiscovery,
370
- useMemo(() => JSON.stringify({
371
- selectedMethodId,
372
- requestPayload,
373
- ocelId,
374
- filters
375
- }), [
376
- ocelId,
377
- requestPayload,
378
- selectedMethodId,
379
- filters
380
- ]),
381
- requestPayload,
382
- selectedMethodId,
383
- filters
384
- ]);
385
- const isDiscovering = isSubmittingDiscovery || task?.state === "PENDING" || task?.state === "STARTED";
386
- const errorMessage = submitError || (methodsError instanceof Error ? methodsError.message : void 0) || (taskError instanceof Error ? taskError.message : void 0) || (task?.state === "FAILURE" ? "The backend discovery task failed." : void 0);
387
- return /* @__PURE__ */ jsxs(Box, {
388
- pos: "relative",
111
+ const DiscoveryPage = () => {
112
+ const [discoveryTask, setDiscoveryTask] = useState(void 0);
113
+ const splitterRef = useRef(null);
114
+ return /* @__PURE__ */ jsxs(Splitter, {
115
+ splitterRef,
116
+ withHandle: false,
389
117
  h: "100%",
390
- style: { overflow: "hidden" },
391
- children: [
392
- task?.state === "SUCCESS" ? /* @__PURE__ */ jsx(Box, {
393
- h: "100%",
394
- p: "sm",
395
- children: /* @__PURE__ */ jsx(Visualization, {
396
- visualization: task.visualization,
397
- menuItems: [{
398
- icon: /* @__PURE__ */ jsx(BookmarkIcon, { style: {
399
- width: 16,
400
- height: 16,
401
- maxWidth: "none",
402
- maxHeight: "none",
403
- stroke: isSaved ? "var(--mantine-color-green-6)" : "currentColor",
404
- fill: isSaved ? "var(--mantine-color-green-6)" : "none"
405
- } }),
406
- label: isSaved ? "Saved" : "Save",
407
- onClick: () => {
408
- if (taskId && !isSaving && taskId !== savedTaskId) saveDiscovery({ taskId });
409
- }
410
- }]
411
- })
412
- }) : /* @__PURE__ */ jsx(Center, {
413
- h: "100%",
414
- children: /* @__PURE__ */ jsx(Text, {
415
- c: "dimmed",
416
- ta: "center",
417
- children: isDiscovering ? "Discovering visualization..." : "The discovery preview will appear here."
418
- })
419
- }),
420
- !panelOpen && /* @__PURE__ */ jsx(Tooltip, {
421
- label: "Open settings",
422
- position: "left",
423
- withArrow: true,
424
- children: /* @__PURE__ */ jsx(ActionIcon, {
425
- variant: "default",
426
- size: "lg",
427
- radius: "md",
428
- onClick: () => setPanelOpen(true),
429
- style: {
430
- position: "absolute",
431
- top: 12,
432
- right: 12,
433
- zIndex: 5
434
- },
435
- children: /* @__PURE__ */ jsx(SettingsIcon, { size: 16 })
436
- })
437
- }),
438
- /* @__PURE__ */ jsx(LoadingOverlay, {
439
- visible: isMethodsLoading || isDiscovering,
440
- zIndex: 100
441
- }),
442
- /* @__PURE__ */ jsx(Drawer, {
443
- opened: panelOpen,
444
- onClose: () => setPanelOpen(false),
445
- position: "right",
446
- title: "Discovery settings",
447
- size: 380,
448
- withOverlay: false,
449
- lockScroll: false,
450
- trapFocus: false,
451
- returnFocus: false,
452
- withinPortal: false,
453
- styles: {
454
- root: {
455
- position: "absolute",
456
- inset: 0,
457
- pointerEvents: "none"
458
- },
459
- inner: {
460
- position: "absolute",
461
- inset: 0,
462
- pointerEvents: "none"
463
- },
464
- content: {
465
- height: "100%",
466
- pointerEvents: "auto"
467
- }
468
- },
469
- children: /* @__PURE__ */ jsx(DiscoverySettingsContent, {
470
- methods,
471
- selectedMethodId,
472
- setSelectedMethodId: (id) => setSelectedMethodId(ocelId, id),
473
- selectedMethod,
474
- selectedSchema,
475
- activeFormData,
476
- setActiveFormData: (data) => selectedMethodId && setFormData(ocelId, selectedMethodId, data),
477
- eventCounts,
478
- objectCounts,
479
- errorMessage,
480
- availableFilters,
481
- filters,
482
- setFilters: (next) => setFiltersInStore(ocelId, next)
118
+ handleColor: "var(--mantine-color-default-border)",
119
+ lineSize: 2,
120
+ children: [/* @__PURE__ */ jsx(Splitter.Pane, {
121
+ defaultSize: 70,
122
+ children: /* @__PURE__ */ jsx(ResultSection, {
123
+ taskId: discoveryTask,
124
+ extraActions: /* @__PURE__ */ jsx(Tooltip, {
125
+ label: "Toggle settings",
126
+ children: /* @__PURE__ */ jsx(ActionIcon, {
127
+ size: "input-sm",
128
+ variant: "outline",
129
+ onClick: () => splitterRef.current?.toggleCollapse(1),
130
+ children: /* @__PURE__ */ jsx(Settings, { size: 20 })
131
+ })
483
132
  })
484
133
  })
485
- ]
134
+ }), /* @__PURE__ */ jsx(Splitter.Pane, {
135
+ defaultSize: 30,
136
+ max: "400px",
137
+ min: "300px",
138
+ collapsible: true,
139
+ children: /* @__PURE__ */ jsx(DiscoverySideBar, { onSuccess: (discoveryTaskId) => setDiscoveryTask(discoveryTaskId) })
140
+ })]
486
141
  });
487
142
  };
488
- const DiscoveryPage = () => {
489
- const { id: ocelId } = useCurrentOcel();
490
- if (!ocelId) return /* @__PURE__ */ jsx(LoadingOverlay, { visible: true });
491
- return /* @__PURE__ */ jsx(DiscoveryPageContent, { ocelId }, ocelId);
492
- };
143
+ var DiscoveryPage_default = defineModuleRoute({
144
+ label: "Discovery",
145
+ name: "discovery",
146
+ component: DiscoveryPage,
147
+ requiresOcel: true
148
+ });
493
149
  //#endregion
494
150
  //#region src/index.ts
495
151
  var src_default = defineModule({
@@ -497,12 +153,7 @@ var src_default = defineModule({
497
153
  description: "A tool for discovering object-centric event logs, allowing you create various plots like OC-DFGs or OC-Petri-Nets.",
498
154
  label: "Model Discovery",
499
155
  authors: [{ name: "Menne, Sebastian" }],
500
- routes: [defineModuleRoute({
501
- component: DiscoveryPage,
502
- label: "Discovery",
503
- name: "discovery",
504
- requiresOcel: true
505
- })],
156
+ routes: [DiscoveryPage_default],
506
157
  icon: ChartNetwork
507
158
  });
508
159
  //#endregion
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ocelescope/discovery",
3
3
  "type": "module",
4
- "version": "0.7.0",
4
+ "version": "0.8.0",
5
5
  "description": "A module for discovery of OCELs",
6
6
  "author": "Sebastian Menne <sebastian.menne@rwth-aachen.de>",
7
7
  "license": "MIT",
@@ -30,6 +30,10 @@
30
30
  "@mantine/carousel": "^9.5.1",
31
31
  "@mantine/core": "^9.5.1",
32
32
  "@mantine/hooks": "^9.5.1",
33
+ "@ocelescope/api-base": "^0.8.0",
34
+ "@ocelescope/core": "^0.8.0",
35
+ "@ocelescope/plugin-components": "^0.8.0",
36
+ "@ocelescope/resources": "^0.8.0",
33
37
  "@rjsf/core": "^6.8.0",
34
38
  "@rjsf/mantine": "^6.8.0",
35
39
  "@rjsf/utils": "^6.8.0",
@@ -38,23 +42,20 @@
38
42
  "embla-carousel": "^8.6.0",
39
43
  "embla-carousel-react": "^8.6.0",
40
44
  "lucide-react": "^1.0.0",
41
- "next": "16.3.0",
42
- "react": "^19.2.8",
43
- "react-dom": "^19.2.8",
45
+ "next": "16.3.2",
46
+ "react": "^19.3.0",
47
+ "react-dom": "^19.3.0",
44
48
  "react-hook-form": "^7.71.2",
45
49
  "uniqolor": "^1.1.1",
46
- "zustand": "^5.0.11",
47
- "@ocelescope/api-base": "^0.7.0",
48
- "@ocelescope/core": "^0.7.0",
49
- "@ocelescope/resources": "^0.7.0"
50
+ "zustand": "^5.0.15"
50
51
  },
51
52
  "devDependencies": {
52
53
  "@rjsf/mantine": "^6.8.0",
53
54
  "@types/file-saver": "^2.0.7",
54
- "@types/node": "^26.2.0",
55
- "@types/react": "^19.2.18",
56
- "@types/react-dom": "^19.2.4",
57
- "tsdown": "^0.22.14",
55
+ "@types/node": "^26.6.1",
56
+ "@types/react": "^19.3.0",
57
+ "@types/react-dom": "^19.3.0",
58
+ "tsdown": "^0.23.0",
58
59
  "typescript": "^6.0.3"
59
60
  },
60
61
  "scripts": {