@revenexx/studio-integrations 0.6.0 → 1.0.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 (137) hide show
  1. package/CHANGELOG.md +643 -0
  2. package/README.md +31 -0
  3. package/dist/module.d.mts +17 -1
  4. package/dist/module.json +1 -1
  5. package/dist/module.mjs +12 -3
  6. package/dist/runtime/components/Integrations/CredentialCreateDialog.vue +32 -28
  7. package/dist/runtime/components/Integrations/CredentialDetailDialog.vue +45 -38
  8. package/dist/runtime/components/Integrations/CredentialRevenexxSource.vue +58 -58
  9. package/dist/runtime/components/Integrations/CredentialTypePicker.vue +10 -9
  10. package/dist/runtime/components/Integrations/DeadLettersPanel.vue +18 -17
  11. package/dist/runtime/components/Integrations/EventTypeCombobox.vue +4 -3
  12. package/dist/runtime/components/Integrations/ExpressionInput.vue +21 -15
  13. package/dist/runtime/components/Integrations/GroupFrameView.vue +29 -19
  14. package/dist/runtime/components/Integrations/Layout.vue +28 -3
  15. package/dist/runtime/components/Integrations/NodeConfigDynamicField.d.vue.ts +3 -0
  16. package/dist/runtime/components/Integrations/NodeConfigDynamicField.vue +30 -16
  17. package/dist/runtime/components/Integrations/NodeConfigDynamicField.vue.d.ts +3 -0
  18. package/dist/runtime/components/Integrations/NodeConfigDynamicSchema.vue +10 -8
  19. package/dist/runtime/components/Integrations/NodeConfigField.d.vue.ts +3 -0
  20. package/dist/runtime/components/Integrations/NodeConfigField.vue +45 -42
  21. package/dist/runtime/components/Integrations/NodeConfigField.vue.d.ts +3 -0
  22. package/dist/runtime/components/Integrations/NodeInspector.d.vue.ts +2 -2
  23. package/dist/runtime/components/Integrations/NodeInspector.vue +315 -221
  24. package/dist/runtime/components/Integrations/NodeInspector.vue.d.ts +2 -2
  25. package/dist/runtime/components/Integrations/NodeOutputSchema.d.vue.ts +2 -1
  26. package/dist/runtime/components/Integrations/NodeOutputSchema.vue +37 -10
  27. package/dist/runtime/components/Integrations/NodeOutputSchema.vue.d.ts +2 -1
  28. package/dist/runtime/components/Integrations/NodePalette.vue +40 -35
  29. package/dist/runtime/components/Integrations/QueryBuilder.vue +44 -43
  30. package/dist/runtime/components/Integrations/RunActionsMenu.vue +36 -12
  31. package/dist/runtime/components/Integrations/RunDetailPanel.vue +114 -62
  32. package/dist/runtime/components/Integrations/RunPayloadInput.vue +14 -13
  33. package/dist/runtime/components/Integrations/RunResponseModal.vue +11 -10
  34. package/dist/runtime/components/Integrations/RunsTable.d.vue.ts +0 -1
  35. package/dist/runtime/components/Integrations/RunsTable.vue +38 -16
  36. package/dist/runtime/components/Integrations/RunsTable.vue.d.ts +0 -1
  37. package/dist/runtime/components/Integrations/SftpAccountImportDialog.vue +8 -7
  38. package/dist/runtime/components/Integrations/Sidebar.vue +14 -10
  39. package/dist/runtime/components/Integrations/StickyNoteView.d.vue.ts +14 -4
  40. package/dist/runtime/components/Integrations/StickyNoteView.vue +82 -34
  41. package/dist/runtime/components/Integrations/StickyNoteView.vue.d.ts +14 -4
  42. package/dist/runtime/components/Integrations/SurfaceCard.d.vue.ts +50 -0
  43. package/dist/runtime/components/Integrations/SurfaceCard.vue +55 -0
  44. package/dist/runtime/components/Integrations/SurfaceCard.vue.d.ts +50 -0
  45. package/dist/runtime/components/Integrations/TemplateCard.vue +18 -8
  46. package/dist/runtime/components/Integrations/TemplateFlowPreview.vue +22 -12
  47. package/dist/runtime/components/Integrations/WorkflowContextMenu.vue +34 -33
  48. package/dist/runtime/components/Integrations/WorkflowCreateDialog.vue +41 -39
  49. package/dist/runtime/components/Integrations/WorkflowDuplicateDialog.vue +8 -7
  50. package/dist/runtime/components/Integrations/WorkflowEdgeView.vue +6 -4
  51. package/dist/runtime/components/Integrations/WorkflowEditor.d.vue.ts +16 -0
  52. package/dist/runtime/components/Integrations/WorkflowEditor.vue +131 -87
  53. package/dist/runtime/components/Integrations/WorkflowEditor.vue.d.ts +16 -0
  54. package/dist/runtime/components/Integrations/WorkflowHistoryPanel.d.vue.ts +6 -0
  55. package/dist/runtime/components/Integrations/WorkflowHistoryPanel.vue +27 -24
  56. package/dist/runtime/components/Integrations/WorkflowHistoryPanel.vue.d.ts +6 -0
  57. package/dist/runtime/components/Integrations/WorkflowIconPicker.vue +7 -6
  58. package/dist/runtime/components/Integrations/WorkflowNodeView.vue +76 -46
  59. package/dist/runtime/components/Integrations/WorkflowRunReplayPanel.vue +55 -43
  60. package/dist/runtime/components/Integrations/WorkflowSettingsDialog.d.vue.ts +16 -17
  61. package/dist/runtime/components/Integrations/WorkflowSettingsDialog.vue +55 -43
  62. package/dist/runtime/components/Integrations/WorkflowSettingsDialog.vue.d.ts +16 -17
  63. package/dist/runtime/components/Integrations/WorkflowTagsInput.vue +9 -8
  64. package/dist/runtime/components/Integrations/WorkflowTriggerView.vue +15 -13
  65. package/dist/runtime/components/Integrations/WorkflowVariablesDialog.vue +79 -39
  66. package/dist/runtime/components/Integrations/WorkflowsTable.vue +83 -45
  67. package/dist/runtime/composables/integrationsApi.js +4 -2
  68. package/dist/runtime/composables/useCredentialTypes.js +4 -2
  69. package/dist/runtime/composables/useIntegrationsCredentials.d.ts +11 -0
  70. package/dist/runtime/composables/useIntegrationsCredentials.js +8 -6
  71. package/dist/runtime/composables/useIntegrationsFocus.d.ts +12 -0
  72. package/dist/runtime/composables/useIntegrationsLocale.d.ts +26 -0
  73. package/dist/runtime/composables/useIntegrationsLocale.js +8 -0
  74. package/dist/runtime/composables/useIntegrationsNodes.js +14 -2
  75. package/dist/runtime/composables/useIntegrationsRealtime.d.ts +149 -0
  76. package/dist/runtime/composables/useIntegrationsRealtime.js +80 -0
  77. package/dist/runtime/composables/useIntegrationsRevisions.js +9 -7
  78. package/dist/runtime/composables/useIntegrationsRuns.d.ts +1 -1
  79. package/dist/runtime/composables/useIntegrationsRuns.js +3 -1
  80. package/dist/runtime/composables/useIntegrationsSchedules.d.ts +3 -2
  81. package/dist/runtime/composables/useIntegrationsSecrets.js +4 -2
  82. package/dist/runtime/composables/useIntegrationsT.d.ts +35 -0
  83. package/dist/runtime/composables/useIntegrationsT.js +9 -0
  84. package/dist/runtime/composables/useIntegrationsTemplates.d.ts +3 -3
  85. package/dist/runtime/composables/useIntegrationsTemplates.js +16 -8
  86. package/dist/runtime/composables/useIntegrationsTriggers.d.ts +23 -3
  87. package/dist/runtime/composables/useIntegrationsTriggers.js +21 -8
  88. package/dist/runtime/composables/useIntegrationsWorkflows.d.ts +10 -1
  89. package/dist/runtime/composables/useIntegrationsWorkflows.js +30 -7
  90. package/dist/runtime/composables/useNodeConfigResolve.js +4 -2
  91. package/dist/runtime/data/integrationNodeCatalog.d.ts +63 -1
  92. package/dist/runtime/data/integrationNodeCatalog.js +22 -4
  93. package/dist/runtime/data/integrationTemplates.d.ts +9 -0
  94. package/dist/runtime/data/integrationTemplates.js +7 -1
  95. package/dist/runtime/data/nodeInputData.d.ts +58 -1
  96. package/dist/runtime/data/nodeInputData.js +30 -5
  97. package/dist/runtime/data/payloadForm.js +2 -1
  98. package/dist/runtime/data/triggerGlyphs.d.ts +47 -0
  99. package/dist/runtime/data/triggerGlyphs.js +11 -0
  100. package/dist/runtime/data/workflowIconCatalog.js +2 -1
  101. package/dist/runtime/i18n/messages/de.json +1224 -0
  102. package/dist/runtime/i18n/messages/en.json +1224 -0
  103. package/dist/runtime/i18n/translate.d.ts +83 -0
  104. package/dist/runtime/i18n/translate.js +41 -0
  105. package/dist/runtime/pages/integrations/audit.vue +52 -34
  106. package/dist/runtime/pages/integrations/credentials/oauth-complete.vue +3 -2
  107. package/dist/runtime/pages/integrations/credentials.vue +73 -52
  108. package/dist/runtime/pages/integrations/index.vue +66 -73
  109. package/dist/runtime/pages/integrations/runs.vue +33 -21
  110. package/dist/runtime/pages/integrations/schedules.vue +49 -28
  111. package/dist/runtime/pages/integrations/secrets.vue +34 -34
  112. package/dist/runtime/pages/integrations/templates/[slug].vue +89 -72
  113. package/dist/runtime/pages/integrations/templates/index.vue +35 -27
  114. package/dist/runtime/pages/integrations/workflows/[id].vue +351 -197
  115. package/dist/runtime/pages/integrations/workflows/index.vue +10 -5
  116. package/dist/runtime/plugins/locale.d.ts +10 -0
  117. package/dist/runtime/plugins/locale.js +6 -0
  118. package/dist/runtime/plugins/realtime.client.d.ts +32 -0
  119. package/dist/runtime/plugins/realtime.client.js +4 -0
  120. package/dist/runtime/types/integrations.d.ts +25 -1
  121. package/dist/runtime/utils/cockpitSources.d.ts +22 -3
  122. package/dist/runtime/utils/credentialState.d.ts +30 -2
  123. package/dist/runtime/utils/credentialState.js +26 -11
  124. package/dist/runtime/utils/localize.d.ts +52 -5
  125. package/dist/runtime/utils/localize.js +47 -9
  126. package/dist/runtime/utils/pollBudget.d.ts +72 -0
  127. package/dist/runtime/utils/pollBudget.js +17 -0
  128. package/dist/runtime/utils/schedule.d.ts +0 -25
  129. package/dist/runtime/utils/schedule.js +37 -25
  130. package/dist/runtime/utils/servedPaths.d.ts +22 -0
  131. package/dist/runtime/utils/servedPaths.js +3 -0
  132. package/dist/runtime/utils/statusStyle.d.ts +26 -2
  133. package/dist/runtime/utils/statusStyle.js +9 -1
  134. package/dist/runtime/utils/validationFindings.d.ts +2 -2
  135. package/dist/runtime/utils/validationFindings.js +4 -3
  136. package/dist/types.d.mts +2 -6
  137. package/package.json +3 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,648 @@
1
1
  # @revenexx/studio-integrations
2
2
 
3
+ ## 1.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - 91888a5: The workflow editor has one Save, and every dialog over the canvas is left the same
8
+ way.
9
+
10
+ "Save" used to mean three different things in this editor, and the one that read as
11
+ most final saved the least:
12
+
13
+ - A step's own dialog said **Save** and wrote nothing to the platform — it committed
14
+ into the workflow's unsaved state.
15
+ - The settings dialog said **Save changes** under its appearance block and really did
16
+ write, shipping the whole unsaved canvas along with it. It could also undo itself: a
17
+ workflow carries its name, tags and icon inside its own definition, so the next
18
+ header Save shipped the canvas draft it had been holding and carried the old values
19
+ straight back over what that button had just written.
20
+ - The variables dialog offered no footer at all and kept every keystroke, so escape
21
+ and the ✕ _kept_ the edits there while the same gestures threw a whole form away in
22
+ the dialog beside it.
23
+
24
+ Now the editor holds **one draft** — the name, the description, the dispatch mode and
25
+ the canvas together — and:
26
+
27
+ - **The header's Save is the only control that writes to the platform.** It persists
28
+ all four in one call, so there is one thing that can fail and one place that says
29
+ so.
30
+ - **Every dialog closes on Cancel or Done.** Done puts what was changed on the
31
+ workflow as an unsaved change; Cancel, escape and the ✕ abandon it. The same
32
+ gesture now means the same thing in all three.
33
+ - **The header names the workflow as entered** — a renamed workflow reads as renamed
34
+ before it is saved, with the unsaved marker beside it. The dispatch badge next to it
35
+ deliberately does _not_ follow the draft: Run fires against the workflow the platform
36
+ holds, so a badge showing a drafted mode would announce a dispatch that is not the
37
+ one about to happen.
38
+
39
+ The dispatch mode could honestly have gone on saving by itself, being the one field
40
+ that is not part of the workflow's own definition and so not revertible by a later
41
+ save. It was pulled into the draft anyway, so that nothing inside a dialog talks to
42
+ the platform.
43
+
44
+ `specs/workflow-save.md` AC-7 to AC-10 carry the promise.
45
+
46
+ **Why this is a major.** Two things a host has to react to. The `Save` accessible name
47
+ is gone from three dialogs — anything addressing it by name reaches nothing, and
48
+ accessible names are part of this module's surface. And the workflow settings dialog's
49
+ props and events changed: `modeDraft`, `savingMode` and `savingMeta` are gone along
50
+ with `change-mode` and `save-meta`, replaced by a required `current` and a single
51
+ `apply`.
52
+
53
+ ### Minor Changes
54
+
55
+ - 6869846: A node's output ports say what flows through them, and so do the fields inside
56
+ them.
57
+
58
+ Node packages describe every output port they declare, and every field inside
59
+ one — what the branch is for, when it fires, what a value in the payload means.
60
+ None of it had ever appeared on screen: the Output tab in a node's configuration
61
+ drew the port's name and the field's type and discarded the sentence beside them.
62
+ It is now read in the reader's language, under the port's name and next to the
63
+ field's, without anything having to run first.
64
+
65
+ The two layers are drawn independently, because that is how they are published: of
66
+ the 84 node types registered today, 8 describe an output port and 22 describe a
67
+ field — 20 of those while the port holding the field says nothing at all. So a
68
+ port with nothing to say still shows what its fields have to say.
69
+
70
+ The same sentence is also on the tooltip of the port's handle on the canvas,
71
+ which is where somebody drawing a connection is actually looking. That one is a
72
+ convenience rather than a promise: a tooltip is not reachable by keyboard, so the
73
+ Output tab stays the place the text can be read.
74
+
75
+ **What a node expects to be given is shown too.** The panel of available data now
76
+ opens with what _this_ node takes: the kind of value, whether an upstream
77
+ connection is required, and the publisher's sentence about it where one exists.
78
+ That answers the opposite question to the list underneath it — the list says what
79
+ there is to feed from, this says what to feed in — and it had been published all
80
+ along: the studio was asking the catalogue for a node's input under a key the
81
+ service does not use, so every input description, data type and requirement
82
+ arrived and was dropped unread.
83
+
84
+ One rule was retired rather than repaired while doing it. A node card used to hide
85
+ its input dot when the manifest said an upstream connection was not required. It
86
+ read the same unused key, so it never once fired — and both halves of it were
87
+ wrong anyway: an optional input is still something you connect to, and a node that
88
+ consumes nothing may still be wired to fix the order it runs in. Every node card
89
+ offers somewhere to connect to, which is what they all did in practice.
90
+
91
+ - 04bd108: The dashboard's shortcuts into Import & Export, the SFTP server, the event stream
92
+ and inbound webhooks are offered as a way in only where the host serves them. Those
93
+ four surfaces belong to the host, not to this module, so the studio now asks the
94
+ router which of the paths this host actually has: in the cockpit all four keep
95
+ working exactly as before, and in a host that has none of them — or two of them —
96
+ the remaining cards stay where they were, keep their name and their description, and
97
+ answer a click by naming the surface and saying that it is to be found in the
98
+ Revenexx Cockpit, instead of leading into a route nobody serves. They look exactly as
99
+ they did — the arrow included.
100
+
101
+ **For hosts that test the studio:** in that state the card is a `button`, not a
102
+ `link`. A suite addressing one of the four with `getByRole('link', { name: 'Import
103
+ & Export' })` has to ask for the role its own host serves — which is why this is a
104
+ minor rather than a patch.
105
+
106
+ - 3c8b669: A step in a template's flow drawing is called the same thing wherever the drawing
107
+ is shown.
108
+
109
+ The small drawing of what a template would build is on four surfaces: the card in
110
+ the gallery, the cards on the dashboard and in the New workflow dialog, and large
111
+ at the top of a template's own page. It named its steps from the node catalogue —
112
+ but only where the page around it had asked for the catalogue for some other
113
+ reason. The gallery and a template's own page had; the dashboard and the create
114
+ dialog had not, so the same step read "HTTP Request" in one place and "Http
115
+ Request" in the next, and a reader moving from the dashboard's card to the page it
116
+ opens saw one step under two names.
117
+
118
+ The drawing now asks for the names it needs itself, on every surface it appears
119
+ on. The request is shared, so a panel of four cards still costs one — and a page
120
+ that already holds the catalogue costs nothing. Two things come along with the
121
+ names on the two surfaces that were missing them: a step is drawn with its own
122
+ symbol and its vendor's logo instead of a generic mark, and with the tint of its
123
+ category behind it, so the four drawings now look alike as well as read alike.
124
+
125
+ The hero drawing on a template's own page also gained an accessible name ("The
126
+ flow this template builds"), which its two neighbouring panels already had. It was
127
+ the largest thing on the page and the only part of it a screen reader could not be
128
+ pointed at. A minor rather than a patch for that name and for the marks: both are
129
+ additive, and an accessible name is something a host or a test can address.
130
+
131
+ - 8b8916f: A workflow's editor header says whether that workflow is active, and the play
132
+ symbol goes back to meaning "run it now".
133
+
134
+ The header used to carry one button that flipped between Activate and Pause, so
135
+ the state was never named — a reader had to invert the offered verb to work out
136
+ that "Activate" meant the workflow was paused, while the workflows list said
137
+ Paused outright. That button also wore the play triangle, the same glyph the
138
+ Run button in the canvas's control pane wears, so one symbol stood both for
139
+ "armed and waiting for its triggers" and for "execute now". A workflow that is
140
+ switched on is not running; it is waiting.
141
+
142
+ The header now names the state in the list's own words — Active or Paused — with
143
+ a switch beside it that flips it, and no glyph. The words come from the same
144
+ message as the list badge, so the two surfaces cannot drift apart in one language
145
+ and not in the other.
146
+
147
+ The activation gate is unchanged. A workflow with incomplete node settings still
148
+ cannot be switched on: the switch cannot be operated, and the reason — how many
149
+ node settings to fix first — is on the control both as a tooltip and as an
150
+ accessible description, because a disabled control shows no tooltip in Chrome.
151
+ The `shift+a` shortcut is still refused with the same message, and pausing an
152
+ active workflow still needs no validation.
153
+
154
+ - 17e938f: Unsaved work in the workflow editor is no longer thrown away without being asked
155
+ about.
156
+
157
+ Everything done on a workflow's canvas lives in the browser until Save is pressed,
158
+ and until now every way out of the editor discarded it silently. Clicking the
159
+ Workflows breadcrumb lost an afternoon's arrangement without a word. So did
160
+ reloading the page.
161
+
162
+ Worse, so did a move that was not leaving at all: a workflow's runs, missed
163
+ firings and earlier versions sit on tabs beside the canvas, and going to one of
164
+ them and back rebuilt the canvas from the _saved_ workflow. The work was still
165
+ there — the header still said "Unsaved changes", and Save would still have written
166
+ it — but nobody could see it any more, so Save wrote a workflow the operator had
167
+ been given no chance to look at.
168
+
169
+ Now:
170
+
171
+ - **Moving between a workflow's own tabs keeps the work.** Coming back to the
172
+ canvas shows it as it was left.
173
+ - **Leaving the workflow asks first**, and staying is what the question falls back
174
+ to: escape or a click beside it keeps the work and the workflow open. Discarding
175
+ is a button somebody has to press.
176
+ - **A reload or a closed browser tab raises the browser's own warning**, which is
177
+ the only wording available on that exit.
178
+ - **Putting an earlier version back says that the unsaved changes go with it.**
179
+ That restore has to discard them — an earlier version is what was asked for —
180
+ but it happens from a tab where the canvas is not on screen, so the question now
181
+ names what is about to be lost instead of taking it silently.
182
+
183
+ Moves the studio makes itself are not questioned: opening one of the workflow's
184
+ runs and closing it again, and landing in the copy that duplicating it just
185
+ created.
186
+
187
+ The promise and its criteria are `specs/workflow-save.md`. Hosts that render the
188
+ workflow editor or the version-history panel themselves gain two optional props —
189
+ the draft the page is holding, and whether there is one.
190
+
191
+ - 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.
192
+
193
+ 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.
194
+
195
+ 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.
196
+
197
+ - 8d55660: Opening a node no longer lands the cursor in its name.
198
+
199
+ A node's configuration used to open with the whole name selected, so it read as an
200
+ edit already in progress and the first key pressed replaced the name of a step the
201
+ user had only opened to look at. The name is left alone now, and the keyboard goes
202
+ to the dialog itself — Escape still closes it, Tab still stays inside it, and it
203
+ announces which node was opened rather than announcing the name field.
204
+
205
+ Renaming is unchanged where it was asked for: Rename in a card's right-click menu,
206
+ and the shortcut that menu names, still open the configuration with the cursor in
207
+ the name and the old name selected, so typing replaces it. That intent is now spent
208
+ on the one node it was asked for — saving a rename and opening another node used to
209
+ carry it along.
210
+
211
+ A minor rather than a patch because the dialog gained an accessible name it did not
212
+ have — `Configure <node>` — which a host or a test can now address it by. Nothing
213
+ was renamed or removed.
214
+
215
+ ### Patch Changes
216
+
217
+ - 9accf9e: The tenant's schedules no longer cost a request per workflow. The workflow list
218
+ already carries each workflow's triggers, so the Dashboard, the Schedules page and
219
+ the navigation rail read them from that one response instead of asking
220
+ `/workflows/{id}/triggers` once per workflow — a third of what opening the dashboard
221
+ cost on a cold visit, gone, with no change to what any of those surfaces show.
222
+
223
+ The per-workflow route is untouched for what it is actually for: a single workflow's
224
+ triggers in the editor, and creating, changing or removing one.
225
+
226
+ - 706281a: A variable's description is saved in the language it is being read in, and replacing
227
+ one no longer glues another language to the typing.
228
+
229
+ Two fields also carry a promise they were relied on for and never had — the name a
230
+ trigger goes by, and a variable's description both hand back exactly what was typed,
231
+ the same promise a node's name already had. That is the specification half; what
232
+ follows is what changed in the product.
233
+
234
+ On a studio set to German, editing a description that already carried a German text
235
+ wrote the typing into the English one: the field went on showing the German text, and
236
+ reopening the dialog showed the old wording with nothing to say that the edit had gone
237
+ nowhere. Descriptions that arrive from a template carry several languages, so this was
238
+ reachable by anyone working in a language other than English.
239
+
240
+ Two consequences of the same rule, both fixed here. A studio set to a **regional**
241
+ language — `de-CH` — reads a `de` description through the region fall-back, and used to
242
+ write the edit into a new `de-CH` key: the Swiss reader saw the new text, everyone on
243
+ plain German went on seeing the old one. And **clearing** a description now takes only
244
+ the language being edited; it used to drop the description in every language at once,
245
+ so emptying a German text destroyed the English one the field had never shown.
246
+
247
+ A description is therefore written under the language it was read from, and a language
248
+ the map does not have yet is written under its base subtag — never the host's raw tag.
249
+ **Clearing** a description removes the text that was on screen, which is not always the
250
+ same key: where the studio is borrowing another language's text — every description
251
+ carries English, so this is the common shape — emptying the field removes that one and
252
+ the description goes with it. Languages the field never displayed are left alone.
253
+
254
+ **Replacing** a description was the gesture that suffered for it. The field was
255
+ re-derived from the saved workflow on every keystroke, so clearing a description that
256
+ carried a second language refilled the field from that language at once — and the next
257
+ character was appended to a sentence the author never typed, then saved under _their_
258
+ language. Ctrl+A, Backspace, "Neu" on a German studio saved `How often it retries.Neu`
259
+ as the German text. The field now holds what is being typed into it while the dialog is
260
+ open, so clearing leaves it empty and what follows is only what was typed.
261
+
262
+ One read-side improvement comes with it: a host locale written with an underscore
263
+ (`de_CH`) now resolves to its language like any other tag, where it used to fall
264
+ through to English.
265
+ That also keeps a host locale the API rejects (`de-ch`, `en_US`, `zh-Hans`) out of a
266
+ key it validates, where it would have failed the whole workflow save rather than just
267
+ the description.
268
+
269
+ - f6a6fdb: The list of available data inside a node's setting opens again, and a setting
270
+ waiting on another one names it the way the form does.
271
+
272
+ A setting that takes a mapped value offers the workflow's data from the field
273
+ itself — earlier steps' outputs, the trigger payload, variables — and that list
274
+ silently stopped opening whenever an earlier step declared what its output
275
+ contains, which every published node does. Mapping a value then only worked
276
+ through the panel beside the form.
277
+
278
+ A setting whose options the platform has to be asked for tells the operator which
279
+ setting to fill in first, and it was naming it by its config key: `Set company_id
280
+ first` under a field labelled _Company_. It now names the label the form actually
281
+ shows, falling back to the key only where no setting matches it.
282
+
283
+ The list of available data is also addressable by name — _Available data for this
284
+ setting_ — so a screen reader announces which of the two offers it is reading. The
285
+ panel beside the form describes itself as _Available data_, and heard rather than
286
+ seen the two were the same words.
287
+
288
+ - 6be63aa: A sticky note's headings and lists are announced as headings and lists.
289
+
290
+ A note on the canvas rendered bold, italic, code and links as the real thing, but
291
+ a heading only as heavier text and a list item only as a bullet character beside
292
+ its words. A sighted reader saw the structure; anyone using a screen reader got an
293
+ unbroken run of text with no heading to jump to and no list to count. Notes are
294
+ where an author explains a workflow to whoever comes next, so this is exactly the
295
+ content that ought to be navigable.
296
+
297
+ A note's `#`, `##` and `###` are now real heading elements, starting at level two
298
+ so the page keeps the one top-level heading it promises, and a run of bulleted or
299
+ numbered lines is one list with its items inside it. The bullet is drawn as before
300
+ but no longer read out.
301
+
302
+ The note looks exactly as it did — this changed the markup, not the design.
303
+
304
+ It also closes a hole found while reviewing that rewrite, in code it did not
305
+ introduce: a note's link address was not escaped against the quote that ends an
306
+ HTML attribute, so a crafted address could put an event handler on the anchor the
307
+ note drew. Notes live in a workflow blob a tenant shares, so it reached whoever
308
+ opened the workflow. **If your users author notes, this is the reason to take this
309
+ release.**
310
+
311
+ - 2658447: Removing a group frame removes the frame, and deleting a connection redraws the
312
+ ones that are left.
313
+
314
+ **A frame folded shut no longer takes its members' connections with it.** Pressing
315
+ Delete on a folded frame did what it was meant to — the frame went, the nodes it
316
+ held stayed — and also removed, from the saved workflow, every connection that ran
317
+ between a node inside the frame and a node outside it. Nothing warned. While the
318
+ frame was folded those connections were drawn as the card's own, so the loss could
319
+ not be seen until the frame was gone and the members were drawn again with a line
320
+ missing, or until the workflow ran. Dissolving a frame through its own toolbar was
321
+ never affected; the keystroke was.
322
+
323
+ **A connection that is deleted no longer leaves its siblings bending around it.**
324
+ Where several connections leave one node, the canvas spreads them apart so their
325
+ horizontal runs do not land on the same line. Deleting one of them left the
326
+ survivors with the spread they had been given while it was still there, so a single
327
+ remaining connection curved as if it were avoiding a neighbour that no longer
328
+ existed — until something unrelated redrew the canvas or the page was reloaded.
329
+
330
+ Both came from the same place. One deletion gesture arrives from the canvas as two
331
+ separate reports — the connections first, the node second — and each half was acting
332
+ on its own: one deleted a connection by an id that, for a folded frame, belonged to
333
+ a connection the user had not touched, while the other never re-ranked what was
334
+ left. The two are now applied together, so deleting a connection reaches the host as
335
+ one change rather than two.
336
+
337
+ - ddbabc6: Deleting a selection of nodes in the workflow editor costs one canvas rebuild
338
+ instead of one per node.
339
+
340
+ The editor applied a Delete one id at a time, and each of those rebuilt the whole
341
+ canvas — nodes, edges, every group's member count, the handle bounds — and made a
342
+ structural clone of the whole workflow to report the change. A ten-node selection
343
+ therefore cost ten of each where one does. The batch path this should have taken
344
+ already existed and was already what the context menu used, so the two routes
345
+ into the same gesture were paying different prices.
346
+
347
+ Nothing about the gesture changes: the same nodes go, a group frame in the
348
+ selection still dissolves and leaves its members where they are, and the workflow
349
+ ends up in the same state. What is new is that the route has a test — pressing
350
+ the key on more than one node was not covered anywhere before.
351
+
352
+ - aac0de4: A magnifier, a spinner, a back arrow, a bolt and a warning triangle keep their
353
+ shape from one screen to the next.
354
+
355
+ Five shapes were drawn from both of the studio's icon libraries at once: whoever
356
+ learned the magnifier on the templates page met a different magnifier in the node
357
+ palette, and the same held for the spinner on a node card, the back arrow in the
358
+ palette, the palette's trigger bolt and the amber warning badge. All five are now
359
+ drawn from Solar, at every place that draws them.
360
+
361
+ Two duplications turned up beside them and went with them. The magnifier had a
362
+ third drawing, in the node inspector's input search. And the trigger's glyph was
363
+ drawn on eight surfaces that agreed in none of them: one glyph on a trigger card
364
+ and another in the header that opens from it, a globe for the webhook on the
365
+ templates page against a link everywhere else, and a different drawing again in the
366
+ palette's trigger tiles, the create dialog's trigger select and the template flow
367
+ preview. A trigger is now the same picture from the moment it is picked to the card
368
+ it becomes.
369
+
370
+ One of those eight was telling you something untrue rather than something
371
+ inconsistent. In the run list, the row for a run is its trigger's glyph, its `#id`
372
+ and its status badge — so that glyph is the only thing on the row that says what
373
+ started the run, and an event-triggered run drew the **manual play button**: "you
374
+ started this yourself", about a run nobody started. Every run now shows the trigger
375
+ it actually had.
376
+
377
+ Nothing about the module's dependencies changes: every file that drew a Lucide
378
+ glyph before still draws one, so `lucide-vue-next` remains as obligatory a peer
379
+ dependency for a host as it was. What this buys is recognition, not a smaller
380
+ install. `docs/icons.md` records what the icon language now is, the eight
381
+ shapes still drawn twice — four of which a rule about glyph _names_ cannot see, and
382
+ that is the finding underneath the sweep — and the one thing a small Solar glyph
383
+ needs on a coloured background.
384
+
385
+ - 276bf2f: A connection test that passed says what it reached
386
+
387
+ The service has always answered a successful test with a sentence, and the client
388
+ threw it away in three separate places: the composable returned a bare `{ ok: true }`
389
+ and discarded the response, `credentialState()` carried `last_test_message` only in
390
+ its `failed` branch, and the detail dialog typed the live result as `{ ok, error? }`
391
+ and rendered a fixed confirmation whenever `ok`. Each was written as "it worked, or
392
+ else here is a reason", so a message could only ever be a complaint.
393
+
394
+ Now a credential type that reached something can name it, and **all three surfaces
395
+ that offer the test show what it said** — a credential's detail view, the dialog it is
396
+ added and edited in, and the one a node's credential field opens. Where a type reports
397
+ nothing the wording is unchanged.
398
+
399
+ The same field carries the reason a test was **refused**, and all three dropped that
400
+ too: the service sends `message` whichever way the test went, and never sends the
401
+ `error` these surfaces were reading — that one is synthesised locally when the call
402
+ does not arrive at all. So a refusal showed "Connection failed." with the reason
403
+ sitting unread beside it. It is shown now.
404
+
405
+ And the detail view says it **once**. It used to print the sentence twice after a
406
+ test — the live result and the state block both had it — and past 497 characters the
407
+ two disagreed, because the platform stores a shortened copy of what it answered.
408
+
409
+ This is worth more than a nicer sentence where a credential's target is **derived
410
+ rather than configured**. A DeepL key decides by itself which of two API hosts every
411
+ translation goes to — the plans are different addresses and a key is refused on the
412
+ wrong one — so since the node stopped asking for an endpoint, the credential is the
413
+ only thing that knows, and its test result is the only place it can say so.
414
+
415
+ The promise is `specs/credential-test.md`, new: one spec rather than the same
416
+ criterion written into three, which is what the granularity rule asks for once a
417
+ promise reaches more than one surface.
418
+
419
+ ## 0.7.0
420
+
421
+ ### Minor Changes
422
+
423
+ - f7ddd90: The run surfaces now update from pushed platform events, not only from their own
424
+ refresh.
425
+
426
+ Where a host has Talkback configured, the Runs list, a workflow's Runs tab, a run's
427
+ record and the replay canvas react to the run and workflow lifecycle the integrations
428
+ service publishes — so a run that finishes is on screen in about a second instead of
429
+ up to three, and a run started from the API, a schedule or an MCP tool appears on an
430
+ idle list that previously had no reason to ask. `workflow.deleted` also takes its runs
431
+ off the list, which no `run.deleted` event exists to do.
432
+
433
+ A run's record follows the same reports, and it now re-reads everything it shows when
434
+ the run it is open on ends — the status it displays comes from a different request
435
+ than the one an ending run used to trigger, so a record left open on a finishing run
436
+ could keep showing the state before it ended. That is fixed for the reported route;
437
+ the three-second poll behind it is unchanged.
438
+
439
+ While events are actually arriving, each surface's own refresh slows to every 30
440
+ seconds and stays as the backstop rather than stopping — the connection signal
441
+ available today cannot tell a quiet socket from a dead one, so a list that stopped
442
+ converging was not a trade worth making. **A connection that reports nothing is
443
+ treated as no connection**: the slower refresh is taken only once something has been
444
+ delivered, so a tenant whose event catalogue does not release these topics to browsers
445
+ keeps the cadence it always had rather than becoming the slowest configuration of the
446
+ three. If the connection drops and comes back having missed more than the platform can
447
+ replay, every surface reads again instead of waiting for a report that no longer
448
+ exists.
449
+
450
+ With no Talkback host configured — the default — nothing is subscribed, neither
451
+ `@revenexx/talkback-js` nor `centrifuge` is loaded, and every surface polls exactly as
452
+ before.
453
+
454
+ **This raises the floor for `@revenexx/studio-shared` to `^0.3.0`**, which is the
455
+ release that carries the realtime seam. A host installing this module gets the newer
456
+ one automatically; a host that pins studio-shared itself has to move with it, or it
457
+ will end up with two copies and no realtime at all.
458
+
459
+ Realtime needs `@revenexx/talkback-js` and `centrifuge` in the host application —
460
+ they are optional peers of studio-shared, so a host that never sets a Talkback host
461
+ installs neither.
462
+
463
+ - 9ef81b8: The studio reads in the language your application chose, both halves of the
464
+ screen at once.
465
+
466
+ Until now every surface was English. Two things change that. The text the node
467
+ packages publish — a node's name, what it is for, the label and example of every
468
+ setting it offers, a credential type's fields, a template's whole description —
469
+ has been shipping in German as well as English all along, and was being discarded
470
+ on the way to the screen; it is now resolved in the reader's language. And the
471
+ studio's own chrome — headings, buttons, tabs, table headers, empty states,
472
+ toasts, confirmations — is read from a message catalogue the module carries
473
+ itself, in English and German.
474
+
475
+ You do not need an i18n library installed, and the module never reads your
476
+ catalogue, a cookie or a browser setting: the language comes from you. Wire one
477
+ of two ways.
478
+
479
+ A language that does not change, in `nuxt.config.ts`:
480
+
481
+ ```ts
482
+ export default defineNuxtConfig({
483
+ modules: ["@revenexx/studio-integrations"],
484
+ studioIntegrations: { locale: "de" },
485
+ });
486
+ ```
487
+
488
+ Deployments can override that with `NUXT_PUBLIC_STUDIO_INTEGRATIONS_LOCALE`
489
+ without a rebuild.
490
+
491
+ A language the user switches while the app is running, from a plugin of yours:
492
+
493
+ ```ts
494
+ const { setLocale } = useIntegrationsLocale();
495
+ watch(hostLocale, (l) => setLocale(l), { immediate: true });
496
+ ```
497
+
498
+ `useIntegrationsLocale()` is auto-imported like every other composable here, so
499
+ you import nothing. A switch reaches surfaces that are already open — no reload,
500
+ no refetch, no reopening a dialog. Both routes may be left alone: with neither
501
+ wired the studio is English, exactly as before, so upgrading changes nothing
502
+ until you ask it to.
503
+
504
+ A tag is BCP-47 and a region falls back to its language, so `de-CH` reads German
505
+ rather than English; anything the catalogue does not carry reads English.
506
+
507
+ **This expects a client-rendered host.** The language is held once per module
508
+ instance, which is once per browser tab on the client and once per process on a
509
+ server. If you render the studio server-side _and_ give each visitor their own
510
+ language, one visitor's choice can reach another's page — a page in the wrong
511
+ language, nothing more, since the value only chooses between the translations of a
512
+ string. A single fixed language is unaffected either way. Both routes above are
513
+ safe in a client-rendered app, which is what the known consumers are.
514
+
515
+ Four English strings changed spelling, to British. One of them is an accessible
516
+ name: the grey swatch in the sticky-note and group-frame colour pickers is
517
+ `Grey`, not `Gray` — update it if a test of yours addresses it by name. The other
518
+ three are wording only: two tooltips on the sample-payload button say `catalogue`,
519
+ and the workflow settings dialog says `Execution behaviour`.
520
+
521
+ - 7cb9f1c: The studio's lists narrow for real.
522
+
523
+ Credentials, runs, workflows and schedules each carried a filter button whose menu
524
+ read "No filters defined." — it could never filter anything. Each now narrows by the
525
+ dimensions its own rows already show: a credential's state and system, a run's
526
+ outcome and what started it, a workflow's position, build and dispatch mode, and
527
+ whether a schedule is live plus the timezone it fires in. Two choices narrow
528
+ together, each has a way back to everything, and the words on the menu are the words
529
+ on the rows.
530
+
531
+ Secrets loses the button instead: a key and two dates have nothing categorical to
532
+ narrow by, so the honest outcome there is not offering it.
533
+
534
+ A narrowing applies to the rows the page has loaded. On the lists collected per
535
+ workflow that is as far back as the page has read.
536
+
537
+ - 8f332af: Deleting is drawn with one bin everywhere, duplicating with one pair of sheets, and a
538
+ trigger's delete button says what it deletes.
539
+
540
+ The studio drew the delete action with three different bin glyphs, two of them one
541
+ click apart on the same node: a node's hover toolbar used Lucide's bin while that
542
+ node's own inspector used Solar's, and the credential surfaces used a third, fuller
543
+ Solar bin. Nothing was broken — what it cost is recognition, on the one action that
544
+ cannot be undone. Every delete and remove in the studio now draws Solar's
545
+ `TrashBinMinimalistic`.
546
+
547
+ The copy sheets sat one button along and are folded in: a node's hover toolbar drew
548
+ Lucide's glyph for **Duplicate** while that same node's inspector drew Solar's for
549
+ **Copy**. Both are Solar's now.
550
+
551
+ Two things a host or a test may notice:
552
+
553
+ - **The trigger card's delete button has an accessible name**, `Delete trigger`,
554
+ where it previously fell back to its `Delete` tooltip. That is what the node card's
555
+ `Delete node` already did, so the two can now be addressed and heard the same way.
556
+ - **No delete icon is imported under another library's name any more.** The alias
557
+ `TrashBinMinimalistic as Trash2` is what hid the divergence — two components read
558
+ identically in the markup and differed only in an import line. The bin travels as
559
+ `TrashBin`.
560
+
561
+ Why Solar, what `lucide-vue-next` is still for, and why the glyph itself is not
562
+ promised in a spec: `docs/icons.md`. It also names what is left — five shapes the
563
+ studio still draws from both libraries — and the ticket that carries them.
564
+
565
+ - fa0ef1a: The studio navigation stays when a workflow is opened, and the canvas gets its
566
+ width only when the operator asks.
567
+
568
+ Until now, opening a workflow — or one of its runs — folded the navigation away on
569
+ mount, and nothing anywhere brought it back: the way on was the breadcrumb or the
570
+ browser's back button. That fold is gone. The rail now stands on every surface,
571
+ including a workflow's canvas, and a control at the head of the workflow page,
572
+ reading **Hide navigation**, hands its width to the canvas when the operator wants
573
+ it. The same control then reads **Show navigation** and gives it back, without
574
+ leaving the surface. The choice is remembered per browser, so it is stated once
575
+ rather than on every visit, and it applies to the canvas alone — a run's record,
576
+ the run lists and the earlier versions keep the navigation either way.
577
+
578
+ Two things to know if you host this module:
579
+
580
+ - **A folded rail is now `inert` and `aria-hidden`.** It used to be clipped to zero
581
+ width with its links still focusable, so a keyboard walked into a navigation
582
+ nobody could see. If a test of yours reaches into the collapsed sidebar, it will
583
+ no longer find it in the accessibility tree — which is the point.
584
+ - **The fold is still driven by `useIntegrationsFocus()`**, unchanged, so a host
585
+ shell that reads `focused` keeps working as before. What changed is who turns it
586
+ on: nothing does it by itself any more. If your own shell collapses the sidebar
587
+ on that state, make sure the surface doing so also offers the way back — the
588
+ control belongs to the page, because a host shell can be replaced and the module's
589
+ cannot reach into it.
590
+
591
+ Two new accessible names, in English and German: `Hide navigation` /
592
+ `Show navigation`.
593
+
594
+ ### Patch Changes
595
+
596
+ - 30f5bda: A group frame now tells the truth about what it holds as soon as a member is deleted.
597
+
598
+ Deleting a node out of a group left the frame printing the count it had before —
599
+ `Invoice sync · 3 nodes` over two remaining nodes — until the page was reloaded. The
600
+ saved workflow was correct throughout; it was the caption that lagged. The larger
601
+ half of the same defect: deleting a frame's last member left the frame drawn on the
602
+ canvas over a workflow that no longer contained it, so the editor showed a group
603
+ that had already ceased to exist.
604
+
605
+ Both follow the deletion at once now. An empty frame you drew yourself still stays —
606
+ it counts down to `0 nodes` and waits to be filled.
607
+
608
+ The cause was timing rather than arithmetic: the canvas rebuild ran inside Vue Flow's
609
+ own change pass, which left the rendered graph on the array from before the deletion.
610
+ It is deferred by one tick. Nothing about the API, the saved blob or the keyboard
611
+ changes.
612
+
613
+ - d690841: A note on a read-only canvas no longer offers controls that do nothing.
614
+
615
+ On the run replay and the revision preview, a sticky note used to be drawn with
616
+ the toolbar it has in the editor — a bin, seven colours, a corner handle — and
617
+ could still be double-clicked into a text field. None of it had any effect: the
618
+ note survived its own Delete, typing into it changed nothing, and the workflow
619
+ never became dirty. A reader could not tell "not allowed here" from "broken".
620
+
621
+ The note is now read-only in the way a node card and a group frame already were:
622
+ no toolbar, no resize handle, and a double-click opens nothing. An empty note is
623
+ quiet too: the _Double-click to edit_ hint belongs to the editor, and on these
624
+ canvases it named the one gesture the note refuses. Everything the note says stays
625
+ exactly as readable, formatting and all — this removes affordances, not content.
626
+
627
+ A double-click on a read-only note now reaches the canvas instead of being
628
+ swallowed, so it zooms there like a double-click on a node card or on empty space.
629
+ A group frame's label was swallowing it the same way, and no longer does — the note
630
+ and that label were the two places on those canvases where the gesture did nothing
631
+ at all, and a dead spot reads as broken. The zoom itself is how these canvases
632
+ behave rather than something promised: what is promised is that nothing opens to be
633
+ edited.
634
+
635
+ If you render `StickyNoteView` yourself: the read-only state _is_ the absence of
636
+ its callbacks. `onUpdate` and `onRemove` in `StickyNodeData` are now optional, and
637
+ a note handed neither draws no tools — the pattern `GroupFrameView` already used
638
+ for its own toolbar. Passing no-ops, which is what the two read-only panels did,
639
+ now means "editable, and nothing happens".
640
+
641
+ A host addressing the note's `Delete note` button or its colour swatches on a
642
+ replay or preview canvas will no longer find them. That is the fix, which is why
643
+ this is a patch: nothing here is additive, and what a host can observe is the
644
+ defect being gone.
645
+
3
646
  ## 0.6.0
4
647
 
5
648
  ### Minor Changes