@kestra-io/ui-libs 0.0.301 → 0.0.302

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 (31) hide show
  1. package/dist/VueFlowUtils-Cck2rgf6.cjs +2 -0
  2. package/dist/VueFlowUtils-Cck2rgf6.cjs.map +1 -0
  3. package/dist/{VueFlowUtils-Ca_LeFFY.js → VueFlowUtils-l5Oh8tEj.js} +753 -751
  4. package/dist/VueFlowUtils-l5Oh8tEj.js.map +1 -0
  5. package/dist/components/nodes/TaskNode.vue.d.ts +17 -7
  6. package/dist/components/nodes/TaskNode.vue.d.ts.map +1 -1
  7. package/dist/components/topology/Topology.vue.d.ts +11 -5
  8. package/dist/components/topology/Topology.vue.d.ts.map +1 -1
  9. package/dist/components/topology/injectionKeys.d.ts +2 -1
  10. package/dist/components/topology/injectionKeys.d.ts.map +1 -1
  11. package/dist/kestra-index.cjs +15 -15
  12. package/dist/kestra-index.cjs.map +1 -1
  13. package/dist/kestra-index.mjs +3935 -3850
  14. package/dist/kestra-index.mjs.map +1 -1
  15. package/dist/kestra-vueflowutils.cjs +1 -1
  16. package/dist/kestra-vueflowutils.mjs +1 -1
  17. package/dist/ui-libs.css +1 -1
  18. package/dist/utils/VueFlowUtils.d.ts +1 -1
  19. package/dist/utils/VueFlowUtils.d.ts.map +1 -1
  20. package/dist/utils/constants.d.ts +3 -1
  21. package/dist/utils/constants.d.ts.map +1 -1
  22. package/package.json +1 -1
  23. package/src/components/nodes/TaskNode.vue +115 -23
  24. package/src/components/topology/Topology.vue +112 -16
  25. package/src/components/topology/injectionKeys.ts +3 -2
  26. package/src/components/topology/topology.scss +38 -1
  27. package/src/utils/VueFlowUtils.ts +3 -2
  28. package/src/utils/constants.ts +3 -1
  29. package/dist/VueFlowUtils-Ca_LeFFY.js.map +0 -1
  30. package/dist/VueFlowUtils-CscPDexP.cjs +0 -2
  31. package/dist/VueFlowUtils-CscPDexP.cjs.map +0 -1
@@ -31,6 +31,7 @@
31
31
  :playground-enabled="playgroundEnabled"
32
32
  :playground-ready-to-start="playgroundReadyToStart"
33
33
  :custom-actions="customActions"
34
+ :show-details="showDetails"
34
35
  @edit="emit(EVENTS.EDIT, $event)"
35
36
  @delete="emit(EVENTS.DELETE, $event)"
36
37
  @run-task="emit(EVENTS.RUN_TASK, $event)"
@@ -40,6 +41,7 @@
40
41
  @show-description="emit(EVENTS.SHOW_DESCRIPTION, $event)"
41
42
  @show-condition="emit(EVENTS.SHOW_CONDITION, $event)"
42
43
  @show-custom-action="emit(EVENTS.SHOW_CUSTOM_ACTION, $event)"
44
+ @show-details="emit(EVENTS.SHOW_DETAILS, $event)"
43
45
  @mouseover="onMouseOver($event)"
44
46
  @mouseleave="onMouseLeave()"
45
47
  @add-error="emit('on-add-flowable-error', $event)"
@@ -89,11 +91,17 @@
89
91
  />
90
92
  </template>
91
93
 
92
- <Controls v-if="controlsShown" :show-interactive="false">
94
+ <Controls v-if="controlsShown" :show-interactive="false" :show-fit-view="false">
95
+ <ControlButton @click="showExtraDetails = !showExtraDetails" :class="{'active': showExtraDetails}">
96
+ <Information />
97
+ </ControlButton>
98
+ <ControlButton @click="fitView()">
99
+ <svg viewBox="0 0 32 32" style="width:12px;height:12px"><path d="M3.692 4.63c0-.53.4-.938.939-.938h5.215V0H4.708C2.13 0 0 2.054 0 4.63v5.216h3.692V4.631zM27.354 0h-5.2v3.692h5.17c.53 0 .984.4.984.939v5.215H32V4.631A4.624 4.624 0 0 0 27.354 0zm.954 24.83c0 .532-.4.94-.939.94h-5.215v3.768h5.215c2.577 0 4.631-2.13 4.631-4.707v-5.139h-3.692v5.139zm-23.677.94a.919.919 0 0 1-.939-.94v-5.138H0v5.139c0 2.577 2.13 4.707 4.708 4.707h5.138V25.77H4.631z" fill="currentColor" /></svg>
100
+ </ControlButton>
93
101
  <ControlButton @click="emit('toggle-orientation', $event)" v-if="toggleOrientationButton">
94
102
  <component :is="isHorizontal ? SplitCellsHorizontal : SplitCellsVertical" />
95
103
  </ControlButton>
96
- <ControlButton @click="toggleDropdown">
104
+ <ControlButton @click="toggleDropdown">
97
105
  <Download />
98
106
  </ControlButton>
99
107
  <ul v-if="isDropdownOpen" class="exporting">
@@ -128,13 +136,14 @@
128
136
  // @ts-expect-error no types for internals necessary
129
137
  import SplitCellsHorizontal from "../../assets/icons/SplitCellsHorizontal.vue";
130
138
  import Download from "vue-material-design-icons/Download.vue";
139
+ import Information from "vue-material-design-icons/Information.vue";
131
140
  import {cssVariable} from "../../utils/global";
132
- import {CLUSTER_PREFIX, CustomActionConfig, EVENTS} from "../../utils/constants"
141
+ import {CLUSTER_PREFIX, EVENTS, NODE_SIZES, ShowDetailsConfig} from "../../utils/constants"
133
142
  import Utils from "../../utils/Utils"
134
143
  import * as VueFlowUtils from "../../utils/VueFlowUtils";
135
144
  import {isParentChildrenRelation, swapBlocks} from "../../utils/FlowYamlUtils";
136
145
  import {useScreenshot} from "./export/useScreenshot";
137
- import {EXECUTION_INJECTION_KEY, SUBFLOWS_EXECUTIONS_INJECTION_KEY} from "./injectionKeys";
146
+ import {EXECUTION_INJECTION_KEY, SUBFLOWS_EXECUTIONS_INJECTION_KEY, SHOW_EXTRA_DETAILS_INJECTION_KEY} from "./injectionKeys";
138
147
  import BasicNode from "../nodes/BasicNode.vue";
139
148
 
140
149
  const props = withDefaults(defineProps<{
@@ -156,7 +165,9 @@
156
165
  playgroundEnabled?: boolean;
157
166
  playgroundReadyToStart?: boolean;
158
167
  getNodeDimensions?: (node: any, getNodeWidth: (node: any) => number, getNodeHeight: (node: any) => number) => { width: number, height: number };
159
- customActions?: Record<string, CustomActionConfig>;
168
+ customActions?: Record<string, ShowDetailsConfig>;
169
+ showDetails?: Record<string, ShowDetailsConfig>;
170
+ animated?: boolean;
160
171
  }>(), {
161
172
  isHorizontal: true,
162
173
  isReadOnly: true,
@@ -173,10 +184,53 @@
173
184
  playgroundReadyToStart: false,
174
185
  subflowsExecutions: () => ({}),
175
186
  getNodeDimensions: undefined,
176
- customActions: () => ({})
187
+ customActions: () => ({}),
188
+ showDetails: () => ({}),
189
+ animated: true
177
190
  });
178
191
 
179
192
  const dragging = ref(false);
193
+ const showExtraDetails = ref(false);
194
+ const HOVERED_NODE_CLASS = "topology-node-hovered";
195
+ const DROP_TARGET_NODE_CLASS = "topology-node-drop-target";
196
+ const effectiveGetNodeDimensions = computed(() => {
197
+ return (node: any, getNodeWidth: (node: any) => number, getNodeHeight: (node: any) => number) => {
198
+ const baseHeight = getNodeHeight(node);
199
+ const dimensions = props.getNodeDimensions
200
+ ? props.getNodeDimensions(node, getNodeWidth, getNodeHeight)
201
+ : {
202
+ width: getNodeWidth(node),
203
+ height: baseHeight
204
+ };
205
+
206
+ if (!showExtraDetails.value && VueFlowUtils.isTaskNode(node)) {
207
+ return {
208
+ ...dimensions,
209
+ height: baseHeight
210
+ };
211
+ }
212
+
213
+ if (showExtraDetails.value && VueFlowUtils.isTaskNode(node)) {
214
+ const taskType = node?.task?.type as string | undefined;
215
+ const hasDetailsAction = Boolean(
216
+ (taskType && props.customActions?.[taskType]) ||
217
+ (taskType && props.showDetails?.[taskType])
218
+ );
219
+
220
+ if (hasDetailsAction) {
221
+ return {
222
+ ...dimensions,
223
+ height: Math.max(
224
+ dimensions.height,
225
+ NODE_SIZES.TASK_EXPANDED_FALLBACK_HEIGHT
226
+ )
227
+ };
228
+ }
229
+ }
230
+
231
+ return dimensions;
232
+ };
233
+ });
180
234
  const lastPosition = ref<XYPosition | null>()
181
235
  const {getNodes, onNodeDrag, onNodeDragStart, onNodeDragStop, fitView, setElements, vueFlowRef} = useVueFlow(props.id);
182
236
  const edgeReplacer = ref({});
@@ -187,6 +241,7 @@
187
241
 
188
242
  provide(EXECUTION_INJECTION_KEY, computed(() => props.execution));
189
243
  provide(SUBFLOWS_EXECUTIONS_INJECTION_KEY, computed(() => props.subflowsExecutions));
244
+ provide(SHOW_EXTRA_DETAILS_INJECTION_KEY, showExtraDetails);
190
245
 
191
246
 
192
247
  const emit = defineEmits(
@@ -206,7 +261,8 @@
206
261
  "message",
207
262
  "expand-subflow",
208
263
  EVENTS.SHOW_CONDITION,
209
- EVENTS.SHOW_CUSTOM_ACTION
264
+ EVENTS.SHOW_CUSTOM_ACTION,
265
+ EVENTS.SHOW_DETAILS
210
266
  ]
211
267
  )
212
268
 
@@ -223,6 +279,10 @@
223
279
  generateGraph();
224
280
  })
225
281
 
282
+ watch(showExtraDetails, () => {
283
+ generateGraph();
284
+ })
285
+
226
286
  const generateGraph = () => {
227
287
  VueFlowUtils.cleanGraph(props.id);
228
288
 
@@ -250,7 +310,8 @@
250
310
  props.isReadOnly,
251
311
  props.isAllowedEdit,
252
312
  props.enableSubflowInteraction,
253
- props.getNodeDimensions
313
+ effectiveGetNodeDimensions.value,
314
+ props.animated
254
315
  );
255
316
 
256
317
  if(elements) {
@@ -266,8 +327,8 @@
266
327
  if (!dragging.value) {
267
328
  VueFlowUtils.linkedElements(props.id, node.uid).forEach((n) => {
268
329
  if (n?.type === "task") {
269
- n.style = {...n.style, outline: "0.5px solid " + cssVariable("--bs-gray-900")}
270
- n.class = "rounded-3"
330
+ n.style = {...n.style, opacity: "1", outline: "none"}
331
+ setNodeInteractionClass(n, HOVERED_NODE_CLASS, true);
271
332
  }
272
333
  });
273
334
  }
@@ -282,7 +343,7 @@
282
343
  getNodes.value.filter(n => n.type === "task" || n.type === "trigger")
283
344
  .forEach(n => {
284
345
  n.style = {...n.style, opacity: "1", outline: "none"}
285
- n.class = ""
346
+ clearNodeInteractionClasses(n);
286
347
  })
287
348
  }
288
349
 
@@ -352,15 +413,50 @@
352
413
  if (e.intersections && !checkIntersections(e.intersections, e.node) && e.intersections.filter((n:any) => n.type === "task").length === 1) {
353
414
  e.intersections.forEach((n:any) => {
354
415
  if (n.type === "task") {
355
- n.style = {...n.style, outline: "0.5px solid " + cssVariable("--bs-primary")}
356
- n.class = "rounded-3"
416
+ n.style = {...n.style, outline: "none"}
417
+ setNodeInteractionClass(n, DROP_TARGET_NODE_CLASS, true);
357
418
  }
358
419
  })
359
- e.node.style = {...e.node.style, outline: "0.5px solid " + cssVariable("--bs-primary")}
360
- e.node.class = "rounded-3"
420
+ e.node.style = {...e.node.style, outline: "none"}
421
+ setNodeInteractionClass(e.node, DROP_TARGET_NODE_CLASS, true);
361
422
  }
362
423
  })
363
424
 
425
+ const normalizeNodeClasses = (value: unknown): string[] => {
426
+ if (typeof value === "string") {
427
+ return value.split(/\s+/).filter(Boolean);
428
+ }
429
+
430
+ if (Array.isArray(value)) {
431
+ return value.flatMap((entry) => normalizeNodeClasses(entry));
432
+ }
433
+
434
+ if (value && typeof value === "object") {
435
+ return Object.entries(value as Record<string, boolean>)
436
+ .filter(([, enabled]) => Boolean(enabled))
437
+ .map(([className]) => className);
438
+ }
439
+
440
+ return [];
441
+ };
442
+
443
+ const setNodeInteractionClass = (node: any, className: string, enabled: boolean) => {
444
+ const classes = new Set(normalizeNodeClasses(node.class));
445
+
446
+ if (enabled) {
447
+ classes.add(className);
448
+ } else {
449
+ classes.delete(className);
450
+ }
451
+
452
+ node.class = Array.from(classes).join(" ");
453
+ };
454
+
455
+ const clearNodeInteractionClasses = (node: any) => {
456
+ setNodeInteractionClass(node, HOVERED_NODE_CLASS, false);
457
+ setNodeInteractionClass(node, DROP_TARGET_NODE_CLASS, false);
458
+ };
459
+
364
460
  const checkIntersections = (intersections:any, node:any) => {
365
461
  const tasksMeet = intersections.filter((n:any) => n.type === "task").map((n:any) => Utils.afterLastDot(n.id));
366
462
  if (tasksMeet.length > 1) {
@@ -489,4 +585,4 @@
489
585
  }
490
586
  }
491
587
  }
492
- </style>
588
+ </style>
@@ -1,4 +1,5 @@
1
- import type {ComputedRef, InjectionKey} from "vue"
1
+ import type {ComputedRef, InjectionKey, Ref} from "vue"
2
2
 
3
3
  export const EXECUTION_INJECTION_KEY = Symbol("execution-injection-key") as InjectionKey<ComputedRef<any>>
4
- export const SUBFLOWS_EXECUTIONS_INJECTION_KEY = Symbol("subflows-executions-injection-key") as InjectionKey<ComputedRef<Record<string, any[]>>>
4
+ export const SUBFLOWS_EXECUTIONS_INJECTION_KEY = Symbol("subflows-executions-injection-key") as InjectionKey<ComputedRef<Record<string, any[]>>>
5
+ export const SHOW_EXTRA_DETAILS_INJECTION_KEY = Symbol("show-extra-details-injection-key") as InjectionKey<Ref<boolean>>
@@ -31,6 +31,10 @@ $node-colors: (
31
31
  font-size: 0.66rem;
32
32
  }
33
33
 
34
+ .vue-flow__panel.vue-flow__controls {
35
+ z-index: 200001;
36
+ }
37
+
34
38
  .vue-flow__controls {
35
39
  border: 1px solid var(--ks-border-primary);
36
40
  border-radius: var(--bs-border-radius);
@@ -40,10 +44,26 @@ $node-colors: (
40
44
  color: var(--bs-black);
41
45
  border-bottom-color: var(--bs-border-color);
42
46
 
47
+ .material-design-icon {
48
+ display: flex;
49
+ align-items: center;
50
+ justify-content: center;
51
+ line-height: 0;
52
+
53
+ svg {
54
+ width: 12px;
55
+ height: 12px;
56
+ }
57
+ }
58
+
43
59
  svg {
44
60
  fill: var(--bs-black);
45
61
  }
46
62
 
63
+ &.active svg {
64
+ fill: var(--ks-content-link);
65
+ }
66
+
47
67
  html.dark & {
48
68
  background: var(--ks-background-card);
49
69
  color: var(--bs-white);
@@ -51,6 +71,10 @@ $node-colors: (
51
71
  svg {
52
72
  fill: var(--bs-white);
53
73
  }
74
+
75
+ &.active svg {
76
+ fill: var(--ks-content-link);
77
+ }
54
78
  }
55
79
  }
56
80
 
@@ -59,6 +83,19 @@ $node-colors: (
59
83
  }
60
84
 
61
85
  .vue-flow__container {
86
+ .vue-flow__node.topology-node-hovered,
87
+ .vue-flow__node.topology-node-drop-target {
88
+ outline: none !important;
89
+ }
90
+
91
+ .vue-flow__node.topology-node-hovered .node-wrapper {
92
+ border-color: var(--bs-gray-900) !important;
93
+ }
94
+
95
+ .vue-flow__node.topology-node-drop-target .node-wrapper {
96
+ border-color: var(--bs-primary) !important;
97
+ }
98
+
62
99
  .top-button-div {
63
100
  position: absolute;
64
101
  top: -0.5rem;
@@ -97,4 +134,4 @@ $node-colors: (
97
134
  .circle-button {
98
135
  display: none !important;
99
136
  }
100
- }
137
+ }
@@ -436,7 +436,8 @@ export function generateGraph(
436
436
  = (node, getNodeWidth, getNodeHeight) => ({
437
437
  width: getNodeWidth(node),
438
438
  height: getNodeHeight(node)
439
- })
439
+ }),
440
+ animated: boolean = true
440
441
  ): Elements | undefined {
441
442
  const elements: Elements = [];
442
443
 
@@ -699,7 +700,7 @@ export function generateGraph(
699
700
  style: {
700
701
  zIndex: 10,
701
702
  },
702
- animated: true,
703
+ animated: animated,
703
704
  });
704
705
  }
705
706
  }
@@ -20,9 +20,10 @@ export const EVENTS = {
20
20
  SHOW_CONDITION: "showCondition",
21
21
  RUN_TASK: "runTask",
22
22
  SHOW_CUSTOM_ACTION: "showCustomAction",
23
+ SHOW_DETAILS: "showDetails",
23
24
  } as const;
24
25
 
25
- export interface CustomActionConfig {
26
+ export interface ShowDetailsConfig {
26
27
  label: string;
27
28
  taskProp: string;
28
29
  lang: string;
@@ -33,6 +34,7 @@ export const CLUSTER_PREFIX = "cluster_";
33
34
  export const NODE_SIZES = {
34
35
  TASK_WIDTH: 184,
35
36
  TASK_HEIGHT: 44,
37
+ TASK_EXPANDED_FALLBACK_HEIGHT: 140,
36
38
  TRIGGER_WIDTH: 184,
37
39
  TRIGGER_HEIGHT: 44,
38
40
  DOT_WIDTH: 5,