@kestra-io/ui-libs 0.0.227 → 0.0.229

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 (58) hide show
  1. package/dist/{FlowYamlUtils-MCAmyY3D.js → FlowYamlUtils-BrY8bEv7.js} +24 -17
  2. package/dist/{FlowYamlUtils-MCAmyY3D.js.map → FlowYamlUtils-BrY8bEv7.js.map} +1 -1
  3. package/dist/{FlowYamlUtils-DAm_-0Qh.cjs → FlowYamlUtils-DvtepVr2.cjs} +3 -2
  4. package/dist/{FlowYamlUtils-DAm_-0Qh.cjs.map → FlowYamlUtils-DvtepVr2.cjs.map} +1 -1
  5. package/dist/VueFlowUtils-BhTB7zMW.cjs +2 -0
  6. package/dist/VueFlowUtils-BhTB7zMW.cjs.map +1 -0
  7. package/dist/{VueFlowUtils-A_7_qgxS.js → VueFlowUtils-BmNdCDFy.js} +461 -452
  8. package/dist/VueFlowUtils-BmNdCDFy.js.map +1 -0
  9. package/dist/assets/icons/RotatingDots.vue.d.ts +6 -0
  10. package/dist/assets/icons/RotatingDots.vue.d.ts.map +1 -0
  11. package/dist/components/misc/Collapsible.vue.d.ts.map +1 -1
  12. package/dist/components/misc/ExecutionInformations.vue.d.ts +1 -0
  13. package/dist/components/misc/ExecutionInformations.vue.d.ts.map +1 -1
  14. package/dist/components/nodes/BasicNode.vue.d.ts +44 -113
  15. package/dist/components/nodes/BasicNode.vue.d.ts.map +1 -1
  16. package/dist/components/nodes/EdgeNode.vue.d.ts +5 -7
  17. package/dist/components/nodes/EdgeNode.vue.d.ts.map +1 -1
  18. package/dist/components/nodes/TaskNode.vue.d.ts +48 -240
  19. package/dist/components/nodes/TaskNode.vue.d.ts.map +1 -1
  20. package/dist/components/plugins/PluginIndex.vue.d.ts +2 -8
  21. package/dist/components/plugins/PluginIndex.vue.d.ts.map +1 -1
  22. package/dist/components/topology/Topology.vue.d.ts +13 -4
  23. package/dist/components/topology/Topology.vue.d.ts.map +1 -1
  24. package/dist/components/topology/injectionKeys.d.ts +0 -1
  25. package/dist/components/topology/injectionKeys.d.ts.map +1 -1
  26. package/dist/index.d.ts +1 -0
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/kestra-flowyamlutils.cjs.js +1 -1
  29. package/dist/kestra-flowyamlutils.es.js +1 -1
  30. package/dist/kestra-index.cjs.js +15 -15
  31. package/dist/kestra-index.cjs.js.map +1 -1
  32. package/dist/kestra-index.es.js +3611 -3656
  33. package/dist/kestra-index.es.js.map +1 -1
  34. package/dist/kestra-vueflowutils.cjs.js +1 -1
  35. package/dist/kestra-vueflowutils.es.js +7 -7
  36. package/dist/ui-libs.css +1 -1
  37. package/dist/utils/FlowYamlUtils.d.ts.map +1 -1
  38. package/dist/utils/Utils.d.ts +14 -7
  39. package/dist/utils/Utils.d.ts.map +1 -1
  40. package/dist/utils/state.d.ts +1 -0
  41. package/dist/utils/state.d.ts.map +1 -1
  42. package/package.json +1 -1
  43. package/src/assets/icons/RotatingDots.vue +25 -0
  44. package/src/components/misc/Collapsible.vue +2 -5
  45. package/src/components/misc/Duration.vue +2 -2
  46. package/src/components/misc/ExecutionInformations.vue +6 -36
  47. package/src/components/nodes/BasicNode.vue +121 -152
  48. package/src/components/nodes/TaskNode.vue +265 -189
  49. package/src/components/topology/Topology.vue +8 -3
  50. package/src/components/topology/injectionKeys.ts +1 -2
  51. package/src/index.ts +1 -0
  52. package/src/utils/FlowYamlUtils.test.ts +11 -0
  53. package/src/utils/FlowYamlUtils.ts +16 -5
  54. package/src/utils/Utils.ts +48 -34
  55. package/src/utils/state.ts +4 -0
  56. package/dist/VueFlowUtils-A_7_qgxS.js.map +0 -1
  57. package/dist/VueFlowUtils-CL70qtJ4.cjs +0 -2
  58. package/dist/VueFlowUtils-CL70qtJ4.cjs.map +0 -1
@@ -7,26 +7,52 @@
7
7
  :class="classes"
8
8
  :icons="icons"
9
9
  :icon-component="iconComponent"
10
- @show-description="forwardEvent(EVENTS.SHOW_DESCRIPTION, $event)"
11
- @expand="forwardEvent(EVENTS.EXPAND, expandData)"
12
- @open-link="forwardEvent(EVENTS.OPEN_LINK, $event)"
13
- @mouseover="forwardEvent(EVENTS.MOUSE_OVER, $event)"
14
- @mouseleave="forwardEvent(EVENTS.MOUSE_LEAVE)"
10
+ @show-description="emit(EVENTS.SHOW_DESCRIPTION, $event)"
11
+ @expand="emit(EVENTS.EXPAND, expandData)"
12
+ @open-link="emit(EVENTS.OPEN_LINK, $event)"
13
+ @mouseover="emit(EVENTS.MOUSE_OVER, $event)"
14
+ @mouseleave="emit(EVENTS.MOUSE_LEAVE)"
15
15
  >
16
16
  <template #content>
17
- <execution-informations v-if="taskExecution" :execution="taskExecution" :task="data.node.task" :color="color" :uid="data.node.uid" />
18
- <button v-if="playgroundEnabled && data.node.task" type="button" class="playground-button" @click="$emit(EVENTS.RUN_TASK, {task: data.node.task})">
19
- <tooltip style="display: flex;" :title="$t('run task in playground')">
20
- <PlayIcon class="button-play-icon" alt="Play task" />
21
- </tooltip>
22
- </button>
17
+ <execution-informations
18
+ v-if="taskExecution"
19
+ :execution="taskExecution"
20
+ :task="data.node.task"
21
+ :color="color"
22
+ :uid="data.node.uid"
23
+ :state="state"
24
+ />
25
+
26
+ <template v-if="data.node.task">
27
+ <button v-if="playgroundEnabled && playgroundReadyToStart" type="button" class="playground-button" @click="emit(EVENTS.RUN_TASK, {task: data.node.task})">
28
+ <tooltip style="display: flex;" :title="$t('run task in playground')">
29
+ <PlayIcon class="button-play-icon" :alt="$t('run task in playground')" />
30
+ </tooltip>
31
+ </button>
32
+ <div
33
+ v-else
34
+ class="playground-button"
35
+ :style="{
36
+ color: `var(--ks-content-${state?.toLowerCase()})`,
37
+ backgroundColor: `var(--ks-background-${state?.toLowerCase()})`
38
+ }"
39
+ >
40
+ <tooltip style="display: flex;" :title="$t(iconAlt)">
41
+ <RotatingDots v-if="state === State.RUNNING" :alt="$t(iconAlt)" />
42
+ <CheckIcon v-else-if="state === State.SUCCESS" :alt="$t(iconAlt)" />
43
+ <AlertIcon v-else-if="state === State.WARNING" :alt="$t(iconAlt)" />
44
+ <SkipForwardIcon v-else-if="state === State.SKIPPED" :alt="$t(iconAlt)" />
45
+ <AlertCircleIcon v-else-if="state === State.FAILED" :alt="$t(iconAlt)" />
46
+ </tooltip>
47
+ </div>
48
+ </template>
23
49
  </template>
24
50
  <template #badge-button-before>
25
51
  <span
26
52
  v-if="data.node.task && data.node.task.runIf"
27
53
  class="circle-button"
28
54
  :class="[`bg-warning`]"
29
- @click="$emit(EVENTS.SHOW_CONDITION, {id: taskId, task: data.node.task, section: SECTIONS.TASKS})"
55
+ @click="emit(EVENTS.SHOW_CONDITION, {id: taskId, task: data.node.task, section: SECTIONS.TASKS})"
30
56
  >
31
57
  <tooltip :title="$t('show task condition')">
32
58
  <SendLock class="button-icon" alt="Show condition" />
@@ -36,7 +62,7 @@
36
62
  v-if="taskExecution"
37
63
  class="circle-button"
38
64
  :class="[`bg-${color}`]"
39
- @click="$emit(EVENTS.SHOW_LOGS, {id: taskId, execution: taskExecution, taskRuns})"
65
+ @click="emit(EVENTS.SHOW_LOGS, {id: taskId, execution: taskExecution, taskRuns})"
40
66
  >
41
67
  <tooltip :title="$t('show task logs')">
42
68
  <TextBoxSearch class="button-icon" alt="Show logs" />
@@ -46,7 +72,7 @@
46
72
  v-if="!taskExecution && !data.isReadOnly && data.isFlowable"
47
73
  class="circle-button"
48
74
  :class="[`bg-${color}`]"
49
- @click="$emit(EVENTS.ADD_ERROR, {task: data.node.task})"
75
+ @click="emit(EVENTS.ADD_ERROR, {task: data.node.task})"
50
76
  >
51
77
  <tooltip :title="$t('add error handler')">
52
78
  <AlertOutline class="button-icon" alt="Add error handler" />
@@ -56,7 +82,7 @@
56
82
  v-if="!taskExecution && !data.isReadOnly"
57
83
  class="circle-button"
58
84
  :class="[`bg-${color}`]"
59
- @click="$emit(EVENTS.EDIT, {task: data.node.task, section: SECTIONS.TASKS})"
85
+ @click="emit(EVENTS.EDIT, {task: data.node.task, section: SECTIONS.TASKS})"
60
86
  >
61
87
  <tooltip :title="$t('edit')">
62
88
  <Pencil class="button-icon" alt="Edit task" />
@@ -66,7 +92,7 @@
66
92
  v-if="!taskExecution && !data.isReadOnly"
67
93
  class="circle-button"
68
94
  :class="[`bg-${color}`]"
69
- @click="$emit(EVENTS.DELETE, {id: taskId, section: SECTIONS.TASKS})"
95
+ @click="emit(EVENTS.DELETE, {id: taskId, section: SECTIONS.TASKS})"
70
96
  >
71
97
  <tooltip :title="$t('delete')">
72
98
  <Delete class="button-icon" alt="Delete task" />
@@ -76,190 +102,235 @@
76
102
  </basic-node>
77
103
  <Handle type="target" :position="targetPosition" />
78
104
  </template>
79
- <script setup>
80
- import BasicNode from "./BasicNode.vue";
81
- </script>
82
- <script>
83
- import {Handle} from "@vue-flow/core";
105
+
106
+ <script setup lang="ts">
107
+ import {computed, inject} from "vue";
108
+ import {Handle, Position} from "@vue-flow/core";
84
109
  import State from "../../utils/state";
85
110
  import {EVENTS, SECTIONS} from "../../utils/constants";
86
111
  import ExecutionInformations from "../misc/ExecutionInformations.vue";
87
- import Pencil from "vue-material-design-icons/Pencil.vue";
88
- import Delete from "vue-material-design-icons/Delete.vue";
89
- import TextBoxSearch from "vue-material-design-icons/TextBoxSearch.vue";
90
- import AlertOutline from "vue-material-design-icons/AlertOutline.vue"
91
- import PlayIcon from "vue-material-design-icons/Play.vue";
92
- import SendLock from "vue-material-design-icons/SendLock.vue"
93
- import Tooltip from "../misc/Tooltip.vue"
112
+ import Tooltip from "../misc/Tooltip.vue";
94
113
  import Utils from "../../utils/Utils";
114
+ import BasicNode from "./BasicNode.vue";
95
115
  import {
96
- EXECUTION_INJECTION_KEY,
116
+ EXECUTION_INJECTION_KEY,
97
117
  SUBFLOWS_EXECUTIONS_INJECTION_KEY,
98
- PLAYGROUND_ENABLED_INJECTION_KEY
99
118
  } from "../topology/injectionKeys";
100
119
 
101
- export default {
102
- name: "Task",
103
- components: {
104
- Pencil,
105
- Delete,
106
- ExecutionInformations,
107
- Handle,
108
- TextBoxSearch,
109
- AlertOutline,
110
- Tooltip,
111
- SendLock
112
- },
113
- inheritAttrs: false,
114
- inject: {
115
- execution: {
116
- from: EXECUTION_INJECTION_KEY,
117
- },
118
- subflowsExecutions: {
119
- from: SUBFLOWS_EXECUTIONS_INJECTION_KEY,
120
- },
121
- playgroundEnabled: {
122
- from: PLAYGROUND_ENABLED_INJECTION_KEY,
123
- }
124
- },
125
- computed: {
126
- SECTIONS() {
127
- return SECTIONS
128
- },
129
- EVENTS() {
130
- return EVENTS
131
- },
132
- color() {
133
- return this.data.color ?? "primary"
134
- },
135
- taskId() {
136
- return Utils.afterLastDot(this.id);
137
- },
138
- taskRunList() {
139
- return this.taskExecution && this.taskExecution.taskRunList ? this.taskExecution.taskRunList : []
140
- },
141
- taskExecution() {
142
- const executionId = this.data.executionId;
143
- if(executionId) {
144
- return executionId === this.execution?.id ? this.execution
145
- : Object.values(this.subflowsExecutions).filter(execution => execution.id === this.data.executionId)?.[0];
146
- }
120
+ import Pencil from "vue-material-design-icons/Pencil.vue";
121
+ import Delete from "vue-material-design-icons/Delete.vue";
122
+ import TextBoxSearch from "vue-material-design-icons/TextBoxSearch.vue";
123
+ import AlertOutline from "vue-material-design-icons/AlertOutline.vue";
124
+ import SendLock from "vue-material-design-icons/SendLock.vue";
125
+ import PlayIcon from "vue-material-design-icons/Play.vue";
126
+ import CheckIcon from "vue-material-design-icons/Check.vue";
127
+ import AlertCircleIcon from "vue-material-design-icons/AlertCircle.vue";
128
+ import AlertIcon from "vue-material-design-icons/Alert.vue";
129
+ import SkipForwardIcon from "vue-material-design-icons/SkipForward.vue";
130
+ import RotatingDots from "../../assets/icons/RotatingDots.vue";
147
131
 
148
- return undefined;
149
- },
150
- taskRuns() {
151
- return this.taskRunList.filter(t => t.taskId === Utils.afterLastDot(this.data.node.uid))
152
- },
153
- state() {
154
- if (!this.taskRuns) {
155
- return null;
156
- }
132
+ // Define types
133
+ interface TaskType {
134
+ id: string;
135
+ type: object;
136
+ default: null;
137
+ runIf?: unknown;
138
+ subflowId?: {
139
+ namespace: string;
140
+ flowId: string;
141
+ };
142
+ namespace?: string;
143
+ flowId?: string;
144
+ }
157
145
 
158
- if (this.taskRuns.length === 1) {
159
- return this.taskRuns[0].state.current
160
- }
146
+ interface NodeData {
147
+ node: {
148
+ uid: string;
149
+ type?: string;
150
+ task: TaskType;
151
+ };
152
+ executionId?: string;
153
+ color?: string;
154
+ isReadOnly?: boolean;
155
+ isFlowable?: boolean;
156
+ link?: {
157
+ namespace: string;
158
+ id: string;
159
+ executionId?: string;
160
+ };
161
+ }
161
162
 
162
- const allStates = this.taskRuns.map(t => t.state.current);
163
+ interface TaskRun {
164
+ taskId: string;
165
+ state: {
166
+ current: [string, string]; // [state, stateText]
167
+ };
168
+ outputs?: {
169
+ executionId?: string;
170
+ };
171
+ }
163
172
 
164
- const SORT_STATUS = [
165
- State.FAILED,
166
- State.KILLED,
167
- State.WARNING,
168
- State.KILLING,
169
- State.RUNNING,
170
- State.SUCCESS,
171
- State.RESTARTED,
172
- State.CREATED,
173
- ];
173
+ interface ExpandData {
174
+ id: string;
175
+ type: string;
176
+ }
174
177
 
175
- // sorting based on SORT_STATUS array
176
- const result = allStates
177
- .map((item) => {
178
- const n = SORT_STATUS.indexOf(item[1]);
179
- SORT_STATUS[n] = undefined;
180
- return [n, item]
181
- })
182
- .sort()
183
- .map((j) => j[1])
184
- return result[0];
185
- },
186
- classes() {
187
- return {
188
- "execution-no-taskrun": this.taskExecution && this.taskRuns && this.taskRuns.length === 0,
189
- }
190
- },
191
- expandData() {
192
- return {
193
- id: this.id,
194
- type: this.data.node.task.type
195
- }
196
- },
197
- dataWithLink() {
198
- if(this.data.node.type?.endsWith("SubflowGraphTask") && this.enableSubflowInteraction){
199
- const subflowIdContainer = this.data.node.task.subflowId ?? this.data.node.task;
200
- return {
201
- ...this.data,
202
- link: {
203
- namespace: subflowIdContainer.namespace,
204
- id: subflowIdContainer.flowId,
205
- executionId: this.taskExecution?.taskRunList
206
- .filter(taskRun => taskRun.taskId === this.data.node.task.id && taskRun.outputs?.executionId)
207
- ?.[0]?.outputs?.executionId
208
- }
209
- }
178
+ const props = withDefaults(defineProps<{
179
+ data: NodeData;
180
+ sourcePosition?: Position;
181
+ targetPosition?: Position;
182
+ id: string;
183
+ icons?: Record<string, unknown>;
184
+ iconComponent?: object;
185
+ enableSubflowInteraction?: boolean;
186
+ playgroundEnabled: boolean;
187
+ playgroundReadyToStart: boolean;
188
+ }>(), {
189
+ sourcePosition: Position.Right,
190
+ targetPosition: Position.Left,
191
+ enableSubflowInteraction: true,
192
+ icons: undefined,
193
+ iconComponent: undefined,
194
+ });
195
+
196
+ defineOptions({
197
+ name: "TaskNode",
198
+ inheritAttrs: false
199
+ });
200
+
201
+ // Define emits
202
+ const emit = defineEmits<{
203
+ (event: typeof EVENTS.EXPAND, data: any): void;
204
+ (event: typeof EVENTS.OPEN_LINK, data: any): void;
205
+ (event: typeof EVENTS.SHOW_LOGS, data: any): void;
206
+ (event: typeof EVENTS.MOUSE_OVER, data: any): void;
207
+ (event: typeof EVENTS.MOUSE_LEAVE): void;
208
+ (event: typeof EVENTS.ADD_ERROR, data: { task: any }): void;
209
+ (event: typeof EVENTS.EDIT, data: any) :void;
210
+ (event: typeof EVENTS.DELETE, data: any) :void;
211
+ (event: typeof EVENTS.ADD_TASK, data: any) :void;
212
+ (event: typeof EVENTS.SHOW_CONDITION, data: any) :void;
213
+ (event: typeof EVENTS.SHOW_DESCRIPTION, data: any) :void;
214
+ (event: typeof EVENTS.RUN_TASK, data: { task: any }) :void;
215
+ }>();
216
+
217
+ // Inject dependencies
218
+ const execution = inject(EXECUTION_INJECTION_KEY);
219
+ const subflowsExecutions = inject(SUBFLOWS_EXECUTIONS_INJECTION_KEY);
220
+
221
+ // Computed properties
222
+ const color = computed(() => props.data.color ?? "primary");
223
+
224
+ const taskId = computed(() => Utils.afterLastDot(props.id));
225
+
226
+ const taskExecution = computed(() => {
227
+ const executionId = props.data.executionId;
228
+ if (executionId) {
229
+ return executionId === execution?.value?.id
230
+ ? execution?.value
231
+ : Object.values(subflowsExecutions?.value || {})
232
+ .find((exec: any) => exec.id === executionId);
233
+ }
234
+ return undefined;
235
+ });
236
+
237
+ const taskRunList = computed(() => {
238
+ return taskExecution.value && taskExecution.value.taskRunList
239
+ ? taskExecution.value.taskRunList
240
+ : [];
241
+ });
242
+
243
+ const taskRuns = computed(() => {
244
+ return taskRunList.value.filter(
245
+ (t: TaskRun) => t.taskId === Utils.afterLastDot(props.data.node.uid)
246
+ );
247
+ });
248
+
249
+ const state = computed(() => {
250
+ if (!taskRuns.value?.length) {
251
+ return null;
252
+ }
253
+
254
+ if (taskRuns.value.length === 1) {
255
+ return taskRuns.value[0].state.current;
256
+ }
257
+
258
+ const allStates = taskRuns.value.map((t: TaskRun) => t.state.current);
259
+
260
+ // Create a copy of SORT_STATUS array to avoid modifying the original
261
+ const SORT_STATUS = [
262
+ State.FAILED,
263
+ State.KILLED,
264
+ State.WARNING,
265
+ State.SKIPPED,
266
+ State.KILLING,
267
+ State.RUNNING,
268
+ State.SUCCESS,
269
+ State.RESTARTED,
270
+ State.CREATED,
271
+ ];
272
+
273
+ // Sort states based on priority
274
+ const result = allStates
275
+ .map((item: [string, string]) => {
276
+ const n = SORT_STATUS.indexOf(item[1]);
277
+ // Handle sorting without modifying the original array
278
+ return [n, item] as [number, [string, string]];
279
+ })
280
+ .sort()
281
+ .map((j: [number, [string, string]]) => j[1]);
282
+
283
+ return result[0];
284
+ });
285
+
286
+ const classes = computed(() => ({
287
+ "execution-no-taskrun":
288
+ Boolean(taskExecution.value && taskRuns.value && taskRuns.value.length === 0)
289
+ }));
290
+
291
+ const expandData = computed<ExpandData>(() => ({
292
+ id: props.id,
293
+ type: String(props.data.node.task.type)
294
+ }));
295
+
296
+ const dataWithLink = computed(() => {
297
+ if (props.data.node.type?.endsWith("SubflowGraphTask") && props.enableSubflowInteraction) {
298
+ const subflowIdContainer = props.data.node.task.subflowId ?? props.data.node.task;
299
+ return {
300
+ ...props.data,
301
+ link: {
302
+ namespace: subflowIdContainer.namespace,
303
+ id: subflowIdContainer.flowId,
304
+ executionId: taskExecution.value?.taskRunList
305
+ .filter((taskRun: TaskRun) =>
306
+ taskRun.taskId === props.data.node.task.id &&
307
+ taskRun.outputs?.executionId
308
+ )
309
+ ?.[0]?.outputs?.executionId
210
310
  }
311
+ };
312
+ }
313
+ return props.data;
314
+ });
211
315
 
212
- return this.data;
213
- }
214
- },
215
- emits: [
216
- EVENTS.EXPAND,
217
- EVENTS.OPEN_LINK,
218
- EVENTS.SHOW_LOGS,
219
- EVENTS.MOUSE_OVER,
220
- EVENTS.MOUSE_LEAVE,
221
- EVENTS.ADD_ERROR,
222
- EVENTS.EDIT,
223
- EVENTS.DELETE,
224
- EVENTS.ADD_TASK,
225
- EVENTS.SHOW_CONDITION
226
- ],
227
- props: {
228
- data: {
229
- type: Object,
230
- required: true,
231
- },
232
- sourcePosition: {
233
- type: String,
234
- required: true
235
- },
236
- targetPosition: {
237
- type: String,
238
- required: true
239
- },
240
- id: {
241
- type: String,
242
- required: true
243
- },
244
- icons: {
245
- type: Object,
246
- default: undefined
247
- },
248
- iconComponent: {
249
- type: Object,
250
- default: undefined
251
- },
252
- enableSubflowInteraction: {
253
- type: Boolean,
254
- default: true
255
- }
256
- },
257
- methods: {
258
- forwardEvent(event, payload) {
259
- this.$emit(event, payload)
260
- },
316
+ const iconAlt = computed(() => {
317
+ if(state.value === State.RUNNING){
318
+ return "task is running";
261
319
  }
262
- }
320
+ if(state.value === State.SUCCESS){
321
+ return "task was successful";
322
+ }
323
+ if(state.value === State.WARNING){
324
+ return "task sent a warning";
325
+ }
326
+ if(state.value === State.SKIPPED){
327
+ return "task was skipped";
328
+ }
329
+ if(state.value === State.FAILED){
330
+ return "task failed";
331
+ }
332
+ return "";
333
+ });
263
334
  </script>
264
335
 
265
336
  <style lang="scss" scoped>
@@ -271,13 +342,18 @@
271
342
  right: 0;
272
343
  z-index: 1;
273
344
  border: none;
274
- background: transparent;
275
- background-color: _color-palette.$base-blue-500;
276
- color: _color-palette.$base-white;
345
+ background-color: var(--ks-background-card);
277
346
  border-radius: 3px;
278
347
  height: 1rem;
279
348
  width: 1rem;
280
- padding: 0;
281
- margin: 6px
349
+ padding: .1rem;
350
+ margin: 6px;
351
+ font-size: .8rem;
352
+ }
353
+
354
+ button.playground-button,
355
+ .dark button.playground-button {
356
+ color: _color-palette.$base-white;
357
+ background-color: _color-palette.$base-blue-400;
282
358
  }
283
359
  </style>
@@ -28,6 +28,8 @@
28
28
  v-bind="taskProps"
29
29
  :icons="icons"
30
30
  :icon-component="iconComponent"
31
+ :playground-enabled="playgroundEnabled"
32
+ :playground-ready-to-start="playgroundReadyToStart"
31
33
  @edit="emit(EVENTS.EDIT, $event)"
32
34
  @delete="emit(EVENTS.DELETE, $event)"
33
35
  @run-task="emit(EVENTS.RUN_TASK, $event)"
@@ -91,6 +93,7 @@
91
93
  </Controls>
92
94
  </VueFlow>
93
95
  </template>
96
+
94
97
  <script lang="ts" setup>
95
98
  import {computed, nextTick, onMounted, PropType, provide, ref, watch} from "vue";
96
99
  import {useVueFlow, VueFlow, XYPosition} from "@vue-flow/core";
@@ -102,7 +105,6 @@
102
105
  import DotNode from "../nodes/DotNode.vue";
103
106
  // @ts-expect-error no types for internals necessary
104
107
  import EdgeNode from "../nodes/EdgeNode.vue";
105
- // @ts-expect-error no types for internals necessary
106
108
  import TaskNode from "../nodes/TaskNode.vue";
107
109
  // @ts-expect-error no types for internals necessary
108
110
  import TriggerNode from "../nodes/TriggerNode.vue"
@@ -119,7 +121,7 @@
119
121
  import * as VueFlowUtils from "../../utils/VueFlowUtils";
120
122
  import {isParentChildrenRelation, swapBlocks} from "../../utils/FlowYamlUtils";
121
123
  import {useScreenshot} from "./export/useScreenshot";
122
- import {EXECUTION_INJECTION_KEY, SUBFLOWS_EXECUTIONS_INJECTION_KEY, PLAYGROUND_ENABLED_INJECTION_KEY} from "./injectionKeys";
124
+ import {EXECUTION_INJECTION_KEY, SUBFLOWS_EXECUTIONS_INJECTION_KEY} from "./injectionKeys";
123
125
 
124
126
  const props = defineProps({
125
127
  id: {
@@ -186,6 +188,10 @@
186
188
  playgroundEnabled: {
187
189
  type: Boolean,
188
190
  default: false
191
+ },
192
+ playgroundReadyToStart: {
193
+ type: Boolean,
194
+ default: false
189
195
  }
190
196
  });
191
197
 
@@ -200,7 +206,6 @@
200
206
 
201
207
  provide(EXECUTION_INJECTION_KEY, computed(() => props.execution));
202
208
  provide(SUBFLOWS_EXECUTIONS_INJECTION_KEY, computed(() => props.subflowsExecutions));
203
- provide(PLAYGROUND_ENABLED_INJECTION_KEY, computed(() => props.playgroundEnabled));
204
209
 
205
210
 
206
211
  const emit = defineEmits(
@@ -1,5 +1,4 @@
1
1
  import type {ComputedRef, InjectionKey} 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[]>>>
5
- export const PLAYGROUND_ENABLED_INJECTION_KEY = Symbol("playground-enabled-injection-key") as InjectionKey<ComputedRef<boolean>>
4
+ export const SUBFLOWS_EXECUTIONS_INJECTION_KEY = Symbol("subflows-executions-injection-key") as InjectionKey<ComputedRef<Record<string, any[]>>>
package/src/index.ts CHANGED
@@ -7,6 +7,7 @@ export {default as getMDCParser} from "./composables/getMDCParser";
7
7
  export * from "./utils/constants";
8
8
  export * from "./utils/url";
9
9
  export * from "./utils/plugins";
10
+ export {default as RotatingDotsIcon} from "./assets/icons/RotatingDots.vue";
10
11
 
11
12
  export type {YamlElement} from "./utils/YamlUtilsLegacy";
12
13
  export type {Plugin} from "./utils/plugins";
@@ -1634,4 +1634,15 @@ describe("get lines infos", () => {
1634
1634
  expect(tasksLines).to.containSubset({when_true: {start: 7, end: 9}});
1635
1635
  expect(tasksLines).to.containSubset({when_false: {start: 11, end: 13}});
1636
1636
  })
1637
+ test("if a task ends on the last line, it should be included", () => {
1638
+ const yamlString = `# this count as an empty line
1639
+ tasks:
1640
+ - id: plugin1
1641
+ type: type1
1642
+ name: Plugin 1
1643
+ extrafield: Extra field 1`;
1644
+
1645
+ const tasksLines = YamlUtils.getTasksLines(yamlString);
1646
+ expect(tasksLines).to.containSubset({plugin1: {start: 3, end: 6}});
1647
+ })
1637
1648
  });
@@ -1223,9 +1223,13 @@ export function getChartAtPosition(source: string, position: { lineNumber: numbe
1223
1223
  export function getTasksLines(
1224
1224
  source: string
1225
1225
  ):Record<string, {start: number, end: number}> {
1226
- const yamlDoc = parseDocument(source) as any;
1226
+ // if a task ends on the last line of the YAML,
1227
+ // its end range will be one line off.
1228
+ // To avoid this specific case, we add a newline at the end of the source.
1229
+ const paddedSource = source + "\n";
1230
+ const yamlDoc = parseDocument(paddedSource) as any;
1227
1231
  const lineCounter = new LineCounter();
1228
- parseDocument(source, {lineCounter});
1232
+ parseDocument(paddedSource, {lineCounter});
1229
1233
 
1230
1234
  let tasksLines: Record<string, {start: number, end: number}> = {};
1231
1235
  visit(yamlDoc, {
@@ -1237,7 +1241,10 @@ export function getTasksLines(
1237
1241
  for (const task of item.value.items) {
1238
1242
  if(isMap(task)){
1239
1243
  const foundChilTasksLines = getTasksAndFlowableLines(lineCounter, task);
1240
- tasksLines = {...tasksLines, ...foundChilTasksLines}
1244
+ tasksLines = {
1245
+ ...tasksLines,
1246
+ ...foundChilTasksLines
1247
+ }
1241
1248
  }
1242
1249
  }
1243
1250
  }
@@ -1249,12 +1256,16 @@ export function getTasksLines(
1249
1256
  });
1250
1257
  return tasksLines;
1251
1258
  }
1252
- function getTasksAndFlowableLines(lineCounter: LineCounter, task: YAMLMap) : Record<string, {start: number, end: number}>{
1259
+
1260
+ function getTasksAndFlowableLines(lineCounter: LineCounter, task: YAMLMap) {
1253
1261
  let tasksLines: Record<string, {start: number, end: number}> = {};
1254
1262
  const taskId = task.get("id") as string | undefined;
1255
1263
  if(taskId){
1256
1264
  if(task.range) {
1257
- tasksLines[taskId] = {start: lineCounter.linePos(task.range[0]).line, end: lineCounter.linePos(task.range[1]).line -1}
1265
+ tasksLines[taskId] = {
1266
+ start: lineCounter.linePos(task.range[0]).line,
1267
+ end: lineCounter.linePos(task.range[1]).line - 1
1268
+ }
1258
1269
  }
1259
1270
  const childTasks = new YAMLSeq<YAMLMap>();
1260
1271
  const tasksChilds = task.get("tasks") as YAMLSeq<YAMLMap> | undefined;