@revenexx/studio-integrations 0.7.0 → 1.1.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 (88) hide show
  1. package/CHANGELOG.md +633 -0
  2. package/dist/module.json +1 -1
  3. package/dist/module.mjs +2 -1
  4. package/dist/runtime/components/Integrations/CredentialCreateDialog.vue +4 -1
  5. package/dist/runtime/components/Integrations/CredentialDetailDialog.vue +8 -2
  6. package/dist/runtime/components/Integrations/DeadLettersPanel.vue +2 -6
  7. package/dist/runtime/components/Integrations/ExpressionInput.vue +5 -0
  8. package/dist/runtime/components/Integrations/NodeConfigDynamicField.d.vue.ts +3 -0
  9. package/dist/runtime/components/Integrations/NodeConfigDynamicField.vue +16 -3
  10. package/dist/runtime/components/Integrations/NodeConfigDynamicField.vue.d.ts +3 -0
  11. package/dist/runtime/components/Integrations/NodeConfigDynamicSchema.vue +1 -0
  12. package/dist/runtime/components/Integrations/NodeConfigField.d.vue.ts +3 -0
  13. package/dist/runtime/components/Integrations/NodeConfigField.vue +2 -0
  14. package/dist/runtime/components/Integrations/NodeConfigField.vue.d.ts +3 -0
  15. package/dist/runtime/components/Integrations/NodeInspector.d.vue.ts +2 -2
  16. package/dist/runtime/components/Integrations/NodeInspector.vue +135 -10
  17. package/dist/runtime/components/Integrations/NodeInspector.vue.d.ts +2 -2
  18. package/dist/runtime/components/Integrations/NodeOutputSchema.d.vue.ts +2 -1
  19. package/dist/runtime/components/Integrations/NodeOutputSchema.vue +34 -8
  20. package/dist/runtime/components/Integrations/NodeOutputSchema.vue.d.ts +2 -1
  21. package/dist/runtime/components/Integrations/NodePalette.vue +12 -8
  22. package/dist/runtime/components/Integrations/RunDetailPanel.vue +9 -6
  23. package/dist/runtime/components/Integrations/RunsTable.vue +2 -2
  24. package/dist/runtime/components/Integrations/StickyNoteView.vue +45 -11
  25. package/dist/runtime/components/Integrations/SurfaceCard.d.vue.ts +50 -0
  26. package/dist/runtime/components/Integrations/SurfaceCard.vue +55 -0
  27. package/dist/runtime/components/Integrations/SurfaceCard.vue.d.ts +50 -0
  28. package/dist/runtime/components/Integrations/TemplateCard.vue +3 -3
  29. package/dist/runtime/components/Integrations/TemplateFlowPreview.vue +12 -3
  30. package/dist/runtime/components/Integrations/WorkflowCreateDialog.vue +5 -4
  31. package/dist/runtime/components/Integrations/WorkflowEditor.d.vue.ts +16 -0
  32. package/dist/runtime/components/Integrations/WorkflowEditor.vue +79 -12
  33. package/dist/runtime/components/Integrations/WorkflowEditor.vue.d.ts +16 -0
  34. package/dist/runtime/components/Integrations/WorkflowHistoryPanel.d.vue.ts +6 -0
  35. package/dist/runtime/components/Integrations/WorkflowHistoryPanel.vue +13 -3
  36. package/dist/runtime/components/Integrations/WorkflowHistoryPanel.vue.d.ts +6 -0
  37. package/dist/runtime/components/Integrations/WorkflowNodeView.d.vue.ts +13 -0
  38. package/dist/runtime/components/Integrations/WorkflowNodeView.vue +95 -29
  39. package/dist/runtime/components/Integrations/WorkflowNodeView.vue.d.ts +13 -0
  40. package/dist/runtime/components/Integrations/WorkflowRunReplayPanel.vue +11 -10
  41. package/dist/runtime/components/Integrations/WorkflowSettingsDialog.d.vue.ts +16 -17
  42. package/dist/runtime/components/Integrations/WorkflowSettingsDialog.vue +37 -26
  43. package/dist/runtime/components/Integrations/WorkflowSettingsDialog.vue.d.ts +16 -17
  44. package/dist/runtime/components/Integrations/WorkflowTriggerView.vue +4 -5
  45. package/dist/runtime/components/Integrations/WorkflowVariablesDialog.vue +53 -14
  46. package/dist/runtime/components/Integrations/WorkflowsTable.vue +9 -4
  47. package/dist/runtime/composables/useIntegrationsCredentials.d.ts +11 -0
  48. package/dist/runtime/composables/useIntegrationsCredentials.js +2 -2
  49. package/dist/runtime/composables/useIntegrationsDeadLetters.d.ts +9 -2
  50. package/dist/runtime/composables/useIntegrationsDeadLetters.js +27 -18
  51. package/dist/runtime/composables/useIntegrationsNodes.js +11 -1
  52. package/dist/runtime/composables/useIntegrationsRuns.d.ts +30 -1
  53. package/dist/runtime/composables/useIntegrationsRuns.js +70 -29
  54. package/dist/runtime/composables/useIntegrationsSchedules.d.ts +7 -14
  55. package/dist/runtime/composables/useIntegrationsSchedules.js +80 -35
  56. package/dist/runtime/composables/useIntegrationsTriggers.d.ts +30 -3
  57. package/dist/runtime/composables/useIntegrationsTriggers.js +18 -7
  58. package/dist/runtime/composables/useIntegrationsWorkflows.d.ts +10 -1
  59. package/dist/runtime/composables/useIntegrationsWorkflows.js +25 -4
  60. package/dist/runtime/composables/useNodeConfigResolve.js +2 -1
  61. package/dist/runtime/data/integrationNodeCatalog.d.ts +22 -1
  62. package/dist/runtime/data/integrationNodeCatalog.js +8 -4
  63. package/dist/runtime/data/loopBody.d.ts +129 -0
  64. package/dist/runtime/data/loopBody.js +76 -0
  65. package/dist/runtime/data/nodeInputData.d.ts +58 -1
  66. package/dist/runtime/data/nodeInputData.js +30 -5
  67. package/dist/runtime/data/triggerGlyphs.d.ts +47 -0
  68. package/dist/runtime/data/triggerGlyphs.js +11 -0
  69. package/dist/runtime/i18n/messages/de.json +62 -33
  70. package/dist/runtime/i18n/messages/en.json +32 -3
  71. package/dist/runtime/pages/integrations/credentials.vue +4 -1
  72. package/dist/runtime/pages/integrations/index.vue +32 -34
  73. package/dist/runtime/pages/integrations/runs.vue +22 -10
  74. package/dist/runtime/pages/integrations/schedules.vue +64 -7
  75. package/dist/runtime/pages/integrations/templates/[slug].vue +13 -5
  76. package/dist/runtime/pages/integrations/workflows/[id].vue +193 -104
  77. package/dist/runtime/types/integrations.d.ts +64 -1
  78. package/dist/runtime/utils/cockpitSources.d.ts +22 -3
  79. package/dist/runtime/utils/credentialState.d.ts +6 -1
  80. package/dist/runtime/utils/credentialState.js +1 -1
  81. package/dist/runtime/utils/localize.d.ts +34 -0
  82. package/dist/runtime/utils/localize.js +22 -7
  83. package/dist/runtime/utils/pollBudget.d.ts +1 -1
  84. package/dist/runtime/utils/servedPaths.d.ts +22 -0
  85. package/dist/runtime/utils/servedPaths.js +3 -0
  86. package/dist/runtime/utils/statusStyle.d.ts +52 -0
  87. package/dist/runtime/utils/statusStyle.js +26 -0
  88. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,638 @@
1
1
  # @revenexx/studio-integrations
2
2
 
3
+ ## 1.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - c8f121b: The Schedules page shows the firing the platform actually holds, and the run it
8
+ really performed.
9
+
10
+ Both times in that list were made up. There was no telemetry to read, so the page
11
+ computed them from the schedule's own identity — arithmetic over the workflow id
12
+ and the trigger id — which told the truth about the _shape_ of the answer and
13
+ nothing about the value. A schedule that fires nightly at 03:00 could read "in
14
+ 18m", and one that had never run could report a last run.
15
+
16
+ They are now the platform's: the next firing it holds, with the offset of the
17
+ schedule's own zone available as the cell's title, and the last run it really
18
+ performed. The header's live count and the timezones the filter offers are its
19
+ counts too, taken over the tenant rather than over the rows on screen — so
20
+ narrowing the list no longer shrinks the menu that narrows it.
21
+
22
+ Two promises changed with them.
23
+
24
+ A paused schedule used to state neither time, which looked like one rule and was
25
+ really an artefact of both being invented from the same flag. It has no next
26
+ firing, because the platform holds none for it — and it keeps the run it performed
27
+ before it was paused. Forgetting that is how a paused schedule reads as one that
28
+ never ran.
29
+
30
+ "A distance further out than a day is stated as the date and time instead" was a
31
+ promise with nothing to prove it: the fabricated times stayed inside twelve hours,
32
+ so no fixture could produce the day-scale form. A weekly schedule reaches it, and
33
+ it now has a test.
34
+
35
+ What the page still cannot say is _why_ a schedule will not fire. The platform
36
+ distinguishes six reasons beyond "somebody paused it" — the workflow is off, its
37
+ bundle never built, the expression cannot be read, the zone is not a real one, the
38
+ rhythm can never come round — and the page shows the absence of a next run and the
39
+ live/paused badge, which covers the first and leaves the others looking like it.
40
+
41
+ Review then found four more things a fully mocked test suite could not see, and
42
+ they are user-visible.
43
+
44
+ A schedule carrying no zone of its own showed a blank timezone and could be found
45
+ under none of the zones the filter offers — the platform counts such a row under
46
+ its own default and narrows to it there, so the studio puts that default back
47
+ rather than showing nothing.
48
+
49
+ A run the platform has created and no worker has started now says so, instead of
50
+ reading as a schedule that has never run: when a run _started_ is recorded only
51
+ once something picks it up.
52
+
53
+ A read the platform refuses says so. Until now the page fell through to the words
54
+ a tenant with no schedules gets, which on this page is the opposite state — an
55
+ operator told there are no schedules stops looking, and a tenant whose list merely
56
+ could not be reached is the one where something may be silently not firing.
57
+
58
+ And a date further out than a day is drawn in the schedule's own timezone, so it
59
+ no longer contradicts the zone stated beside it — or the exact moment on its own
60
+ hover — by an hour or two.
61
+
62
+ - 82884b7: The Runs page, its Missed runs tab and the Dashboard read the platform's own
63
+ lists and figures instead of assembling them in the browser.
64
+
65
+ Runs are a per-workflow resource, so the tenant-wide views used to collect them:
66
+ a request per workflow, paged to the end of each one's history — up to a hundred
67
+ pages of a hundred rows apiece — and then ordered, filtered and counted here. A
68
+ tenant's ordering and totals were therefore only ever as complete as that
69
+ collecting, and nothing said how far back the page reached. The same went for the
70
+ missed firings and for the four figures on the landing page, four of which could
71
+ not start until one shared list of workflows had arrived.
72
+
73
+ The platform serves all of it now. One request for the runs, ordered by it; one
74
+ for the counts, taken over the tenant rather than over what happened to load; one
75
+ for the latest run of each workflow, which is what the Workflows list and the
76
+ dashboard's two panels actually want. The dashboard no longer loads a run list at
77
+ all.
78
+
79
+ Three things visibly change rather than merely getting faster:
80
+
81
+ The trigger column and its filter tell runs apart. Every row claimed to have been
82
+ started by hand, because the payload carried nothing about what started it, so
83
+ that menu had one populated option. The platform reports it, so the column is
84
+ true and narrowing by it works.
85
+
86
+ The Workflows list stops being able to say "never run" about a workflow that
87
+ simply ran a while ago. That cell used to pick the newest run out of the tenant's
88
+ whole history held in memory, which only worked while all of it was loaded.
89
+
90
+ The counts are the tenant's. The Missed runs badge, the runs in flight and the
91
+ failed figure are counted by the platform under the same narrowing as the list
92
+ beside them, so a figure and its rows can no longer disagree.
93
+
94
+ What is still bounded is depth: the Runs list reaches the most recent hundred
95
+ runs, and narrowing reaches what is on the page. Paging past that needs the shared
96
+ studio table to be able to report a narrowing back to the page, which it cannot
97
+ yet — that is the remaining half of PO-231.
98
+
99
+ - 59133ea: The canvas says which steps a loop repeats.
100
+
101
+ An iterator draws its two outputs — Item and Done — like any other pair of ports,
102
+ so nothing said that everything hanging off Item runs once per element while
103
+ everything off Done runs once, afterwards. Somebody who had not drawn the workflow
104
+ could not see where the repeating part began or how far it reached.
105
+
106
+ Every step a loop repeats now carries a mark saying so, and naming the loop; a
107
+ step inside two loops names both, outermost first. The loop itself carries the
108
+ number of steps it repeats — including zero, which is what a loop nothing is wired
109
+ to yet looks like. Selecting the loop draws its whole body as part of the
110
+ selection, for as long as the selection lasts — and selecting any step of the body
111
+ does the same from the other end, drawing the loop and everything that repeats
112
+ alongside it. The marks are on all three canvases
113
+ that draw a workflow — the editor, the run replay and the revision preview — and
114
+ they follow a rewiring at once, before anything is saved.
115
+
116
+ What is marked is what the engine will actually repeat, which is not always the
117
+ body as it was drawn: the repeating part has no end anywhere in the workflow, only
118
+ a reach, so a step wired to the last step of the body runs once per element even
119
+ when it was meant to run once afterwards. A loop's Output tab now counts the steps
120
+ it repeats, names them, and says which of them are wired after the loop as well —
121
+ reported rather than refused, because a body that rejoins the main flow can be
122
+ exactly what its author wanted.
123
+
124
+ The connections themselves are unchanged: they carry importance, never meaning,
125
+ and colour on them stays reserved for a run that actually happened.
126
+
127
+ ### Patch Changes
128
+
129
+ - 5385146: A missed run's state is said in the studio's own words.
130
+
131
+ The badge on a missed run showed the state as the platform spells it — `PENDING`,
132
+ `REPLAYED`, `DISCARDED` — while the badge on a run row one tab away said
133
+ "succeeded" or "running" in the operator's language. A German interface therefore
134
+ read English in this one list, and any state the platform starts recording
135
+ tomorrow would have appeared on screen untranslated with nothing to notice it.
136
+
137
+ Both lists that carry the entry — the tenant-wide Missed runs tab and the panel
138
+ inside a workflow's editor — now say the state through the message catalogue: a
139
+ firing still waiting, one replayed, one discarded, in English and in German. A
140
+ state the studio has no word for says exactly that and keeps the platform's own
141
+ value alongside it, so an operator can quote what arrived without the studio
142
+ passing it off as a word somebody chose.
143
+
144
+ The colours of those badges are unchanged, and the two surfaces still tint them
145
+ differently — that is a separate finding, not this one.
146
+
147
+ - 630523f: A missed run's state is drawn the same way on both lists.
148
+
149
+ The same entry was coloured differently depending on where it was opened. Beside
150
+ the tenant's runs it read the cockpit-wide status palette, where a waiting firing
151
+ is tinted like a run that is about to start and the other two states are absent
152
+ altogether — so _replayed_ and _discarded_ were both grey. Inside a workflow the
153
+ panel carried a palette of its own: amber for waiting, green for replayed, grey
154
+ for discarded.
155
+
156
+ Both lists now draw a state from one place: waiting asks for attention, replayed
157
+ reads as finished well, discarded and anything the studio has no word for read as
158
+ over. The colours are the shared palette's, so this is one more vocabulary mapped
159
+ into the studio's tones rather than a second set of colours — and the word and the
160
+ colour for a state now come from a single map, which is what stops the next state
161
+ being added to one and forgotten in the other.
162
+
163
+ Visible change: on the tenant-wide _Missed runs_ tab a waiting firing turns from
164
+ blue to amber and a replayed one from grey to green. The panel inside a workflow
165
+ keeps the colours it had, give or take the shared palette's border and text tints.
166
+
167
+ - 6e1a42e: A run's outcome is drawn the same way wherever it is shown.
168
+
169
+ A run terminated by an operator read _failed_ in a list and _failed_ at its own
170
+ record — in two colours. The word went through the studio's vocabulary, where the
171
+ platform's `terminated` becomes _failed_, and the colour did not: the palette was
172
+ handed the platform's word, which it has no branch for, so the badge fell back to
173
+ the grey a cancelled run wears. Clicking the row took the operator from a red
174
+ badge to a grey one for the same run.
175
+
176
+ The colour is now decided from the same word as the label, everywhere a run's or a
177
+ step's state is drawn: the runs list, the dashboard's latest runs, a run's record,
178
+ its timeline and the replay. Nothing changes on the surfaces that were already
179
+ right — a row's status is mapped before anything draws it — and a run whose state
180
+ the platform reports as `terminated` or `timed_out` now looks like the failure the
181
+ badge says it is.
182
+
183
+ A cancelled run was affected in the same way, in the _word_ rather than the
184
+ colour: the platform spells a cancellation the American way, so a run cancelled
185
+ from its row read _cancelled_ on the row and _canceled_ at its own record — and in
186
+ German the record said it in English. It now reads the studio's word wherever it
187
+ is shown.
188
+
189
+ One of those surfaces was worse in German than in English: the timeline's step
190
+ lightbox derived its colour from the word it had already translated, so a failed
191
+ step was drawn neutral for a German reader and red for an English one. The colour
192
+ is now taken from the status itself.
193
+
194
+ `statusClass` is unchanged and still exports the studio-wide status palette;
195
+ `runStatusClass` is the run-vocabulary door to it.
196
+
197
+ - e69e407: A run is called a Run in German too.
198
+
199
+ The German interface used two words for one object. Three quarters of the
200
+ catalogue said _Run_ — the sidebar item, the editor's Runs tab, the Run button, the
201
+ breadcrumb, every audit entry — while 29 values said _Ausführung_, including the
202
+ tab sitting directly beside the one that said _Runs_, and two sentences that used
203
+ both words in the same breath ("Noch keine Ausführungen — im Editor auf Run
204
+ klicken").
205
+
206
+ Those 29 now say _Run_: the editor's _Verpasste Runs_ tab, the dashboard's _Letzte
207
+ Runs_ panel and its missed-run count, the schedules table's _Letzter Run_ and
208
+ _Nächster Run_, and the toasts and hints around starting, retrying and replaying
209
+ one.
210
+
211
+ _Ausführung_ stays where it names the act rather than the object —
212
+ _Ausführungsmodus_, _Ausführungsverhalten_, _Ausführungsverlauf_,
213
+ _Hintergrundausführung_, and the settings section _Ausführung_. Their English says
214
+ _Execution_ too, which is the test for the next one: if the English says _run_, the
215
+ German says _Run_. The rule is now written down in `docs/interface-language.md`
216
+ rather than living in one catalogue entry's description.
217
+
218
+ No English copy changed, and no key was added or removed.
219
+
220
+ ## 1.0.0
221
+
222
+ ### Major Changes
223
+
224
+ - 91888a5: The workflow editor has one Save, and every dialog over the canvas is left the same
225
+ way.
226
+
227
+ "Save" used to mean three different things in this editor, and the one that read as
228
+ most final saved the least:
229
+
230
+ - A step's own dialog said **Save** and wrote nothing to the platform — it committed
231
+ into the workflow's unsaved state.
232
+ - The settings dialog said **Save changes** under its appearance block and really did
233
+ write, shipping the whole unsaved canvas along with it. It could also undo itself: a
234
+ workflow carries its name, tags and icon inside its own definition, so the next
235
+ header Save shipped the canvas draft it had been holding and carried the old values
236
+ straight back over what that button had just written.
237
+ - The variables dialog offered no footer at all and kept every keystroke, so escape
238
+ and the ✕ _kept_ the edits there while the same gestures threw a whole form away in
239
+ the dialog beside it.
240
+
241
+ Now the editor holds **one draft** — the name, the description, the dispatch mode and
242
+ the canvas together — and:
243
+
244
+ - **The header's Save is the only control that writes to the platform.** It persists
245
+ all four in one call, so there is one thing that can fail and one place that says
246
+ so.
247
+ - **Every dialog closes on Cancel or Done.** Done puts what was changed on the
248
+ workflow as an unsaved change; Cancel, escape and the ✕ abandon it. The same
249
+ gesture now means the same thing in all three.
250
+ - **The header names the workflow as entered** — a renamed workflow reads as renamed
251
+ before it is saved, with the unsaved marker beside it. The dispatch badge next to it
252
+ deliberately does _not_ follow the draft: Run fires against the workflow the platform
253
+ holds, so a badge showing a drafted mode would announce a dispatch that is not the
254
+ one about to happen.
255
+
256
+ The dispatch mode could honestly have gone on saving by itself, being the one field
257
+ that is not part of the workflow's own definition and so not revertible by a later
258
+ save. It was pulled into the draft anyway, so that nothing inside a dialog talks to
259
+ the platform.
260
+
261
+ `specs/workflow-save.md` AC-7 to AC-10 carry the promise.
262
+
263
+ **Why this is a major.** Two things a host has to react to. The `Save` accessible name
264
+ is gone from three dialogs — anything addressing it by name reaches nothing, and
265
+ accessible names are part of this module's surface. And the workflow settings dialog's
266
+ props and events changed: `modeDraft`, `savingMode` and `savingMeta` are gone along
267
+ with `change-mode` and `save-meta`, replaced by a required `current` and a single
268
+ `apply`.
269
+
270
+ ### Minor Changes
271
+
272
+ - 6869846: A node's output ports say what flows through them, and so do the fields inside
273
+ them.
274
+
275
+ Node packages describe every output port they declare, and every field inside
276
+ one — what the branch is for, when it fires, what a value in the payload means.
277
+ None of it had ever appeared on screen: the Output tab in a node's configuration
278
+ drew the port's name and the field's type and discarded the sentence beside them.
279
+ It is now read in the reader's language, under the port's name and next to the
280
+ field's, without anything having to run first.
281
+
282
+ The two layers are drawn independently, because that is how they are published: of
283
+ the 84 node types registered today, 8 describe an output port and 22 describe a
284
+ field — 20 of those while the port holding the field says nothing at all. So a
285
+ port with nothing to say still shows what its fields have to say.
286
+
287
+ The same sentence is also on the tooltip of the port's handle on the canvas,
288
+ which is where somebody drawing a connection is actually looking. That one is a
289
+ convenience rather than a promise: a tooltip is not reachable by keyboard, so the
290
+ Output tab stays the place the text can be read.
291
+
292
+ **What a node expects to be given is shown too.** The panel of available data now
293
+ opens with what _this_ node takes: the kind of value, whether an upstream
294
+ connection is required, and the publisher's sentence about it where one exists.
295
+ That answers the opposite question to the list underneath it — the list says what
296
+ there is to feed from, this says what to feed in — and it had been published all
297
+ along: the studio was asking the catalogue for a node's input under a key the
298
+ service does not use, so every input description, data type and requirement
299
+ arrived and was dropped unread.
300
+
301
+ One rule was retired rather than repaired while doing it. A node card used to hide
302
+ its input dot when the manifest said an upstream connection was not required. It
303
+ read the same unused key, so it never once fired — and both halves of it were
304
+ wrong anyway: an optional input is still something you connect to, and a node that
305
+ consumes nothing may still be wired to fix the order it runs in. Every node card
306
+ offers somewhere to connect to, which is what they all did in practice.
307
+
308
+ - 04bd108: The dashboard's shortcuts into Import & Export, the SFTP server, the event stream
309
+ and inbound webhooks are offered as a way in only where the host serves them. Those
310
+ four surfaces belong to the host, not to this module, so the studio now asks the
311
+ router which of the paths this host actually has: in the cockpit all four keep
312
+ working exactly as before, and in a host that has none of them — or two of them —
313
+ the remaining cards stay where they were, keep their name and their description, and
314
+ answer a click by naming the surface and saying that it is to be found in the
315
+ Revenexx Cockpit, instead of leading into a route nobody serves. They look exactly as
316
+ they did — the arrow included.
317
+
318
+ **For hosts that test the studio:** in that state the card is a `button`, not a
319
+ `link`. A suite addressing one of the four with `getByRole('link', { name: 'Import
320
+ & Export' })` has to ask for the role its own host serves — which is why this is a
321
+ minor rather than a patch.
322
+
323
+ - 3c8b669: A step in a template's flow drawing is called the same thing wherever the drawing
324
+ is shown.
325
+
326
+ The small drawing of what a template would build is on four surfaces: the card in
327
+ the gallery, the cards on the dashboard and in the New workflow dialog, and large
328
+ at the top of a template's own page. It named its steps from the node catalogue —
329
+ but only where the page around it had asked for the catalogue for some other
330
+ reason. The gallery and a template's own page had; the dashboard and the create
331
+ dialog had not, so the same step read "HTTP Request" in one place and "Http
332
+ Request" in the next, and a reader moving from the dashboard's card to the page it
333
+ opens saw one step under two names.
334
+
335
+ The drawing now asks for the names it needs itself, on every surface it appears
336
+ on. The request is shared, so a panel of four cards still costs one — and a page
337
+ that already holds the catalogue costs nothing. Two things come along with the
338
+ names on the two surfaces that were missing them: a step is drawn with its own
339
+ symbol and its vendor's logo instead of a generic mark, and with the tint of its
340
+ category behind it, so the four drawings now look alike as well as read alike.
341
+
342
+ The hero drawing on a template's own page also gained an accessible name ("The
343
+ flow this template builds"), which its two neighbouring panels already had. It was
344
+ the largest thing on the page and the only part of it a screen reader could not be
345
+ pointed at. A minor rather than a patch for that name and for the marks: both are
346
+ additive, and an accessible name is something a host or a test can address.
347
+
348
+ - 8b8916f: A workflow's editor header says whether that workflow is active, and the play
349
+ symbol goes back to meaning "run it now".
350
+
351
+ The header used to carry one button that flipped between Activate and Pause, so
352
+ the state was never named — a reader had to invert the offered verb to work out
353
+ that "Activate" meant the workflow was paused, while the workflows list said
354
+ Paused outright. That button also wore the play triangle, the same glyph the
355
+ Run button in the canvas's control pane wears, so one symbol stood both for
356
+ "armed and waiting for its triggers" and for "execute now". A workflow that is
357
+ switched on is not running; it is waiting.
358
+
359
+ The header now names the state in the list's own words — Active or Paused — with
360
+ a switch beside it that flips it, and no glyph. The words come from the same
361
+ message as the list badge, so the two surfaces cannot drift apart in one language
362
+ and not in the other.
363
+
364
+ The activation gate is unchanged. A workflow with incomplete node settings still
365
+ cannot be switched on: the switch cannot be operated, and the reason — how many
366
+ node settings to fix first — is on the control both as a tooltip and as an
367
+ accessible description, because a disabled control shows no tooltip in Chrome.
368
+ The `shift+a` shortcut is still refused with the same message, and pausing an
369
+ active workflow still needs no validation.
370
+
371
+ - 17e938f: Unsaved work in the workflow editor is no longer thrown away without being asked
372
+ about.
373
+
374
+ Everything done on a workflow's canvas lives in the browser until Save is pressed,
375
+ and until now every way out of the editor discarded it silently. Clicking the
376
+ Workflows breadcrumb lost an afternoon's arrangement without a word. So did
377
+ reloading the page.
378
+
379
+ Worse, so did a move that was not leaving at all: a workflow's runs, missed
380
+ firings and earlier versions sit on tabs beside the canvas, and going to one of
381
+ them and back rebuilt the canvas from the _saved_ workflow. The work was still
382
+ there — the header still said "Unsaved changes", and Save would still have written
383
+ it — but nobody could see it any more, so Save wrote a workflow the operator had
384
+ been given no chance to look at.
385
+
386
+ Now:
387
+
388
+ - **Moving between a workflow's own tabs keeps the work.** Coming back to the
389
+ canvas shows it as it was left.
390
+ - **Leaving the workflow asks first**, and staying is what the question falls back
391
+ to: escape or a click beside it keeps the work and the workflow open. Discarding
392
+ is a button somebody has to press.
393
+ - **A reload or a closed browser tab raises the browser's own warning**, which is
394
+ the only wording available on that exit.
395
+ - **Putting an earlier version back says that the unsaved changes go with it.**
396
+ That restore has to discard them — an earlier version is what was asked for —
397
+ but it happens from a tab where the canvas is not on screen, so the question now
398
+ names what is about to be lost instead of taking it silently.
399
+
400
+ Moves the studio makes itself are not questioned: opening one of the workflow's
401
+ runs and closing it again, and landing in the copy that duplicating it just
402
+ created.
403
+
404
+ The promise and its criteria are `specs/workflow-save.md`. Hosts that render the
405
+ workflow editor or the version-history panel themselves gain two optional props —
406
+ the draft the page is holding, and whether there is one.
407
+
408
+ - 2c5d6e1: The node palette no longer offers a node version the platform cannot execute. Registering a node version and building its code are two separate steps, and a version stuck after the first one used to be offered like any other — it drew its settings form, saved into a workflow, and then failed the moment a step was tested, with an error advising a retry that could never help.
409
+
410
+ The palette now offers only versions that can run, and a node whose newest version is unbuilt is offered at its newest runnable one instead; a node with no runnable version at all is not offered. A workflow already pinned to such a version keeps drawing that node — the step is really there — and its output panel now says that this version has no built code rather than offering a test that would be refused.
411
+
412
+ Needs an Integrations API that reports the build state per node version. Against an older API nothing changes: every version counts as runnable, exactly as before.
413
+
414
+ - 8d55660: Opening a node no longer lands the cursor in its name.
415
+
416
+ A node's configuration used to open with the whole name selected, so it read as an
417
+ edit already in progress and the first key pressed replaced the name of a step the
418
+ user had only opened to look at. The name is left alone now, and the keyboard goes
419
+ to the dialog itself — Escape still closes it, Tab still stays inside it, and it
420
+ announces which node was opened rather than announcing the name field.
421
+
422
+ Renaming is unchanged where it was asked for: Rename in a card's right-click menu,
423
+ and the shortcut that menu names, still open the configuration with the cursor in
424
+ the name and the old name selected, so typing replaces it. That intent is now spent
425
+ on the one node it was asked for — saving a rename and opening another node used to
426
+ carry it along.
427
+
428
+ A minor rather than a patch because the dialog gained an accessible name it did not
429
+ have — `Configure <node>` — which a host or a test can now address it by. Nothing
430
+ was renamed or removed.
431
+
432
+ ### Patch Changes
433
+
434
+ - 9accf9e: The tenant's schedules no longer cost a request per workflow. The workflow list
435
+ already carries each workflow's triggers, so the Dashboard, the Schedules page and
436
+ the navigation rail read them from that one response instead of asking
437
+ `/workflows/{id}/triggers` once per workflow — a third of what opening the dashboard
438
+ cost on a cold visit, gone, with no change to what any of those surfaces show.
439
+
440
+ The per-workflow route is untouched for what it is actually for: a single workflow's
441
+ triggers in the editor, and creating, changing or removing one.
442
+
443
+ - 706281a: A variable's description is saved in the language it is being read in, and replacing
444
+ one no longer glues another language to the typing.
445
+
446
+ Two fields also carry a promise they were relied on for and never had — the name a
447
+ trigger goes by, and a variable's description both hand back exactly what was typed,
448
+ the same promise a node's name already had. That is the specification half; what
449
+ follows is what changed in the product.
450
+
451
+ On a studio set to German, editing a description that already carried a German text
452
+ wrote the typing into the English one: the field went on showing the German text, and
453
+ reopening the dialog showed the old wording with nothing to say that the edit had gone
454
+ nowhere. Descriptions that arrive from a template carry several languages, so this was
455
+ reachable by anyone working in a language other than English.
456
+
457
+ Two consequences of the same rule, both fixed here. A studio set to a **regional**
458
+ language — `de-CH` — reads a `de` description through the region fall-back, and used to
459
+ write the edit into a new `de-CH` key: the Swiss reader saw the new text, everyone on
460
+ plain German went on seeing the old one. And **clearing** a description now takes only
461
+ the language being edited; it used to drop the description in every language at once,
462
+ so emptying a German text destroyed the English one the field had never shown.
463
+
464
+ A description is therefore written under the language it was read from, and a language
465
+ the map does not have yet is written under its base subtag — never the host's raw tag.
466
+ **Clearing** a description removes the text that was on screen, which is not always the
467
+ same key: where the studio is borrowing another language's text — every description
468
+ carries English, so this is the common shape — emptying the field removes that one and
469
+ the description goes with it. Languages the field never displayed are left alone.
470
+
471
+ **Replacing** a description was the gesture that suffered for it. The field was
472
+ re-derived from the saved workflow on every keystroke, so clearing a description that
473
+ carried a second language refilled the field from that language at once — and the next
474
+ character was appended to a sentence the author never typed, then saved under _their_
475
+ language. Ctrl+A, Backspace, "Neu" on a German studio saved `How often it retries.Neu`
476
+ as the German text. The field now holds what is being typed into it while the dialog is
477
+ open, so clearing leaves it empty and what follows is only what was typed.
478
+
479
+ One read-side improvement comes with it: a host locale written with an underscore
480
+ (`de_CH`) now resolves to its language like any other tag, where it used to fall
481
+ through to English.
482
+ That also keeps a host locale the API rejects (`de-ch`, `en_US`, `zh-Hans`) out of a
483
+ key it validates, where it would have failed the whole workflow save rather than just
484
+ the description.
485
+
486
+ - f6a6fdb: The list of available data inside a node's setting opens again, and a setting
487
+ waiting on another one names it the way the form does.
488
+
489
+ A setting that takes a mapped value offers the workflow's data from the field
490
+ itself — earlier steps' outputs, the trigger payload, variables — and that list
491
+ silently stopped opening whenever an earlier step declared what its output
492
+ contains, which every published node does. Mapping a value then only worked
493
+ through the panel beside the form.
494
+
495
+ A setting whose options the platform has to be asked for tells the operator which
496
+ setting to fill in first, and it was naming it by its config key: `Set company_id
497
+ first` under a field labelled _Company_. It now names the label the form actually
498
+ shows, falling back to the key only where no setting matches it.
499
+
500
+ The list of available data is also addressable by name — _Available data for this
501
+ setting_ — so a screen reader announces which of the two offers it is reading. The
502
+ panel beside the form describes itself as _Available data_, and heard rather than
503
+ seen the two were the same words.
504
+
505
+ - 6be63aa: A sticky note's headings and lists are announced as headings and lists.
506
+
507
+ A note on the canvas rendered bold, italic, code and links as the real thing, but
508
+ a heading only as heavier text and a list item only as a bullet character beside
509
+ its words. A sighted reader saw the structure; anyone using a screen reader got an
510
+ unbroken run of text with no heading to jump to and no list to count. Notes are
511
+ where an author explains a workflow to whoever comes next, so this is exactly the
512
+ content that ought to be navigable.
513
+
514
+ A note's `#`, `##` and `###` are now real heading elements, starting at level two
515
+ so the page keeps the one top-level heading it promises, and a run of bulleted or
516
+ numbered lines is one list with its items inside it. The bullet is drawn as before
517
+ but no longer read out.
518
+
519
+ The note looks exactly as it did — this changed the markup, not the design.
520
+
521
+ It also closes a hole found while reviewing that rewrite, in code it did not
522
+ introduce: a note's link address was not escaped against the quote that ends an
523
+ HTML attribute, so a crafted address could put an event handler on the anchor the
524
+ note drew. Notes live in a workflow blob a tenant shares, so it reached whoever
525
+ opened the workflow. **If your users author notes, this is the reason to take this
526
+ release.**
527
+
528
+ - 2658447: Removing a group frame removes the frame, and deleting a connection redraws the
529
+ ones that are left.
530
+
531
+ **A frame folded shut no longer takes its members' connections with it.** Pressing
532
+ Delete on a folded frame did what it was meant to — the frame went, the nodes it
533
+ held stayed — and also removed, from the saved workflow, every connection that ran
534
+ between a node inside the frame and a node outside it. Nothing warned. While the
535
+ frame was folded those connections were drawn as the card's own, so the loss could
536
+ not be seen until the frame was gone and the members were drawn again with a line
537
+ missing, or until the workflow ran. Dissolving a frame through its own toolbar was
538
+ never affected; the keystroke was.
539
+
540
+ **A connection that is deleted no longer leaves its siblings bending around it.**
541
+ Where several connections leave one node, the canvas spreads them apart so their
542
+ horizontal runs do not land on the same line. Deleting one of them left the
543
+ survivors with the spread they had been given while it was still there, so a single
544
+ remaining connection curved as if it were avoiding a neighbour that no longer
545
+ existed — until something unrelated redrew the canvas or the page was reloaded.
546
+
547
+ Both came from the same place. One deletion gesture arrives from the canvas as two
548
+ separate reports — the connections first, the node second — and each half was acting
549
+ on its own: one deleted a connection by an id that, for a folded frame, belonged to
550
+ a connection the user had not touched, while the other never re-ranked what was
551
+ left. The two are now applied together, so deleting a connection reaches the host as
552
+ one change rather than two.
553
+
554
+ - ddbabc6: Deleting a selection of nodes in the workflow editor costs one canvas rebuild
555
+ instead of one per node.
556
+
557
+ The editor applied a Delete one id at a time, and each of those rebuilt the whole
558
+ canvas — nodes, edges, every group's member count, the handle bounds — and made a
559
+ structural clone of the whole workflow to report the change. A ten-node selection
560
+ therefore cost ten of each where one does. The batch path this should have taken
561
+ already existed and was already what the context menu used, so the two routes
562
+ into the same gesture were paying different prices.
563
+
564
+ Nothing about the gesture changes: the same nodes go, a group frame in the
565
+ selection still dissolves and leaves its members where they are, and the workflow
566
+ ends up in the same state. What is new is that the route has a test — pressing
567
+ the key on more than one node was not covered anywhere before.
568
+
569
+ - aac0de4: A magnifier, a spinner, a back arrow, a bolt and a warning triangle keep their
570
+ shape from one screen to the next.
571
+
572
+ Five shapes were drawn from both of the studio's icon libraries at once: whoever
573
+ learned the magnifier on the templates page met a different magnifier in the node
574
+ palette, and the same held for the spinner on a node card, the back arrow in the
575
+ palette, the palette's trigger bolt and the amber warning badge. All five are now
576
+ drawn from Solar, at every place that draws them.
577
+
578
+ Two duplications turned up beside them and went with them. The magnifier had a
579
+ third drawing, in the node inspector's input search. And the trigger's glyph was
580
+ drawn on eight surfaces that agreed in none of them: one glyph on a trigger card
581
+ and another in the header that opens from it, a globe for the webhook on the
582
+ templates page against a link everywhere else, and a different drawing again in the
583
+ palette's trigger tiles, the create dialog's trigger select and the template flow
584
+ preview. A trigger is now the same picture from the moment it is picked to the card
585
+ it becomes.
586
+
587
+ One of those eight was telling you something untrue rather than something
588
+ inconsistent. In the run list, the row for a run is its trigger's glyph, its `#id`
589
+ and its status badge — so that glyph is the only thing on the row that says what
590
+ started the run, and an event-triggered run drew the **manual play button**: "you
591
+ started this yourself", about a run nobody started. Every run now shows the trigger
592
+ it actually had.
593
+
594
+ Nothing about the module's dependencies changes: every file that drew a Lucide
595
+ glyph before still draws one, so `lucide-vue-next` remains as obligatory a peer
596
+ dependency for a host as it was. What this buys is recognition, not a smaller
597
+ install. `docs/icons.md` records what the icon language now is, the eight
598
+ shapes still drawn twice — four of which a rule about glyph _names_ cannot see, and
599
+ that is the finding underneath the sweep — and the one thing a small Solar glyph
600
+ needs on a coloured background.
601
+
602
+ - 276bf2f: A connection test that passed says what it reached
603
+
604
+ The service has always answered a successful test with a sentence, and the client
605
+ threw it away in three separate places: the composable returned a bare `{ ok: true }`
606
+ and discarded the response, `credentialState()` carried `last_test_message` only in
607
+ its `failed` branch, and the detail dialog typed the live result as `{ ok, error? }`
608
+ and rendered a fixed confirmation whenever `ok`. Each was written as "it worked, or
609
+ else here is a reason", so a message could only ever be a complaint.
610
+
611
+ Now a credential type that reached something can name it, and **all three surfaces
612
+ that offer the test show what it said** — a credential's detail view, the dialog it is
613
+ added and edited in, and the one a node's credential field opens. Where a type reports
614
+ nothing the wording is unchanged.
615
+
616
+ The same field carries the reason a test was **refused**, and all three dropped that
617
+ too: the service sends `message` whichever way the test went, and never sends the
618
+ `error` these surfaces were reading — that one is synthesised locally when the call
619
+ does not arrive at all. So a refusal showed "Connection failed." with the reason
620
+ sitting unread beside it. It is shown now.
621
+
622
+ And the detail view says it **once**. It used to print the sentence twice after a
623
+ test — the live result and the state block both had it — and past 497 characters the
624
+ two disagreed, because the platform stores a shortened copy of what it answered.
625
+
626
+ This is worth more than a nicer sentence where a credential's target is **derived
627
+ rather than configured**. A DeepL key decides by itself which of two API hosts every
628
+ translation goes to — the plans are different addresses and a key is refused on the
629
+ wrong one — so since the node stopped asking for an endpoint, the credential is the
630
+ only thing that knows, and its test result is the only place it can say so.
631
+
632
+ The promise is `specs/credential-test.md`, new: one spec rather than the same
633
+ criterion written into three, which is what the granularity rule asks for once a
634
+ promise reaches more than one surface.
635
+
3
636
  ## 0.7.0
4
637
 
5
638
  ### Minor Changes
package/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@revenexx/studio-integrations",
3
3
  "configKey": "studioIntegrations",
4
- "version": "0.7.0",
4
+ "version": "1.1.0",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "unknown"
package/dist/module.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { existsSync, readdirSync, statSync } from 'node:fs';
1
+ import { readdirSync, statSync, existsSync } from 'node:fs';
2
2
  import { join } from 'node:path';
3
3
  import { defineNuxtModule, createResolver, addPlugin, hasNuxtModule, installModule, addComponentsDir, addImportsDir, extendPages } from '@nuxt/kit';
4
4
 
@@ -22,6 +22,7 @@ function scanRoutes(dir, baseUrl, baseName) {
22
22
  }
23
23
  return routes;
24
24
  }
25
+
25
26
  const module$1 = defineNuxtModule({
26
27
  meta: {
27
28
  name: "@revenexx/studio-integrations",