@revenexx/studio-integrations 0.7.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.
- package/CHANGELOG.md +416 -0
- package/dist/module.json +1 -1
- package/dist/module.mjs +2 -1
- package/dist/runtime/components/Integrations/CredentialCreateDialog.vue +4 -1
- package/dist/runtime/components/Integrations/CredentialDetailDialog.vue +8 -2
- package/dist/runtime/components/Integrations/ExpressionInput.vue +5 -0
- package/dist/runtime/components/Integrations/NodeConfigDynamicField.d.vue.ts +3 -0
- package/dist/runtime/components/Integrations/NodeConfigDynamicField.vue +16 -3
- package/dist/runtime/components/Integrations/NodeConfigDynamicField.vue.d.ts +3 -0
- package/dist/runtime/components/Integrations/NodeConfigDynamicSchema.vue +1 -0
- package/dist/runtime/components/Integrations/NodeConfigField.d.vue.ts +3 -0
- package/dist/runtime/components/Integrations/NodeConfigField.vue +2 -0
- package/dist/runtime/components/Integrations/NodeConfigField.vue.d.ts +3 -0
- package/dist/runtime/components/Integrations/NodeInspector.d.vue.ts +2 -2
- package/dist/runtime/components/Integrations/NodeInspector.vue +95 -10
- package/dist/runtime/components/Integrations/NodeInspector.vue.d.ts +2 -2
- package/dist/runtime/components/Integrations/NodeOutputSchema.d.vue.ts +2 -1
- package/dist/runtime/components/Integrations/NodeOutputSchema.vue +34 -8
- package/dist/runtime/components/Integrations/NodeOutputSchema.vue.d.ts +2 -1
- package/dist/runtime/components/Integrations/NodePalette.vue +12 -8
- package/dist/runtime/components/Integrations/StickyNoteView.vue +45 -11
- package/dist/runtime/components/Integrations/SurfaceCard.d.vue.ts +50 -0
- package/dist/runtime/components/Integrations/SurfaceCard.vue +55 -0
- package/dist/runtime/components/Integrations/SurfaceCard.vue.d.ts +50 -0
- package/dist/runtime/components/Integrations/TemplateCard.vue +3 -3
- package/dist/runtime/components/Integrations/TemplateFlowPreview.vue +12 -3
- package/dist/runtime/components/Integrations/WorkflowCreateDialog.vue +5 -4
- package/dist/runtime/components/Integrations/WorkflowEditor.d.vue.ts +16 -0
- package/dist/runtime/components/Integrations/WorkflowEditor.vue +52 -11
- package/dist/runtime/components/Integrations/WorkflowEditor.vue.d.ts +16 -0
- package/dist/runtime/components/Integrations/WorkflowHistoryPanel.d.vue.ts +6 -0
- package/dist/runtime/components/Integrations/WorkflowHistoryPanel.vue +4 -2
- package/dist/runtime/components/Integrations/WorkflowHistoryPanel.vue.d.ts +6 -0
- package/dist/runtime/components/Integrations/WorkflowNodeView.vue +59 -28
- package/dist/runtime/components/Integrations/WorkflowRunReplayPanel.vue +3 -4
- package/dist/runtime/components/Integrations/WorkflowSettingsDialog.d.vue.ts +16 -17
- package/dist/runtime/components/Integrations/WorkflowSettingsDialog.vue +37 -26
- package/dist/runtime/components/Integrations/WorkflowSettingsDialog.vue.d.ts +16 -17
- package/dist/runtime/components/Integrations/WorkflowTriggerView.vue +4 -5
- package/dist/runtime/components/Integrations/WorkflowVariablesDialog.vue +53 -14
- package/dist/runtime/composables/useIntegrationsCredentials.d.ts +11 -0
- package/dist/runtime/composables/useIntegrationsCredentials.js +2 -2
- package/dist/runtime/composables/useIntegrationsNodes.js +11 -1
- package/dist/runtime/composables/useIntegrationsSchedules.d.ts +3 -2
- package/dist/runtime/composables/useIntegrationsTriggers.d.ts +23 -3
- package/dist/runtime/composables/useIntegrationsTriggers.js +18 -7
- package/dist/runtime/composables/useIntegrationsWorkflows.d.ts +10 -1
- package/dist/runtime/composables/useIntegrationsWorkflows.js +25 -4
- package/dist/runtime/composables/useNodeConfigResolve.js +2 -1
- package/dist/runtime/data/integrationNodeCatalog.d.ts +22 -1
- package/dist/runtime/data/integrationNodeCatalog.js +8 -4
- package/dist/runtime/data/nodeInputData.d.ts +58 -1
- package/dist/runtime/data/nodeInputData.js +30 -5
- package/dist/runtime/data/triggerGlyphs.d.ts +47 -0
- package/dist/runtime/data/triggerGlyphs.js +11 -0
- package/dist/runtime/i18n/messages/de.json +20 -3
- package/dist/runtime/i18n/messages/en.json +20 -3
- package/dist/runtime/pages/integrations/credentials.vue +4 -1
- package/dist/runtime/pages/integrations/index.vue +16 -17
- package/dist/runtime/pages/integrations/templates/[slug].vue +13 -5
- package/dist/runtime/pages/integrations/workflows/[id].vue +193 -104
- package/dist/runtime/types/integrations.d.ts +25 -1
- package/dist/runtime/utils/cockpitSources.d.ts +22 -3
- package/dist/runtime/utils/credentialState.d.ts +6 -1
- package/dist/runtime/utils/credentialState.js +1 -1
- package/dist/runtime/utils/localize.d.ts +34 -0
- package/dist/runtime/utils/localize.js +22 -7
- package/dist/runtime/utils/pollBudget.d.ts +1 -1
- package/dist/runtime/utils/servedPaths.d.ts +22 -0
- package/dist/runtime/utils/servedPaths.js +3 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,421 @@
|
|
|
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
|
+
|
|
3
419
|
## 0.7.0
|
|
4
420
|
|
|
5
421
|
### Minor Changes
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
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",
|
|
@@ -259,7 +259,10 @@ async function submit() {
|
|
|
259
259
|
class="rounded-md px-3 py-2 text-sm"
|
|
260
260
|
:class="testResult.ok ? 'bg-emerald-500/10 text-emerald-700' : 'bg-rose-500/10 text-rose-700'"
|
|
261
261
|
>
|
|
262
|
-
|
|
262
|
+
<!-- The type's own sentence, either way. This is the surface where it is
|
|
263
|
+
worth the most: nothing is stored yet, so the operator is deciding
|
|
264
|
+
whether these access data reach what they meant (specs/credential-test.md). -->
|
|
265
|
+
{{ testResult.ok ? testResult.message ?? t("integration.credentials.shared.test.ok") : testResult.error ?? testResult.message ?? t("integration.credentials.shared.test.failed") }}
|
|
263
266
|
</div>
|
|
264
267
|
</div>
|
|
265
268
|
|
|
@@ -214,7 +214,13 @@ async function connect() {
|
|
|
214
214
|
{{ t("integration.credentials.detail.action.reconnect") }}
|
|
215
215
|
</Button>
|
|
216
216
|
</div>
|
|
217
|
-
|
|
217
|
+
<!-- The stored sentence, and only while nothing fresher is on screen. The
|
|
218
|
+
live box below shows the result of a test just run, and the reload that
|
|
219
|
+
follows it puts the very same sentence here — so both would print it
|
|
220
|
+
twice, and past the length the platform truncates at, twice differently.
|
|
221
|
+
The freshly returned one wins, being whole (specs/credential-test.md
|
|
222
|
+
AC-1). -->
|
|
223
|
+
<p v-if="state.message && !liveTest" class="mt-1 text-sm break-words opacity-90">
|
|
218
224
|
{{ state.message }}
|
|
219
225
|
</p>
|
|
220
226
|
<p v-else-if="state.key === 'untested'" class="mt-1 text-sm opacity-80">
|
|
@@ -314,7 +320,7 @@ async function connect() {
|
|
|
314
320
|
class="rounded-md px-3 py-2 text-sm"
|
|
315
321
|
:class="liveTest.ok ? 'bg-emerald-500/10 text-emerald-700' : 'bg-rose-500/10 text-rose-700'"
|
|
316
322
|
>
|
|
317
|
-
{{ liveTest.ok ? t("integration.credentials.shared.test.ok") : liveTest.error ?? t("integration.credentials.shared.test.failed") }}
|
|
323
|
+
{{ liveTest.ok ? liveTest.message ?? t("integration.credentials.shared.test.ok") : liveTest.error ?? liveTest.message ?? t("integration.credentials.shared.test.failed") }}
|
|
318
324
|
</div>
|
|
319
325
|
|
|
320
326
|
<!-- The save was refused. Same rule as the create dialog: stated here, and at
|
|
@@ -220,8 +220,13 @@ function insert(expr) {
|
|
|
220
220
|
<span class="min-w-0 truncate font-mono" :class="preview.misses ? 'text-amber-600' : 'text-emerald-700'">{{ preview.resolved }}</span>
|
|
221
221
|
</p>
|
|
222
222
|
|
|
223
|
+
<!-- Named, because the same expressions are offered twice on this surface —
|
|
224
|
+
here and in the panel beside the form — and a popup nothing can address
|
|
225
|
+
is a popup nothing can test either. -->
|
|
223
226
|
<div
|
|
224
227
|
v-if="open && hasSuggestions"
|
|
228
|
+
role="group"
|
|
229
|
+
:aria-label="t('integration.nodeConfig.expression.picker.aria')"
|
|
225
230
|
class="absolute right-0 top-full z-50 mt-1 flex max-h-72 w-80 flex-col rounded-md border border-black/[0.08] bg-white text-sm shadow-lg"
|
|
226
231
|
>
|
|
227
232
|
<div class="shrink-0 border-b border-black/[0.06] p-1">
|
|
@@ -5,6 +5,9 @@ type __VLS_Props = {
|
|
|
5
5
|
field: ConfigField;
|
|
6
6
|
config: Record<string, unknown>;
|
|
7
7
|
modelValue: unknown;
|
|
8
|
+
/** The settings this one sits among, so a dependency can be named as the
|
|
9
|
+
* operator sees it rather than by its config key. */
|
|
10
|
+
siblingFields?: ConfigField[];
|
|
8
11
|
};
|
|
9
12
|
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
10
13
|
"update:modelValue": (value: unknown) => any;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { computed, ref } from "vue";
|
|
3
|
+
import { isVersionExecutable } from "../../data/integrationNodeCatalog";
|
|
3
4
|
import { ChevronDown } from "lucide-vue-next";
|
|
4
5
|
import { Input } from "@revenexx/studio";
|
|
5
6
|
import { resolveLocalized } from "../../utils/localize";
|
|
@@ -8,12 +9,14 @@ const props = defineProps({
|
|
|
8
9
|
version: { type: String, required: true },
|
|
9
10
|
field: { type: Object, required: true },
|
|
10
11
|
config: { type: Object, required: true },
|
|
11
|
-
modelValue: { type: null, required: true }
|
|
12
|
+
modelValue: { type: null, required: true },
|
|
13
|
+
siblingFields: { type: Array, required: false }
|
|
12
14
|
});
|
|
13
15
|
const emit = defineEmits(["update:modelValue"]);
|
|
14
16
|
const t = useIntegrationsT();
|
|
15
17
|
const search = ref("");
|
|
16
18
|
const focused = ref(false);
|
|
19
|
+
const versionNotReady = computed(() => !isVersionExecutable(props.slug, props.version));
|
|
17
20
|
const q = useNodeConfigResolve({
|
|
18
21
|
slug: () => props.slug,
|
|
19
22
|
version: () => props.version,
|
|
@@ -22,6 +25,10 @@ const q = useNodeConfigResolve({
|
|
|
22
25
|
dependsOn: () => props.field.dependsOn,
|
|
23
26
|
search: () => focused.value ? search.value : ""
|
|
24
27
|
});
|
|
28
|
+
const unsatisfiedLabels = computed(() => q.unsatisfied.value.map((key) => {
|
|
29
|
+
const sibling = props.siblingFields?.find((f) => f.key === key);
|
|
30
|
+
return sibling && resolveLocalized(sibling.label) || key;
|
|
31
|
+
}));
|
|
25
32
|
const options = computed(() => q.data.value?.options ?? []);
|
|
26
33
|
const isMulti = computed(() => props.field.type === "multiselect");
|
|
27
34
|
const disabledControlClass = "flex h-8 items-center rounded-md border border-black/[0.08] bg-white px-2 text-sm text-muted-foreground opacity-50";
|
|
@@ -76,10 +83,16 @@ function toggleMulti(optValue) {
|
|
|
76
83
|
|
|
77
84
|
<template>
|
|
78
85
|
<div>
|
|
86
|
+
<!-- the pinned version cannot be run, so there is nothing to resolve -->
|
|
87
|
+
<template v-if="versionNotReady">
|
|
88
|
+
<div :class="disabledControlClass">—</div>
|
|
89
|
+
<p class="mt-1 text-sm text-amber-600">{{ t("integration.nodeConfig.dynamicField.versionNotReady") }}</p>
|
|
90
|
+
</template>
|
|
91
|
+
|
|
79
92
|
<!-- gated: required dependencies still unset -->
|
|
80
|
-
<template v-if="q.gated.value">
|
|
93
|
+
<template v-else-if="q.gated.value">
|
|
81
94
|
<div :class="disabledControlClass">—</div>
|
|
82
|
-
<p class="mt-1 text-sm text-amber-600">{{ t("integration.nodeConfig.dynamicField.gated", { keys:
|
|
95
|
+
<p class="mt-1 text-sm text-amber-600">{{ t("integration.nodeConfig.dynamicField.gated", { keys: unsatisfiedLabels.join(", ") }) }}</p>
|
|
83
96
|
</template>
|
|
84
97
|
|
|
85
98
|
<!-- first load: no data yet -->
|
|
@@ -5,6 +5,9 @@ type __VLS_Props = {
|
|
|
5
5
|
field: ConfigField;
|
|
6
6
|
config: Record<string, unknown>;
|
|
7
7
|
modelValue: unknown;
|
|
8
|
+
/** The settings this one sits among, so a dependency can be named as the
|
|
9
|
+
* operator sees it rather than by its config key. */
|
|
10
|
+
siblingFields?: ConfigField[];
|
|
8
11
|
};
|
|
9
12
|
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
10
13
|
"update:modelValue": (value: unknown) => any;
|
|
@@ -6,6 +6,9 @@ type __VLS_Props = {
|
|
|
6
6
|
version: string;
|
|
7
7
|
secretKeys: string[];
|
|
8
8
|
staticKeys?: string[];
|
|
9
|
+
/** The whole set of settings this one belongs to — a `dynamic` field names the
|
|
10
|
+
* ones it waits for out of it (NodeConfigDynamicField). */
|
|
11
|
+
siblingFields?: ConfigField[];
|
|
9
12
|
depth?: number;
|
|
10
13
|
variables?: Record<string, WorkflowVariable>;
|
|
11
14
|
upstreamOutputs?: Array<{
|
|
@@ -23,6 +23,7 @@ const props = defineProps({
|
|
|
23
23
|
version: { type: String, required: true },
|
|
24
24
|
secretKeys: { type: Array, required: true },
|
|
25
25
|
staticKeys: { type: Array, required: false },
|
|
26
|
+
siblingFields: { type: Array, required: false },
|
|
26
27
|
depth: { type: Number, required: false },
|
|
27
28
|
variables: { type: Object, required: false },
|
|
28
29
|
upstreamOutputs: { type: Array, required: false },
|
|
@@ -395,6 +396,7 @@ function setArrayItemField(index, fieldKey, v) {
|
|
|
395
396
|
:field="field"
|
|
396
397
|
:config="config"
|
|
397
398
|
:model-value="value"
|
|
399
|
+
:sibling-fields="siblingFields"
|
|
398
400
|
@update:model-value="write"
|
|
399
401
|
/>
|
|
400
402
|
|
|
@@ -6,6 +6,9 @@ type __VLS_Props = {
|
|
|
6
6
|
version: string;
|
|
7
7
|
secretKeys: string[];
|
|
8
8
|
staticKeys?: string[];
|
|
9
|
+
/** The whole set of settings this one belongs to — a `dynamic` field names the
|
|
10
|
+
* ones it waits for out of it (NodeConfigDynamicField). */
|
|
11
|
+
siblingFields?: ConfigField[];
|
|
9
12
|
depth?: number;
|
|
10
13
|
variables?: Record<string, WorkflowVariable>;
|
|
11
14
|
upstreamOutputs?: Array<{
|
|
@@ -28,13 +28,13 @@ type __VLS_Props = {
|
|
|
28
28
|
refusedFields?: Record<string, string>;
|
|
29
29
|
};
|
|
30
30
|
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
31
|
-
close: () => any;
|
|
32
31
|
update: (next: WorkflowTrigger | WorkflowNode) => any;
|
|
32
|
+
close: () => any;
|
|
33
33
|
remove: () => any;
|
|
34
34
|
navigate: (id: string) => any;
|
|
35
35
|
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
36
|
-
onClose?: (() => any) | undefined;
|
|
37
36
|
onUpdate?: ((next: WorkflowTrigger | WorkflowNode) => any) | undefined;
|
|
37
|
+
onClose?: (() => any) | undefined;
|
|
38
38
|
onRemove?: (() => any) | undefined;
|
|
39
39
|
onNavigate?: ((id: string) => any) | undefined;
|
|
40
40
|
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|