@knime/hub-features 1.22.4 → 1.24.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.
@@ -0,0 +1,472 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "inmemory://schemas/analytics-events.json",
4
+ "title": "AnalyticsEventSchema",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": ["version", "events"],
8
+ "properties": {
9
+ "version": {
10
+ "$comment": "Version of this document",
11
+ "type": "string",
12
+ "const": "v1.0"
13
+ },
14
+ "events": {
15
+ "type": "object",
16
+ "additionalProperties": false,
17
+ "required": [
18
+ "kai_prompted",
19
+ "layouteditor_opened",
20
+ "annotation_created",
21
+ "workflow_saved",
22
+ "connection_created",
23
+ "node_created",
24
+ "qam_opened",
25
+ "node_searched",
26
+ "sidepanel_opened",
27
+ "action_undone",
28
+ "action_redone"
29
+ ],
30
+ "properties": {
31
+ "kai_prompted": {
32
+ "type": "object",
33
+ "additionalProperties": false,
34
+ "required": ["kaiqa_button_", "kaibuild_button_", "qam_button_"],
35
+ "properties": {
36
+ "kaiqa_button_": {
37
+ "$ref": "#/definitions/EmptyPayload"
38
+ },
39
+ "kaibuild_button_": {
40
+ "$ref": "#/definitions/EmptyPayload"
41
+ },
42
+ "qam_button_": {
43
+ "$ref": "#/definitions/KaiPromptedPayload"
44
+ }
45
+ }
46
+ },
47
+ "layouteditor_opened": {
48
+ "type": "object",
49
+ "additionalProperties": false,
50
+ "required": [
51
+ "canvas_ctxmenu_openlayouteditor",
52
+ "keyboard_shortcut_openlayouteditor",
53
+ "wftoolbar_button_openlayouteditor"
54
+ ],
55
+ "properties": {
56
+ "canvas_ctxmenu_openlayouteditor": {
57
+ "$ref": "#/definitions/EmptyPayload"
58
+ },
59
+ "keyboard_shortcut_openlayouteditor": {
60
+ "$ref": "#/definitions/EmptyPayload"
61
+ },
62
+ "wftoolbar_button_openlayouteditor": {
63
+ "$ref": "#/definitions/EmptyPayload"
64
+ }
65
+ }
66
+ },
67
+ "annotation_created": {
68
+ "type": "object",
69
+ "additionalProperties": false,
70
+ "required": [
71
+ "canvas_ctxmenu_newannotation",
72
+ "canvas_ctxmenu_kaiexplain"
73
+ ],
74
+ "properties": {
75
+ "canvas_ctxmenu_newannotation": {
76
+ "$ref": "#/definitions/EmptyPayload"
77
+ },
78
+ "canvas_ctxmenu_kaiexplain": {
79
+ "$ref": "#/definitions/EmptyPayload"
80
+ }
81
+ }
82
+ },
83
+ "workflow_saved": {
84
+ "type": "object",
85
+ "additionalProperties": false,
86
+ "required": ["wftoolbar_button_save", "keyboard_shortcut_savewf"],
87
+ "properties": {
88
+ "wftoolbar_button_save": {
89
+ "$ref": "#/definitions/WorkflowSavedPayload"
90
+ },
91
+ "keyboard_shortcut_savewf": {
92
+ "$ref": "#/definitions/WorkflowSavedPayload"
93
+ }
94
+ }
95
+ },
96
+ "connection_created": {
97
+ "type": "object",
98
+ "additionalProperties": false,
99
+ "required": [
100
+ "port_dragdrop_fwd",
101
+ "port_dragdrop_bwd",
102
+ "keyboard_shortcut_connectnodes",
103
+ "keyboard_shortcut_connectflowvar",
104
+ "canvas_ctxmenu_connectnodes",
105
+ "canvas_ctxmenu_connectflowvar"
106
+ ],
107
+ "properties": {
108
+ "port_dragdrop_fwd": {
109
+ "$ref": "#/definitions/ConnectionCreatedPayload"
110
+ },
111
+ "port_dragdrop_bwd": {
112
+ "$ref": "#/definitions/ConnectionCreatedPayload"
113
+ },
114
+ "keyboard_shortcut_connectnodes": {
115
+ "$ref": "#/definitions/EmptyPayload"
116
+ },
117
+ "keyboard_shortcut_connectflowvar": {
118
+ "$ref": "#/definitions/EmptyPayload"
119
+ },
120
+ "canvas_ctxmenu_connectnodes": {
121
+ "$ref": "#/definitions/EmptyPayload"
122
+ },
123
+ "canvas_ctxmenu_connectflowvar": {
124
+ "$ref": "#/definitions/EmptyPayload"
125
+ }
126
+ }
127
+ },
128
+ "node_created": {
129
+ "type": "object",
130
+ "additionalProperties": false,
131
+ "required": [
132
+ "noderepo_dragdrop_",
133
+ "noderepo_doubleclick_",
134
+ "noderepo_keyboard_enter",
135
+ "explorer_dragdrop_",
136
+ "qam_click_",
137
+ "qam_keyboard_enter",
138
+ "kaiqa_dragdrop_",
139
+ "kaiqa_keyboard_enter"
140
+ ],
141
+ "properties": {
142
+ "noderepo_dragdrop_": {
143
+ "$ref": "#/definitions/NodeCreated_Base"
144
+ },
145
+ "noderepo_doubleclick_": {
146
+ "$ref": "#/definitions/NodeCreated_WithOptionalConnectedTo"
147
+ },
148
+ "noderepo_keyboard_enter": {
149
+ "$ref": "#/definitions/NodeCreated_WithOptionalConnectedTo"
150
+ },
151
+ "explorer_dragdrop_": {
152
+ "$ref": "#/definitions/NodeCreated_Base"
153
+ },
154
+ "qam_click_": {
155
+ "$ref": "#/definitions/NodeCreated_WithOptionalConnectedToPorts"
156
+ },
157
+ "qam_keyboard_enter": {
158
+ "$ref": "#/definitions/NodeCreated_WithOptionalConnectedToPorts"
159
+ },
160
+ "kaiqa_dragdrop_": {
161
+ "$ref": "#/definitions/NodeCreated_Base"
162
+ },
163
+ "kaiqa_keyboard_enter": {
164
+ "$ref": "#/definitions/NodeCreated_Base"
165
+ }
166
+ }
167
+ },
168
+ "qam_opened": {
169
+ "type": "object",
170
+ "additionalProperties": false,
171
+ "required": [
172
+ "port_dragdrop_fwd",
173
+ "port_dragdrop_bwd",
174
+ "canvas_doubleclick_",
175
+ "keyboard_shortcut_",
176
+ "canvas_ctxmenu_quickaddnode"
177
+ ],
178
+ "properties": {
179
+ "port_dragdrop_fwd": {
180
+ "$ref": "#/definitions/QAMOpened_Payload"
181
+ },
182
+ "port_dragdrop_bwd": {
183
+ "$ref": "#/definitions/QAMOpened_Payload"
184
+ },
185
+ "canvas_doubleclick_": {
186
+ "$ref": "#/definitions/EmptyPayload"
187
+ },
188
+ "keyboard_shortcut_": {
189
+ "$ref": "#/definitions/QAMOpened_PartialPayload"
190
+ },
191
+ "canvas_ctxmenu_quickaddnode": {
192
+ "$ref": "#/definitions/EmptyPayload"
193
+ }
194
+ }
195
+ },
196
+ "node_searched": {
197
+ "type": "object",
198
+ "additionalProperties": false,
199
+ "required": ["noderepo_type_", "qam_type_"],
200
+ "properties": {
201
+ "noderepo_type_": {
202
+ "$ref": "#/definitions/SearchPayload"
203
+ },
204
+ "qam_type_": {
205
+ "$ref": "#/definitions/SearchPayload"
206
+ }
207
+ }
208
+ },
209
+ "sidepanel_opened": {
210
+ "type": "object",
211
+ "additionalProperties": false,
212
+ "required": [
213
+ "sidepanel_click_info",
214
+ "sidepanel_click_noderepo",
215
+ "sidepanel_click_explorer",
216
+ "sidepanel_click_kai",
217
+ "sidepanel_click_monitor",
218
+ "wftoolbar_dropdownmenu_versionhistory"
219
+ ],
220
+ "properties": {
221
+ "sidepanel_click_info": {
222
+ "$ref": "#/definitions/EmptyPayload"
223
+ },
224
+ "sidepanel_click_noderepo": {
225
+ "$ref": "#/definitions/EmptyPayload"
226
+ },
227
+ "sidepanel_click_explorer": {
228
+ "$ref": "#/definitions/EmptyPayload"
229
+ },
230
+ "sidepanel_click_kai": {
231
+ "$ref": "#/definitions/EmptyPayload"
232
+ },
233
+ "sidepanel_click_monitor": {
234
+ "$ref": "#/definitions/EmptyPayload"
235
+ },
236
+ "wftoolbar_dropdownmenu_versionhistory": {
237
+ "$ref": "#/definitions/EmptyPayload"
238
+ }
239
+ }
240
+ },
241
+ "action_undone": {
242
+ "type": "object",
243
+ "additionalProperties": false,
244
+ "required": ["wftoolbar_button_", "keyboard_shortcut_"],
245
+ "properties": {
246
+ "wftoolbar_button_": {
247
+ "$ref": "#/definitions/EmptyPayload"
248
+ },
249
+ "keyboard_shortcut_": {
250
+ "$ref": "#/definitions/EmptyPayload"
251
+ }
252
+ }
253
+ },
254
+ "action_redone": {
255
+ "type": "object",
256
+ "additionalProperties": false,
257
+ "required": ["wftoolbar_button_", "keyboard_shortcut_"],
258
+ "properties": {
259
+ "wftoolbar_button_": {
260
+ "$ref": "#/definitions/EmptyPayload"
261
+ },
262
+ "keyboard_shortcut_": {
263
+ "$ref": "#/definitions/EmptyPayload"
264
+ }
265
+ }
266
+ }
267
+ }
268
+ }
269
+ },
270
+ "definitions": {
271
+ "EmptyPayload": {
272
+ "type": "null",
273
+ "additionalProperties": false,
274
+ "maxProperties": 0
275
+ },
276
+ "WorkflowSavedPayload": {
277
+ "type": "object",
278
+ "additionalProperties": false,
279
+ "required": ["isAutosyncEnabled"],
280
+ "properties": {
281
+ "isAutosyncEnabled": {
282
+ "type": "boolean"
283
+ }
284
+ }
285
+ },
286
+ "ConnectionCreated_NodePayload": {
287
+ "type": "object",
288
+ "additionalProperties": false,
289
+ "required": ["nodeType", "nodePortIndex", "nodePortId"],
290
+ "properties": {
291
+ "nodeType": {
292
+ "type": "string",
293
+ "enum": ["node", "component", "metanode"]
294
+ },
295
+ "nodePortIndex": {
296
+ "type": "number"
297
+ },
298
+ "nodePortId": {
299
+ "type": "string"
300
+ },
301
+ "nodeFactoryId": {
302
+ "type": "string"
303
+ }
304
+ }
305
+ },
306
+ "ConnectionCreatedPayload": {
307
+ "type": "object",
308
+ "additionalProperties": false,
309
+ "required": ["fromNode", "toNode"],
310
+ "properties": {
311
+ "fromNode": {
312
+ "$ref": "#/definitions/ConnectionCreated_NodePayload"
313
+ },
314
+ "toNode": {
315
+ "$ref": "#/definitions/ConnectionCreated_NodePayload"
316
+ }
317
+ }
318
+ },
319
+ "KaiPromptedPayload": {
320
+ "type": "object",
321
+ "additionalProperties": false,
322
+ "properties": {
323
+ "nodeFactoryId": {
324
+ "type": "string"
325
+ },
326
+ "nodeType": {
327
+ "type": "string",
328
+ "enum": ["node", "component", "metanode"]
329
+ }
330
+ }
331
+ },
332
+ "NodeOrComponent": {
333
+ "type": "object",
334
+ "additionalProperties": false,
335
+ "properties": {
336
+ "nodeFactoryId": {
337
+ "type": "string",
338
+ "$comment": "asdasd"
339
+ },
340
+ "nodeHubId": {
341
+ "type": "string"
342
+ }
343
+ }
344
+ },
345
+ "NodeCreated_Common": {
346
+ "type": "object",
347
+ "additionalProperties": false,
348
+ "required": ["nodeType"],
349
+ "properties": {
350
+ "nodeType": {
351
+ "type": "string",
352
+ "enum": ["node", "component"]
353
+ }
354
+ }
355
+ },
356
+ "ConnectedTo_Basic": {
357
+ "type": "object",
358
+ "additionalProperties": false,
359
+ "required": ["nodeType", "nodeFactoryId"],
360
+ "properties": {
361
+ "nodeType": {
362
+ "type": "string",
363
+ "enum": ["node", "component", "metanode"]
364
+ },
365
+ "nodeFactoryId": {
366
+ "type": "string"
367
+ }
368
+ }
369
+ },
370
+ "ConnectedTo_WithPorts": {
371
+ "type": "object",
372
+ "additionalProperties": false,
373
+ "required": ["nodeType", "nodeFactoryId"],
374
+ "properties": {
375
+ "nodeType": {
376
+ "type": "string",
377
+ "enum": ["node", "component", "metanode"]
378
+ },
379
+ "nodeFactoryId": {
380
+ "type": "string"
381
+ },
382
+ "nodePortIndex": {
383
+ "type": "number"
384
+ },
385
+ "nodePortId": {
386
+ "type": "string"
387
+ }
388
+ }
389
+ },
390
+ "NodeCreated_Base": {
391
+ "allOf": [
392
+ {
393
+ "$ref": "#/definitions/NodeCreated_Common"
394
+ },
395
+ {
396
+ "$ref": "#/definitions/NodeOrComponent"
397
+ }
398
+ ]
399
+ },
400
+ "NodeCreated_WithOptionalConnectedTo": {
401
+ "allOf": [
402
+ {
403
+ "$ref": "#/definitions/NodeCreated_Common"
404
+ },
405
+ {
406
+ "$ref": "#/definitions/NodeOrComponent"
407
+ },
408
+ {
409
+ "type": "object",
410
+ "additionalProperties": false,
411
+ "properties": {
412
+ "connectedTo": {
413
+ "$ref": "#/definitions/ConnectedTo_Basic"
414
+ }
415
+ }
416
+ }
417
+ ]
418
+ },
419
+ "NodeCreated_WithOptionalConnectedToPorts": {
420
+ "allOf": [
421
+ {
422
+ "$ref": "#/definitions/NodeCreated_Common"
423
+ },
424
+ {
425
+ "$ref": "#/definitions/NodeOrComponent"
426
+ },
427
+ {
428
+ "type": "object",
429
+ "additionalProperties": false,
430
+ "properties": {
431
+ "connectedTo": {
432
+ "$ref": "#/definitions/ConnectedTo_WithPorts"
433
+ }
434
+ }
435
+ }
436
+ ]
437
+ },
438
+ "QAMOpened_Payload": {
439
+ "type": "object",
440
+ "additionalProperties": false,
441
+ "required": ["connectedTo"],
442
+ "properties": {
443
+ "connectedTo": {
444
+ "$ref": "#/definitions/ConnectedTo_WithPorts"
445
+ }
446
+ }
447
+ },
448
+ "QAMOpened_PartialPayload": {
449
+ "type": "object",
450
+ "additionalProperties": false,
451
+ "properties": {
452
+ "connectedTo": {
453
+ "$ref": "#/definitions/ConnectedTo_WithPorts"
454
+ }
455
+ }
456
+ },
457
+ "SearchPayload": {
458
+ "type": "object",
459
+ "additionalProperties": false,
460
+ "required": ["repoType", "keyword"],
461
+ "properties": {
462
+ "repoType": {
463
+ "type": "string",
464
+ "enum": ["node", "component"]
465
+ },
466
+ "keyword": {
467
+ "type": "string"
468
+ }
469
+ }
470
+ }
471
+ }
472
+ }
@@ -0,0 +1,62 @@
1
+ import type { AnalyticsEventSchema } from "./schema/schema";
2
+
3
+ export const SEPARATOR = "::";
4
+ type Separator = typeof SEPARATOR;
5
+
6
+ type EventDefinitions = AnalyticsEventSchema["events"];
7
+
8
+ /**
9
+ * Group names (top-level keys in `events`, e.g. "kai_prompted").
10
+ */
11
+ type GroupName = keyof EventDefinitions;
12
+
13
+ /**
14
+ * Event names in the flattened "group::event" form. This makes event calls
15
+ * single keys using the `::` separator (for example "kai_prompted::kaiqa_button_prompt").
16
+ */
17
+ export type EventNames = {
18
+ [G in GroupName]: `${G}${Separator}${keyof EventDefinitions[G] & string}`;
19
+ }[GroupName];
20
+
21
+ export type Metadata = Omit<AnalyticsEventSchema, "events">;
22
+
23
+ export type Context = { jobId: string };
24
+
25
+ /**
26
+ * Resolve the payload type for a flattened event name like
27
+ * "group::eventKey". If the referenced payload is `null`, the args are
28
+ * just the type; otherwise a payload must be provided.
29
+ */
30
+ type PayloadFor<KN extends EventNames> =
31
+ KN extends `${infer G}${Separator}${infer E}`
32
+ ? G extends GroupName
33
+ ? E extends keyof EventDefinitions[G]
34
+ ? EventDefinitions[G][E]
35
+ : never
36
+ : never
37
+ : never;
38
+
39
+ type EventArgs<K extends EventNames> =
40
+ PayloadFor<K> extends null
41
+ ? { id: K; payload?: never }
42
+ : { id: K; payload: PayloadFor<K> };
43
+
44
+ export type AnalyticsPayload = {
45
+ id: string;
46
+ data: unknown;
47
+ };
48
+
49
+ export type CreateEventFn<TReturn = void> = <K extends EventNames>(
50
+ args: EventArgs<K>,
51
+ ) => TReturn;
52
+
53
+ export interface AnalyticsAdapter {
54
+ /**
55
+ * Function to send the event according to the API the adapter is implementing
56
+ */
57
+ sendEvent: (params: {
58
+ idParser: (id: string) => { category: string; action: string };
59
+ event: AnalyticsPayload;
60
+ metadata: Metadata;
61
+ }) => void;
62
+ }
@@ -0,0 +1,35 @@
1
+ import { SEPARATOR } from "../types";
2
+
3
+ const isValid = (id: string) => id.includes(SEPARATOR);
4
+
5
+ /**
6
+ * Parses the given event id, splitting it by a known separator. Each id is expected to have
7
+ * two components to it: The event category and a specific action within that category
8
+ * @returns
9
+ * @throws when id format is invalid
10
+ */
11
+ const parse = (id: string): { category: string; action: string } => {
12
+ if (!isValid(id)) {
13
+ throw new Error(`Cannot parse event id. Invalid format found: ${id}`);
14
+ }
15
+
16
+ const out = id.split(SEPARATOR);
17
+
18
+ if (out.length !== 2) {
19
+ throw new Error(`Cannot parse event id. Invalid format found: ${id}`);
20
+ }
21
+
22
+ const [category, action] = out;
23
+ return { category, action };
24
+ };
25
+
26
+ export const eventID = (id: string) => ({
27
+ isValid: () => isValid(id),
28
+ /**
29
+ * Parses the given event id, splitting it by a known separator. Each id is expected to have
30
+ * two components to it: The event category and a specific action within that category
31
+ * @returns
32
+ * @throws when id format is invalid
33
+ */
34
+ parse: () => parse(id),
35
+ });
@@ -0,0 +1,33 @@
1
+ // eslint-disable-next-line depend/ban-dependencies
2
+ import { snakeCase } from "lodash-es";
3
+
4
+ const isPlainObject = (value: unknown): value is Record<string, unknown> => {
5
+ return (
6
+ typeof value === "object" &&
7
+ value !== null &&
8
+ Object.getPrototypeOf(value) === Object.prototype
9
+ );
10
+ };
11
+
12
+ /**
13
+ * Deeply converts all properties in the given object from camelCase to snake_case.
14
+ */
15
+ export const toSnakeCaseDeep = (object: Partial<Record<string, unknown>>) =>
16
+ Object.entries(object).reduce(
17
+ (acc, [rawKey, rawValue]) => {
18
+ const key = rawKey.toString();
19
+
20
+ if (isPlainObject(rawValue)) {
21
+ acc[snakeCase(key)] = toSnakeCaseDeep(rawValue);
22
+ } else if (Array.isArray(rawValue)) {
23
+ acc[snakeCase(key)] = rawValue.map((v) =>
24
+ isPlainObject(v) ? toSnakeCaseDeep(v) : v,
25
+ );
26
+ } else {
27
+ acc[snakeCase(key)] = rawValue;
28
+ }
29
+
30
+ return acc;
31
+ },
32
+ {} as Record<string, unknown>,
33
+ );