@revenexx/studio-integrations 1.1.0 → 1.2.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 +520 -0
- package/README.md +3 -1
- package/dist/module.json +1 -1
- package/dist/runtime/components/Integrations/CredentialCreateDialog.vue +6 -18
- package/dist/runtime/components/Integrations/CredentialDetailDialog.vue +13 -23
- package/dist/runtime/components/Integrations/CredentialRevenexxSource.vue +7 -6
- package/dist/runtime/components/Integrations/DeadLettersPanel.vue +15 -4
- package/dist/runtime/components/Integrations/ExpressionInput.d.vue.ts +4 -0
- package/dist/runtime/components/Integrations/ExpressionInput.vue +77 -22
- package/dist/runtime/components/Integrations/ExpressionInput.vue.d.ts +4 -0
- package/dist/runtime/components/Integrations/GroupFrameView.vue +5 -4
- package/dist/runtime/components/Integrations/LoadingAnnouncement.d.vue.ts +38 -0
- package/dist/runtime/components/Integrations/LoadingAnnouncement.vue +16 -0
- package/dist/runtime/components/Integrations/LoadingAnnouncement.vue.d.ts +38 -0
- package/dist/runtime/components/Integrations/NodeConfigField.vue +23 -0
- package/dist/runtime/components/Integrations/NodeInspector.d.vue.ts +2 -2
- package/dist/runtime/components/Integrations/NodeInspector.vue +25 -32
- package/dist/runtime/components/Integrations/NodeInspector.vue.d.ts +2 -2
- package/dist/runtime/components/Integrations/RunActionsMenu.vue +5 -3
- package/dist/runtime/components/Integrations/RunDetailPanel.vue +5 -17
- package/dist/runtime/components/Integrations/RunResponseModal.d.vue.ts +30 -8
- package/dist/runtime/components/Integrations/RunResponseModal.vue +92 -24
- package/dist/runtime/components/Integrations/RunResponseModal.vue.d.ts +30 -8
- package/dist/runtime/components/Integrations/RunsTable.d.vue.ts +61 -3
- package/dist/runtime/components/Integrations/RunsTable.vue +143 -20
- package/dist/runtime/components/Integrations/RunsTable.vue.d.ts +61 -3
- package/dist/runtime/components/Integrations/SftpAccountImportDialog.vue +10 -1
- package/dist/runtime/components/Integrations/StickyNoteView.vue +1 -1
- package/dist/runtime/components/Integrations/WorkflowCreateDialog.vue +18 -3
- package/dist/runtime/components/Integrations/WorkflowDeleteDialog.d.vue.ts +18 -0
- package/dist/runtime/components/Integrations/WorkflowDeleteDialog.vue +70 -0
- package/dist/runtime/components/Integrations/WorkflowDeleteDialog.vue.d.ts +18 -0
- package/dist/runtime/components/Integrations/WorkflowDuplicateDialog.vue +2 -1
- package/dist/runtime/components/Integrations/WorkflowEdgeView.vue +4 -4
- package/dist/runtime/components/Integrations/WorkflowEditor.vue +39 -28
- package/dist/runtime/components/Integrations/WorkflowHistoryPanel.vue +17 -6
- package/dist/runtime/components/Integrations/WorkflowNodeView.vue +17 -21
- package/dist/runtime/components/Integrations/WorkflowRunReplayPanel.vue +8 -11
- package/dist/runtime/components/Integrations/WorkflowTriggerView.vue +6 -7
- package/dist/runtime/components/Integrations/WorkflowVariablesDialog.vue +7 -7
- package/dist/runtime/components/Integrations/WorkflowsTable.vue +10 -48
- package/dist/runtime/components/Integrations/canvasSides.d.ts +48 -0
- package/dist/runtime/components/Integrations/canvasSides.js +22 -0
- package/dist/runtime/composables/useCredentialTypes.js +2 -6
- package/dist/runtime/composables/useIntegrationsAudit.js +2 -2
- package/dist/runtime/composables/useIntegrationsCredentials.js +4 -8
- package/dist/runtime/composables/useIntegrationsDeadLetters.d.ts +4 -0
- package/dist/runtime/composables/useIntegrationsDeadLetters.js +16 -1
- package/dist/runtime/composables/useIntegrationsNodes.js +2 -2
- package/dist/runtime/composables/useIntegrationsRevisions.js +2 -6
- package/dist/runtime/composables/useIntegrationsRuns.d.ts +4 -15
- package/dist/runtime/composables/useIntegrationsRuns.js +49 -34
- package/dist/runtime/composables/useIntegrationsSchedules.js +2 -2
- package/dist/runtime/composables/useIntegrationsSecrets.js +2 -6
- package/dist/runtime/composables/useIntegrationsTemplates.js +2 -5
- package/dist/runtime/composables/useIntegrationsTriggers.js +2 -2
- package/dist/runtime/composables/useIntegrationsWorkflows.js +4 -7
- package/dist/runtime/composables/useNodeConfigResolve.js +2 -2
- package/dist/runtime/composables/useOAuthConnect.d.ts +42 -0
- package/dist/runtime/composables/useOAuthConnect.js +33 -0
- package/dist/runtime/data/expressionEditor.d.ts +17 -5
- package/dist/runtime/data/expressionEditor.js +11 -5
- package/dist/runtime/data/handleId.d.ts +61 -1
- package/dist/runtime/data/handleId.js +8 -1
- package/dist/runtime/data/payloadForm.js +3 -2
- package/dist/runtime/i18n/messages/de.json +30 -11
- package/dist/runtime/i18n/messages/en.json +27 -8
- package/dist/runtime/pages/integrations/audit.vue +7 -6
- package/dist/runtime/pages/integrations/credentials.vue +9 -21
- package/dist/runtime/pages/integrations/index.vue +70 -12
- package/dist/runtime/pages/integrations/runs.vue +116 -7
- package/dist/runtime/pages/integrations/secrets.vue +2 -1
- package/dist/runtime/pages/integrations/templates/[slug].vue +2 -1
- package/dist/runtime/pages/integrations/templates/index.vue +18 -15
- package/dist/runtime/pages/integrations/workflows/[id].vue +177 -28
- package/dist/runtime/types/integrations.d.ts +5 -0
- package/dist/runtime/utils/apiError.d.ts +21 -1
- package/dist/runtime/utils/apiError.js +1 -1
- package/dist/runtime/utils/clipboard.d.ts +33 -0
- package/dist/runtime/utils/clipboard.js +11 -0
- package/dist/runtime/utils/deepClone.d.ts +41 -0
- package/dist/runtime/utils/deepClone.js +3 -0
- package/dist/runtime/utils/formatDuration.d.ts +44 -0
- package/dist/runtime/utils/formatDuration.js +13 -0
- package/dist/runtime/utils/nodeDisplayName.d.ts +22 -0
- package/dist/runtime/utils/nodeDisplayName.js +6 -0
- package/dist/runtime/utils/notify.d.ts +1 -1
- package/dist/runtime/utils/runEnvelope.d.ts +31 -0
- package/dist/runtime/utils/runEnvelope.js +12 -0
- package/dist/runtime/utils/runFeedQuery.d.ts +135 -0
- package/dist/runtime/utils/runFeedQuery.js +66 -0
- package/dist/runtime/utils/runOutputs.d.ts +33 -0
- package/dist/runtime/utils/runOutputs.js +10 -0
- package/dist/runtime/utils/statusStyle.d.ts +24 -0
- package/dist/runtime/utils/statusStyle.js +1 -0
- package/dist/runtime/utils/validationFindings.d.ts +26 -3
- package/dist/runtime/utils/validationFindings.js +18 -3
- package/package.json +1 -1
|
@@ -12,11 +12,23 @@ export interface InlineNodeJSON {
|
|
|
12
12
|
export declare const EXPR_TOKEN_NODE = "exprToken";
|
|
13
13
|
/** Raw text → inline content: text nodes with one atom pill per token. */
|
|
14
14
|
export declare function textToInlineContent(text: string): InlineNodeJSON[];
|
|
15
|
-
/**
|
|
16
|
-
|
|
15
|
+
/**
|
|
16
|
+
* One paragraph per line, or one paragraph for the whole value.
|
|
17
|
+
*
|
|
18
|
+
* A field the node declared `multiline` keeps its newlines: each line becomes a
|
|
19
|
+
* paragraph, which is the only structure a TipTap doc has for one. Every other
|
|
20
|
+
* field is single-line and stays a single paragraph — the editor swallows Enter
|
|
21
|
+
* there, so nothing can create a second one from inside.
|
|
22
|
+
*/
|
|
23
|
+
type LineMode = {
|
|
24
|
+
multiline?: boolean;
|
|
25
|
+
};
|
|
26
|
+
/** Raw text → a full TipTap doc: one paragraph, or one per line when multiline. */
|
|
27
|
+
export declare function textToDoc(text: string, { multiline }?: LineMode): InlineNodeJSON;
|
|
17
28
|
/** TipTap doc JSON → raw text (pills serialize back to their `${{ … }}` token).
|
|
18
|
-
* Multiple paragraphs
|
|
19
|
-
*
|
|
20
|
-
export declare function docToText(doc: InlineNodeJSON | null | undefined): string;
|
|
29
|
+
* Multiple paragraphs are the lines of a multiline field; in a single-line
|
|
30
|
+
* field they can only have arrived by paste, and collapse to single spaces. */
|
|
31
|
+
export declare function docToText(doc: InlineNodeJSON | null | undefined, { multiline }?: LineMode): string;
|
|
21
32
|
/** True when any TEXT node still carries a complete raw token (needs re-pilling). */
|
|
22
33
|
export declare function hasRawTokenText(doc: InlineNodeJSON | null | undefined): boolean;
|
|
34
|
+
export {};
|
|
@@ -11,11 +11,17 @@ export function textToInlineContent(text) {
|
|
|
11
11
|
if (cursor < text.length) out.push({ type: "text", text: text.slice(cursor) });
|
|
12
12
|
return out;
|
|
13
13
|
}
|
|
14
|
-
export function textToDoc(text) {
|
|
15
|
-
const
|
|
16
|
-
return {
|
|
14
|
+
export function textToDoc(text, { multiline = false } = {}) {
|
|
15
|
+
const lines = multiline ? text.split("\n") : [text];
|
|
16
|
+
return {
|
|
17
|
+
type: "doc",
|
|
18
|
+
content: lines.map((line) => {
|
|
19
|
+
const content = textToInlineContent(line);
|
|
20
|
+
return content.length ? { type: "paragraph", content } : { type: "paragraph" };
|
|
21
|
+
})
|
|
22
|
+
};
|
|
17
23
|
}
|
|
18
|
-
export function docToText(doc) {
|
|
24
|
+
export function docToText(doc, { multiline = false } = {}) {
|
|
19
25
|
if (!doc) return "";
|
|
20
26
|
const inlineText = (p) => {
|
|
21
27
|
let s = "";
|
|
@@ -26,7 +32,7 @@ export function docToText(doc) {
|
|
|
26
32
|
}
|
|
27
33
|
return s;
|
|
28
34
|
};
|
|
29
|
-
return (doc.content ?? []).filter((n) => n.type === "paragraph").map(inlineText).join(" ");
|
|
35
|
+
return (doc.content ?? []).filter((n) => n.type === "paragraph").map(inlineText).join(multiline ? "\n" : " ");
|
|
30
36
|
}
|
|
31
37
|
export function hasRawTokenText(doc) {
|
|
32
38
|
if (!doc) return false;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* The shape of a canvas handle id — writing one, and reading the port name back out.
|
|
3
3
|
*
|
|
4
4
|
* Each node on the canvas renders four connection points per port, one per
|
|
5
5
|
* side, so that an edge can leave and arrive without crossing a card body. The
|
|
@@ -19,5 +19,65 @@
|
|
|
19
19
|
* how to read an id, and because that is what makes it testable: the editor is
|
|
20
20
|
* an SFC, out of reach of the unit suite, and the defect above shipped once
|
|
21
21
|
* already without anything going red.
|
|
22
|
+
*
|
|
23
|
+
* **Both directions live here, and that is PO-258.** The reader was here alone while
|
|
24
|
+
* twelve places across six components assembled an id with a template string and five
|
|
25
|
+
* of them declared the side union again — so the two halves of one contract agreed by
|
|
26
|
+
* spelling the same thing the same way rather than by construction. Nothing was wrong
|
|
27
|
+
* on screen; what it cost is that adding a fifth dot position would have had the
|
|
28
|
+
* writers produce `paid__centre` while the reader, which never heard of it, handed
|
|
29
|
+
* `paid__centre` back as a port name. That is not nullish, so the `?? 'default'` behind
|
|
30
|
+
* every call site cannot catch it, and the editor would have persisted an output no
|
|
31
|
+
* node has.
|
|
32
|
+
*
|
|
33
|
+
* **What happens elsewhere when a fifth position is added, and that is PO-396.** This
|
|
34
|
+
* module owns what a side *is*; what the canvas does with one — where the library draws
|
|
35
|
+
* it, what faces it, where along an edge it sits — lives in
|
|
36
|
+
* `components/Integrations/canvasSides.ts`, which is separate for one reason worth
|
|
37
|
+
* keeping: `Position` is Vue Flow's, and this file has no imports, so its round trip can
|
|
38
|
+
* be proved without the canvas library.
|
|
39
|
+
*
|
|
40
|
+
* Those three answers used to be ternary chains inside the components, each ending in an
|
|
41
|
+
* `else`, and two of them were written more than once: the position map in the node card
|
|
42
|
+
* and the trigger card, and the opposite-side map in the editor and in both read-only
|
|
43
|
+
* canvases — where it was called `opposite` rather than `oppositeSide`, which is why a
|
|
44
|
+
* search by name found one of the three. An `else` absorbs a new name
|
|
45
|
+
* silently — a `centre` dot drawn on the left, with `right` called its opposite — and
|
|
46
|
+
* every one of those is a plausible answer for *some* side, so nothing would look wrong.
|
|
47
|
+
* They are now `Record<Side, …>` maps: adding a name to `SIDES` below stops all three
|
|
48
|
+
* compiling until they say what it means. Still more than one edit, and none of them
|
|
49
|
+
* can be forgotten, which is the better half of the trade.
|
|
22
50
|
*/
|
|
51
|
+
/**
|
|
52
|
+
* The side suffix, anchored at the end. The four sides are a closed set, which
|
|
53
|
+
* is what lets the name in front of them be read whole: a port name is not
|
|
54
|
+
* restricted to a safe alphabet: `portsForNode` builds one with `String(v)` over
|
|
55
|
+
* the config values a person types into a switch node's cases, and a
|
|
56
|
+
* server-resolved dynamic output is named whatever the remote system calls its
|
|
57
|
+
* fields — where a double underscore is a naming convention rather than an
|
|
58
|
+
* accident. So a name may well contain `__` itself, and taking the FIRST one as
|
|
59
|
+
* the separator would hand back a truncated name that no node has a port for.
|
|
60
|
+
* Truncated is worse than empty: it is not nullish, so a caller's
|
|
61
|
+
* `?? 'default'` cannot catch it either.
|
|
62
|
+
*/
|
|
63
|
+
/** Every side a connection dot is rendered on. The closed set the parse anchors on. */
|
|
64
|
+
export declare const SIDES: readonly ["top", "right", "bottom", "left"];
|
|
65
|
+
export type Side = (typeof SIDES)[number];
|
|
23
66
|
export declare function portFromHandleId(handleId: string | null | undefined): string | null;
|
|
67
|
+
/**
|
|
68
|
+
* The id of an output dot: the port's own name, then the side.
|
|
69
|
+
*
|
|
70
|
+
* The name is passed through as it is. A port name is not restricted to a safe
|
|
71
|
+
* alphabet — `portsForNode` builds one with `String(v)` over what a person types into a
|
|
72
|
+
* switch node's cases — and sanitising it here would produce an id the reader cannot
|
|
73
|
+
* turn back into the name the blob stores.
|
|
74
|
+
*/
|
|
75
|
+
export declare function outputHandleId(port: string, side: Side): string;
|
|
76
|
+
/**
|
|
77
|
+
* The id of the single input dot on a given side.
|
|
78
|
+
*
|
|
79
|
+
* The separator sits at the front with no name before it, which is exactly what
|
|
80
|
+
* `portFromHandleId` reads as "no port": a node has one logical input, so there is no
|
|
81
|
+
* name to carry. A group frame's input is this on the top side.
|
|
82
|
+
*/
|
|
83
|
+
export declare function inputHandleId(side: Side): string;
|
|
@@ -1,6 +1,13 @@
|
|
|
1
|
-
const
|
|
1
|
+
export const SIDES = ["top", "right", "bottom", "left"];
|
|
2
|
+
const SIDE_SUFFIX = new RegExp(`__(?:${SIDES.join("|")})$`);
|
|
2
3
|
export function portFromHandleId(handleId) {
|
|
3
4
|
if (!handleId) return null;
|
|
4
5
|
const name = handleId.replace(SIDE_SUFFIX, "");
|
|
5
6
|
return name.startsWith("__") || !name ? null : name;
|
|
6
7
|
}
|
|
8
|
+
export function outputHandleId(port, side) {
|
|
9
|
+
return `${port}__${side}`;
|
|
10
|
+
}
|
|
11
|
+
export function inputHandleId(side) {
|
|
12
|
+
return `__in__${side}`;
|
|
13
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useIntegrationsT } from "../composables/useIntegrationsT.js";
|
|
2
|
+
import { deepClone } from "../utils/deepClone.js";
|
|
2
3
|
const PAYLOAD_REF_RE = /\$\{\{\s*trigger\.payload\.([a-zA-Z0-9_.-]+)/g;
|
|
3
4
|
const FILE_KEYS = /* @__PURE__ */ new Set(["data", "filename", "contentType", "size"]);
|
|
4
5
|
function collectRefs(value, out) {
|
|
@@ -91,7 +92,7 @@ export function getPath(source, path) {
|
|
|
91
92
|
return cursor;
|
|
92
93
|
}
|
|
93
94
|
export function buildPayload(fields, textValues, files, extras) {
|
|
94
|
-
const payload =
|
|
95
|
+
const payload = deepClone(extras ?? {});
|
|
95
96
|
for (const field of fields) {
|
|
96
97
|
if (field.kind === "file") {
|
|
97
98
|
const file = files[field.path];
|
|
@@ -111,7 +112,7 @@ export function buildPayload(fields, textValues, files, extras) {
|
|
|
111
112
|
return payload;
|
|
112
113
|
}
|
|
113
114
|
export function splitPayload(fields, payload) {
|
|
114
|
-
const extras =
|
|
115
|
+
const extras = deepClone(payload ?? {});
|
|
115
116
|
const textValues = {};
|
|
116
117
|
const files = {};
|
|
117
118
|
const deleteAt = (path) => {
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
"integration.audit.table.column.actor": "Akteur",
|
|
29
29
|
"integration.audit.table.column.resource": "Ressource",
|
|
30
30
|
"integration.audit.table.column.when": "Wann",
|
|
31
|
+
"integration.audit.toast.copyFailed": "Kopieren fehlgeschlagen",
|
|
31
32
|
"integration.audit.toast.copied": "Kopiert",
|
|
32
33
|
"integration.canvas.badge.trigger": "Trigger",
|
|
33
34
|
"integration.canvas.color.amber": "Bernstein",
|
|
@@ -229,6 +230,7 @@
|
|
|
229
230
|
"integration.credentials.sftpImport.empty": "Keine aktiven Plattform-SFTP-Konten. Zuerst eines unter Integration Studio → SFTP anlegen.",
|
|
230
231
|
"integration.credentials.sftpImport.error.importFailed": "Import fehlgeschlagen.",
|
|
231
232
|
"integration.credentials.sftpImport.error.readPassword": "Das Kontopasswort konnte nicht gelesen werden.",
|
|
233
|
+
"integration.credentials.sftpImport.state.loading": "SFTP-Konten werden geladen…",
|
|
232
234
|
"integration.credentials.sftpImport.title": "Plattform-SFTP-Konto importieren",
|
|
233
235
|
"integration.credentials.shared.action.testConnection": "Verbindung testen",
|
|
234
236
|
"integration.credentials.shared.authKind.apiKey": "API-Key",
|
|
@@ -263,6 +265,7 @@
|
|
|
263
265
|
"integration.dashboard.attention.healthy": "Alle Workflows in Ordnung.",
|
|
264
266
|
"integration.dashboard.attention.missedRuns": "{n} verpasster Run | {n} verpasste Runs",
|
|
265
267
|
"integration.dashboard.attention.missedRuns.hint": "Trigger haben ausgelöst, während ihr Workflow nicht laufen konnte — prüfen und erneut ausführen.",
|
|
268
|
+
"integration.dashboard.attention.state.loading": "Es wird geprüft, was Aufmerksamkeit erfordert…",
|
|
266
269
|
"integration.dashboard.attention.title": "Erfordert Aufmerksamkeit",
|
|
267
270
|
"integration.dashboard.head.title": "Dashboard · Integration Studio",
|
|
268
271
|
"integration.dashboard.header.description": "Alles, was die Revenue Cloud mit der Außenwelt verbindet.",
|
|
@@ -276,7 +279,9 @@
|
|
|
276
279
|
"integration.dashboard.kpi.runningNow.sub": "laufende Runs",
|
|
277
280
|
"integration.dashboard.kpi.scheduled.label": "Geplant",
|
|
278
281
|
"integration.dashboard.kpi.scheduled.sub": "aktive Zeitplan-Trigger",
|
|
282
|
+
"integration.dashboard.kpi.state.loading": "Kennzahlen werden geladen…",
|
|
279
283
|
"integration.dashboard.runs.empty": "Noch keine Runs.",
|
|
284
|
+
"integration.dashboard.runs.state.loading": "Letzte Runs werden geladen…",
|
|
280
285
|
"integration.dashboard.runs.title": "Letzte Runs",
|
|
281
286
|
"integration.dashboard.surface.events.hint": "Live-Events der Plattform, die Workflows abonnieren.",
|
|
282
287
|
"integration.dashboard.surface.events.label": "Event-Stream",
|
|
@@ -288,6 +293,7 @@
|
|
|
288
293
|
"integration.dashboard.surface.webhooks.hint": "Eingehende HTTP-Endpoints, die Workflows auslösen.",
|
|
289
294
|
"integration.dashboard.surface.webhooks.label": "Webhooks",
|
|
290
295
|
"integration.dashboard.templates.empty": "Noch keine Vorlagen registriert.",
|
|
296
|
+
"integration.dashboard.templates.state.loading": "Vorlagen werden geladen…",
|
|
291
297
|
"integration.dashboard.templates.title": "Mit einer Vorlage starten",
|
|
292
298
|
"integration.deadLetters.action.discard": "Verwerfen",
|
|
293
299
|
"integration.deadLetters.action.replay": "Wiederholen",
|
|
@@ -300,6 +306,7 @@
|
|
|
300
306
|
"integration.deadLetters.panel.title": "Verpasste Runs",
|
|
301
307
|
"integration.deadLetters.reason.fallback": "Kein Grund erfasst.",
|
|
302
308
|
"integration.deadLetters.state.empty": "Keine verpassten Runs. Jeder Trigger hat einen Run ausgelöst.",
|
|
309
|
+
"integration.deadLetters.state.loading": "Verpasste Runs werden geladen…",
|
|
303
310
|
"integration.deadLetters.status.discarded": "verworfen",
|
|
304
311
|
"integration.deadLetters.status.pending": "wartet",
|
|
305
312
|
"integration.deadLetters.status.replayed": "wiederholt",
|
|
@@ -317,7 +324,8 @@
|
|
|
317
324
|
"integration.editor.action.discard.label": "Verwerfen",
|
|
318
325
|
"integration.editor.action.discard.title": "Nicht gespeicherte Änderungen verwerfen",
|
|
319
326
|
"integration.editor.action.duplicate.label": "Duplizieren",
|
|
320
|
-
"integration.editor.action.
|
|
327
|
+
"integration.editor.action.more.aria": "Weitere Aktionen für diesen Workflow",
|
|
328
|
+
"integration.editor.action.more.label": "Aktionen",
|
|
321
329
|
"integration.editor.action.pause.title": "Workflow pausieren",
|
|
322
330
|
"integration.editor.action.retry": "Erneut versuchen",
|
|
323
331
|
"integration.editor.action.save.label": "Speichern",
|
|
@@ -433,6 +441,7 @@
|
|
|
433
441
|
"integration.editor.tab.editor": "Editor",
|
|
434
442
|
"integration.editor.tab.history": "Verlauf",
|
|
435
443
|
"integration.editor.tab.runs": "Runs",
|
|
444
|
+
"integration.editor.toast.deleted": "„{name}“ gelöscht",
|
|
436
445
|
"integration.editor.toast.duplicated": "Dupliziert als „{name}“",
|
|
437
446
|
"integration.editor.tool.addGroup.label": "Gruppe",
|
|
438
447
|
"integration.editor.tool.addGroup.tooltip": "Gruppenrahmen hinzufügen — hineingezogene Nodes treten ihr bei",
|
|
@@ -472,6 +481,7 @@
|
|
|
472
481
|
"integration.history.preview.title.current": "Aktuelle Version · Revision {revision}",
|
|
473
482
|
"integration.history.preview.title.revision": "Revision {revision} (schreibgeschützt)",
|
|
474
483
|
"integration.history.state.empty": "Noch keine archivierten Revisionen — speichern Sie eine Änderung, um die erste Momentaufnahme zu erstellen.",
|
|
484
|
+
"integration.history.state.loading": "Versionsverlauf wird geladen…",
|
|
475
485
|
"integration.history.toast.loadRevisionFailed": "Die Revision konnte nicht geladen werden.",
|
|
476
486
|
"integration.history.toast.restoreFailed": "Die Revision konnte nicht wiederhergestellt werden.",
|
|
477
487
|
"integration.history.toast.restored": "Revision {revision} wiederhergestellt",
|
|
@@ -520,6 +530,7 @@
|
|
|
520
530
|
"integration.nodeConfig.dynamicSchema.resolving": "Felder werden geladen…",
|
|
521
531
|
"integration.nodeConfig.expression.badge.title": "Akzeptiert ${{ … }}-Ausdrücke",
|
|
522
532
|
"integration.nodeConfig.expression.insertTitle": "Ausdruck einfügen",
|
|
533
|
+
"integration.nodeConfig.expression.insertAria": "Ausdruck einfügen — verfügbare Daten für diese Einstellung",
|
|
523
534
|
"integration.nodeConfig.expression.picker.aria": "Verfügbare Daten für diese Einstellung",
|
|
524
535
|
"integration.nodeConfig.expression.picker.empty": "Nichts entspricht „{query}“.",
|
|
525
536
|
"integration.nodeConfig.expression.picker.filterAria": "Verfügbare Daten filtern",
|
|
@@ -727,6 +738,7 @@
|
|
|
727
738
|
"integration.nodeInspector.toast.configCopyFailed": "Konfiguration konnte nicht kopiert werden",
|
|
728
739
|
"integration.nodeInspector.toast.configPasted": "Konfiguration eingefügt",
|
|
729
740
|
"integration.nodeInspector.toast.expressionCopied": "Ausdruck kopiert. Klicken Sie zuerst in ein Feld, um ihn direkt einzufügen.",
|
|
741
|
+
"integration.nodeInspector.toast.expressionCopyFailed": "Ausdruck konnte nicht kopiert werden. Klicken Sie in ein Feld, um ihn direkt einzufügen.",
|
|
730
742
|
"integration.nodeInspector.toast.rotateFailed": "Secret konnte nicht neu erzeugt werden.",
|
|
731
743
|
"integration.nodeInspector.toast.rotateNoSecret": "Der Endpoint hat kein Secret zurückgegeben.",
|
|
732
744
|
"integration.nodeInspector.toast.samplePinned": "Beispielausgabe angeheftet",
|
|
@@ -829,7 +841,7 @@
|
|
|
829
841
|
"integration.runs.action.back": "Zurück",
|
|
830
842
|
"integration.runs.action.cancel": "Run stoppen",
|
|
831
843
|
"integration.runs.action.resume": "Fortsetzen",
|
|
832
|
-
"integration.runs.action.retry": "
|
|
844
|
+
"integration.runs.action.retry": "Erneut ausführen",
|
|
833
845
|
"integration.runs.action.terminate": "Terminieren",
|
|
834
846
|
"integration.runs.confirm.cancel": "Diesen Run stoppen?",
|
|
835
847
|
"integration.runs.confirm.resume": "Diesen Run fortsetzen?",
|
|
@@ -889,9 +901,9 @@
|
|
|
889
901
|
"integration.runs.list.header.title": "Runs",
|
|
890
902
|
"integration.runs.menu.aria.actions": "Aktionen für Run #{id}",
|
|
891
903
|
"integration.runs.menu.cancel": "Run stoppen",
|
|
892
|
-
"integration.runs.menu.replay": "
|
|
904
|
+
"integration.runs.menu.replay": "Wiedergabe",
|
|
893
905
|
"integration.runs.menu.resume": "Fortsetzen",
|
|
894
|
-
"integration.runs.menu.retry": "
|
|
906
|
+
"integration.runs.menu.retry": "Erneut ausführen",
|
|
895
907
|
"integration.runs.menu.terminate": "Terminieren",
|
|
896
908
|
"integration.runs.menu.viewDetails": "Details anzeigen",
|
|
897
909
|
"integration.runs.notice.requested": "{action} angefordert.",
|
|
@@ -907,13 +919,15 @@
|
|
|
907
919
|
"integration.runs.payload.parseError": "Das JSON lässt sich nicht parsen — beheben Sie den Fehler, bevor Sie zur Formularansicht zurückwechseln.",
|
|
908
920
|
"integration.runs.response.action.viewRun": "Run ansehen",
|
|
909
921
|
"integration.runs.response.action.viewRunWithId": "Run #{id} ansehen",
|
|
910
|
-
"integration.runs.response.async.started": "Run wurde gestartet
|
|
911
|
-
"integration.runs.response.async.startedWithId": "Run #{id} wurde gestartet
|
|
912
|
-
"integration.runs.response.description.async": "
|
|
922
|
+
"integration.runs.response.async.started": "Run wurde gestartet.",
|
|
923
|
+
"integration.runs.response.async.startedWithId": "Run #{id} wurde gestartet.",
|
|
924
|
+
"integration.runs.response.description.async": "Im Hintergrund gestartet",
|
|
913
925
|
"integration.runs.response.description.sync": "Synchrones Run-Ergebnis",
|
|
914
|
-
"integration.runs.response.
|
|
926
|
+
"integration.runs.response.following": "Warten, bis der Run fertig ist…",
|
|
915
927
|
"integration.runs.response.loading.async": "Wird gestartet…",
|
|
916
928
|
"integration.runs.response.loading.sync": "Wird ausgeführt…",
|
|
929
|
+
"integration.runs.response.nothingReturned": "Der Run hat nichts zurückgegeben.",
|
|
930
|
+
"integration.runs.response.runNumber": "Run #{id}",
|
|
917
931
|
"integration.runs.response.title.async": "Run gestartet",
|
|
918
932
|
"integration.runs.response.title.sync": "Run-Antwort",
|
|
919
933
|
"integration.runs.status.cancelled": "abgebrochen",
|
|
@@ -928,6 +942,8 @@
|
|
|
928
942
|
"integration.runs.table.column.trigger": "Trigger",
|
|
929
943
|
"integration.runs.table.column.workflow": "Workflow",
|
|
930
944
|
"integration.runs.table.empty": "Noch keine Runs — starten Sie einen Workflow, um diese Ansicht zu füllen.",
|
|
945
|
+
"integration.runs.table.empty.narrowed": "Keine Runs passen zu dieser Einschränkung.",
|
|
946
|
+
"integration.runs.table.filter.all": "Alle",
|
|
931
947
|
"integration.runs.table.search.placeholder": "Runs durchsuchen…",
|
|
932
948
|
"integration.runs.tabs.runs.label": "Runs",
|
|
933
949
|
"integration.runs.toast.action.requested": "{action} angefordert",
|
|
@@ -990,6 +1006,7 @@
|
|
|
990
1006
|
"integration.secrets.error.loadFailed": "Secrets konnten nicht geladen werden.",
|
|
991
1007
|
"integration.secrets.error.valueRequired": "Der Wert ist erforderlich.",
|
|
992
1008
|
"integration.secrets.form.error.invalidKey": "Der Schlüssel muss ^[A-Z0-9_]+$ entsprechen (Großbuchstaben, Ziffern, Unterstriche).",
|
|
1009
|
+
"integration.secrets.form.error.saveFailed": "Das Secret konnte nicht gespeichert werden.",
|
|
993
1010
|
"integration.secrets.form.key.label": "Schlüssel",
|
|
994
1011
|
"integration.secrets.form.key.patternLabel": "Muster:",
|
|
995
1012
|
"integration.secrets.form.value.hide": "Wert ausblenden",
|
|
@@ -1128,7 +1145,12 @@
|
|
|
1128
1145
|
"integration.workflows.create.template.noMatch": "Keine Treffer für „{query}“.",
|
|
1129
1146
|
"integration.workflows.create.template.search.aria": "Vorlagen durchsuchen",
|
|
1130
1147
|
"integration.workflows.create.template.search.placeholder": "Vorlagen durchsuchen…",
|
|
1148
|
+
"integration.workflows.create.template.state.loading": "Vorlagen werden geladen…",
|
|
1131
1149
|
"integration.workflows.create.toast.templateError": "Der Workflow konnte nicht aus dieser Vorlage erstellt werden.",
|
|
1150
|
+
"integration.workflows.delete.action.deleting": "Wird gelöscht…",
|
|
1151
|
+
"integration.workflows.delete.dialog.description": "und der gesamte Revisionsverlauf werden endgültig gelöscht.",
|
|
1152
|
+
"integration.workflows.delete.dialog.title": "Workflow löschen?",
|
|
1153
|
+
"integration.workflows.delete.error.generic": "Der Workflow konnte nicht gelöscht werden.",
|
|
1132
1154
|
"integration.workflows.duplicate.dialog.description": "Erstellt eine pausierte Kopie von „{name}“ mit allen Triggern aus.",
|
|
1133
1155
|
"integration.workflows.duplicate.dialog.title": "Workflow duplizieren",
|
|
1134
1156
|
"integration.workflows.duplicate.error.generic": "Der Workflow konnte nicht dupliziert werden.",
|
|
@@ -1174,9 +1196,6 @@
|
|
|
1174
1196
|
"integration.workflows.table.column.status": "Status",
|
|
1175
1197
|
"integration.workflows.table.column.triggers": "Trigger",
|
|
1176
1198
|
"integration.workflows.table.column.updated": "Aktualisiert",
|
|
1177
|
-
"integration.workflows.table.deleteDialog.action.deleting": "Wird gelöscht…",
|
|
1178
|
-
"integration.workflows.table.deleteDialog.description": "und der gesamte Revisionsverlauf werden endgültig gelöscht.",
|
|
1179
|
-
"integration.workflows.table.deleteDialog.title": "Workflow löschen?",
|
|
1180
1199
|
"integration.workflows.table.group.noTags": "Keine Tags",
|
|
1181
1200
|
"integration.workflows.table.lastRun.aria.never": "{name}, letzter Run: Nie ausgeführt",
|
|
1182
1201
|
"integration.workflows.table.menu.action.activate": "Aktivieren",
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
"integration.audit.table.column.actor": "Actor",
|
|
29
29
|
"integration.audit.table.column.resource": "Resource",
|
|
30
30
|
"integration.audit.table.column.when": "When",
|
|
31
|
+
"integration.audit.toast.copyFailed": "Could not copy",
|
|
31
32
|
"integration.audit.toast.copied": "Copied",
|
|
32
33
|
"integration.canvas.badge.trigger": "Trigger",
|
|
33
34
|
"integration.canvas.color.amber": "Amber",
|
|
@@ -229,6 +230,7 @@
|
|
|
229
230
|
"integration.credentials.sftpImport.empty": "No active platform SFTP accounts. Create one under Integration Studio → SFTP first.",
|
|
230
231
|
"integration.credentials.sftpImport.error.importFailed": "Import failed.",
|
|
231
232
|
"integration.credentials.sftpImport.error.readPassword": "Could not read the account password.",
|
|
233
|
+
"integration.credentials.sftpImport.state.loading": "Loading the SFTP accounts…",
|
|
232
234
|
"integration.credentials.sftpImport.title": "Import platform SFTP account",
|
|
233
235
|
"integration.credentials.shared.action.testConnection": "Connect",
|
|
234
236
|
"integration.credentials.shared.authKind.apiKey": "API Key",
|
|
@@ -263,6 +265,7 @@
|
|
|
263
265
|
"integration.dashboard.attention.healthy": "All workflows healthy.",
|
|
264
266
|
"integration.dashboard.attention.missedRuns": "{n} missed run | {n} missed runs",
|
|
265
267
|
"integration.dashboard.attention.missedRuns.hint": "Triggers fired while their workflow couldn't run — review & replay.",
|
|
268
|
+
"integration.dashboard.attention.state.loading": "Checking what needs attention…",
|
|
266
269
|
"integration.dashboard.attention.title": "Needs attention",
|
|
267
270
|
"integration.dashboard.head.title": "Dashboard · Integration Studio",
|
|
268
271
|
"integration.dashboard.header.description": "Everything that connects Revenue Cloud to the outside world.",
|
|
@@ -276,7 +279,9 @@
|
|
|
276
279
|
"integration.dashboard.kpi.runningNow.sub": "live executions in flight",
|
|
277
280
|
"integration.dashboard.kpi.scheduled.label": "Scheduled",
|
|
278
281
|
"integration.dashboard.kpi.scheduled.sub": "scheduled triggers active",
|
|
282
|
+
"integration.dashboard.kpi.state.loading": "Loading the key figures…",
|
|
279
283
|
"integration.dashboard.runs.empty": "No runs yet.",
|
|
284
|
+
"integration.dashboard.runs.state.loading": "Loading the latest executions…",
|
|
280
285
|
"integration.dashboard.runs.title": "Latest executions",
|
|
281
286
|
"integration.dashboard.surface.events.hint": "Live platform events that workflows subscribe to.",
|
|
282
287
|
"integration.dashboard.surface.events.label": "Event Stream",
|
|
@@ -288,6 +293,7 @@
|
|
|
288
293
|
"integration.dashboard.surface.webhooks.hint": "Inbound HTTP endpoints that trigger workflows.",
|
|
289
294
|
"integration.dashboard.surface.webhooks.label": "Webhooks",
|
|
290
295
|
"integration.dashboard.templates.empty": "No templates registered yet.",
|
|
296
|
+
"integration.dashboard.templates.state.loading": "Loading templates…",
|
|
291
297
|
"integration.dashboard.templates.title": "Start from a template",
|
|
292
298
|
"integration.deadLetters.action.discard": "Discard",
|
|
293
299
|
"integration.deadLetters.action.replay": "Replay",
|
|
@@ -300,6 +306,7 @@
|
|
|
300
306
|
"integration.deadLetters.panel.title": "Missed runs",
|
|
301
307
|
"integration.deadLetters.reason.fallback": "No reason recorded.",
|
|
302
308
|
"integration.deadLetters.state.empty": "No missed runs. Every trigger firing made it into a run.",
|
|
309
|
+
"integration.deadLetters.state.loading": "Loading the missed runs…",
|
|
303
310
|
"integration.deadLetters.status.discarded": "discarded",
|
|
304
311
|
"integration.deadLetters.status.pending": "waiting",
|
|
305
312
|
"integration.deadLetters.status.replayed": "replayed",
|
|
@@ -317,7 +324,8 @@
|
|
|
317
324
|
"integration.editor.action.discard.label": "Cancel",
|
|
318
325
|
"integration.editor.action.discard.title": "Discard unsaved changes",
|
|
319
326
|
"integration.editor.action.duplicate.label": "Duplicate",
|
|
320
|
-
"integration.editor.action.
|
|
327
|
+
"integration.editor.action.more.aria": "More actions for this workflow",
|
|
328
|
+
"integration.editor.action.more.label": "Actions",
|
|
321
329
|
"integration.editor.action.pause.title": "Pause this workflow",
|
|
322
330
|
"integration.editor.action.retry": "Retry",
|
|
323
331
|
"integration.editor.action.save.label": "Save",
|
|
@@ -433,6 +441,7 @@
|
|
|
433
441
|
"integration.editor.tab.editor": "Editor",
|
|
434
442
|
"integration.editor.tab.history": "History",
|
|
435
443
|
"integration.editor.tab.runs": "Runs",
|
|
444
|
+
"integration.editor.toast.deleted": "Deleted “{name}”",
|
|
436
445
|
"integration.editor.toast.duplicated": "Duplicated as “{name}”",
|
|
437
446
|
"integration.editor.tool.addGroup.label": "Group",
|
|
438
447
|
"integration.editor.tool.addGroup.tooltip": "Add group frame — nodes dropped inside join it",
|
|
@@ -472,6 +481,7 @@
|
|
|
472
481
|
"integration.history.preview.title.current": "Current version · revision {revision}",
|
|
473
482
|
"integration.history.preview.title.revision": "Revision {revision} (read-only)",
|
|
474
483
|
"integration.history.state.empty": "No archived revisions yet — save a change to create the first snapshot.",
|
|
484
|
+
"integration.history.state.loading": "Loading the version history…",
|
|
475
485
|
"integration.history.toast.loadRevisionFailed": "Could not load the revision.",
|
|
476
486
|
"integration.history.toast.restoreFailed": "Could not restore the revision.",
|
|
477
487
|
"integration.history.toast.restored": "Revision {revision} restored",
|
|
@@ -520,6 +530,7 @@
|
|
|
520
530
|
"integration.nodeConfig.dynamicSchema.resolving": "Resolving fields…",
|
|
521
531
|
"integration.nodeConfig.expression.badge.title": "Accepts ${{ … }} expressions",
|
|
522
532
|
"integration.nodeConfig.expression.insertTitle": "Insert expression",
|
|
533
|
+
"integration.nodeConfig.expression.insertAria": "Insert expression — available data for this setting",
|
|
523
534
|
"integration.nodeConfig.expression.picker.aria": "Available data for this setting",
|
|
524
535
|
"integration.nodeConfig.expression.picker.empty": "Nothing matches “{query}”.",
|
|
525
536
|
"integration.nodeConfig.expression.picker.filterAria": "Filter available data",
|
|
@@ -727,6 +738,7 @@
|
|
|
727
738
|
"integration.nodeInspector.toast.configCopyFailed": "Could not copy config",
|
|
728
739
|
"integration.nodeInspector.toast.configPasted": "Config pasted",
|
|
729
740
|
"integration.nodeInspector.toast.expressionCopied": "Expression copied. Click into a field first to insert it directly.",
|
|
741
|
+
"integration.nodeInspector.toast.expressionCopyFailed": "Could not copy the expression. Click into a field to insert it directly.",
|
|
730
742
|
"integration.nodeInspector.toast.rotateFailed": "Could not rotate the secret.",
|
|
731
743
|
"integration.nodeInspector.toast.rotateNoSecret": "The endpoint did not return a secret.",
|
|
732
744
|
"integration.nodeInspector.toast.samplePinned": "Sample output pinned",
|
|
@@ -907,13 +919,15 @@
|
|
|
907
919
|
"integration.runs.payload.parseError": "The JSON does not parse — fix it before switching back to the form.",
|
|
908
920
|
"integration.runs.response.action.viewRun": "View run",
|
|
909
921
|
"integration.runs.response.action.viewRunWithId": "View run #{id}",
|
|
910
|
-
"integration.runs.response.async.started": "Run started
|
|
911
|
-
"integration.runs.response.async.startedWithId": "Run #{id} started
|
|
912
|
-
"integration.runs.response.description.async": "
|
|
922
|
+
"integration.runs.response.async.started": "Run started.",
|
|
923
|
+
"integration.runs.response.async.startedWithId": "Run #{id} started.",
|
|
924
|
+
"integration.runs.response.description.async": "Started in the background",
|
|
913
925
|
"integration.runs.response.description.sync": "Synchronous run result",
|
|
914
|
-
"integration.runs.response.
|
|
926
|
+
"integration.runs.response.following": "Waiting for the run to finish…",
|
|
915
927
|
"integration.runs.response.loading.async": "Starting…",
|
|
916
928
|
"integration.runs.response.loading.sync": "Running…",
|
|
929
|
+
"integration.runs.response.nothingReturned": "The run returned nothing.",
|
|
930
|
+
"integration.runs.response.runNumber": "Run #{id}",
|
|
917
931
|
"integration.runs.response.title.async": "Run started",
|
|
918
932
|
"integration.runs.response.title.sync": "Run response",
|
|
919
933
|
"integration.runs.status.cancelled": "cancelled",
|
|
@@ -928,6 +942,8 @@
|
|
|
928
942
|
"integration.runs.table.column.trigger": "Trigger",
|
|
929
943
|
"integration.runs.table.column.workflow": "Workflow",
|
|
930
944
|
"integration.runs.table.empty": "No runs yet — kick off a workflow to populate this view.",
|
|
945
|
+
"integration.runs.table.empty.narrowed": "No runs match this narrowing.",
|
|
946
|
+
"integration.runs.table.filter.all": "All",
|
|
931
947
|
"integration.runs.table.search.placeholder": "Search runs…",
|
|
932
948
|
"integration.runs.tabs.runs.label": "Runs",
|
|
933
949
|
"integration.runs.toast.action.requested": "{action} requested",
|
|
@@ -990,6 +1006,7 @@
|
|
|
990
1006
|
"integration.secrets.error.loadFailed": "Could not load secrets.",
|
|
991
1007
|
"integration.secrets.error.valueRequired": "Value is required.",
|
|
992
1008
|
"integration.secrets.form.error.invalidKey": "Key must match ^[A-Z0-9_]+$ (uppercase letters, digits, underscores).",
|
|
1009
|
+
"integration.secrets.form.error.saveFailed": "Could not save the secret.",
|
|
993
1010
|
"integration.secrets.form.key.label": "Key",
|
|
994
1011
|
"integration.secrets.form.key.patternLabel": "Pattern:",
|
|
995
1012
|
"integration.secrets.form.value.hide": "Hide value",
|
|
@@ -1128,7 +1145,12 @@
|
|
|
1128
1145
|
"integration.workflows.create.template.noMatch": "Nothing matches “{query}”.",
|
|
1129
1146
|
"integration.workflows.create.template.search.aria": "Search templates",
|
|
1130
1147
|
"integration.workflows.create.template.search.placeholder": "Search templates…",
|
|
1148
|
+
"integration.workflows.create.template.state.loading": "Loading templates…",
|
|
1131
1149
|
"integration.workflows.create.toast.templateError": "Could not create the workflow from this template.",
|
|
1150
|
+
"integration.workflows.delete.action.deleting": "Deleting…",
|
|
1151
|
+
"integration.workflows.delete.dialog.description": "and all its revision history will be permanently deleted.",
|
|
1152
|
+
"integration.workflows.delete.dialog.title": "Delete workflow?",
|
|
1153
|
+
"integration.workflows.delete.error.generic": "The workflow could not be deleted.",
|
|
1132
1154
|
"integration.workflows.duplicate.dialog.description": "Creates a paused copy of “{name}” with all triggers off.",
|
|
1133
1155
|
"integration.workflows.duplicate.dialog.title": "Duplicate workflow",
|
|
1134
1156
|
"integration.workflows.duplicate.error.generic": "Could not duplicate the workflow.",
|
|
@@ -1174,9 +1196,6 @@
|
|
|
1174
1196
|
"integration.workflows.table.column.status": "Status",
|
|
1175
1197
|
"integration.workflows.table.column.triggers": "Triggers",
|
|
1176
1198
|
"integration.workflows.table.column.updated": "Updated",
|
|
1177
|
-
"integration.workflows.table.deleteDialog.action.deleting": "Deleting…",
|
|
1178
|
-
"integration.workflows.table.deleteDialog.description": "and all its revision history will be permanently deleted.",
|
|
1179
|
-
"integration.workflows.table.deleteDialog.title": "Delete workflow?",
|
|
1180
1199
|
"integration.workflows.table.group.noTags": "No tags",
|
|
1181
1200
|
"integration.workflows.table.lastRun.aria.never": "{name} last run: Never run",
|
|
1182
1201
|
"integration.workflows.table.menu.action.activate": "Activate",
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
Play as Run
|
|
11
11
|
} from "#solar-icons";
|
|
12
12
|
import { Badge, Button } from "@revenexx/studio";
|
|
13
|
-
import {
|
|
13
|
+
import { copyToClipboard } from "../../utils/clipboard";
|
|
14
14
|
const t = useIntegrationsT();
|
|
15
15
|
useHead({ title: () => t("integration.audit.head.title") });
|
|
16
16
|
const { entries, loading, error, hasMore, load, loadMore } = useIntegrationsAudit();
|
|
@@ -76,11 +76,12 @@ const columns = computed(() => [
|
|
|
76
76
|
{ key: "when", label: t("integration.audit.table.column.when"), width: "180px", sortable: true, sortGetter: (e) => e.created_at }
|
|
77
77
|
]);
|
|
78
78
|
const selected = ref(null);
|
|
79
|
-
function copy(
|
|
80
|
-
if (
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
79
|
+
function copy(text) {
|
|
80
|
+
if (!text) return;
|
|
81
|
+
void copyToClipboard(text, {
|
|
82
|
+
copied: t("integration.audit.toast.copied"),
|
|
83
|
+
failed: t("integration.audit.toast.copyFailed")
|
|
84
|
+
});
|
|
84
85
|
}
|
|
85
86
|
const panelEl = ref(null);
|
|
86
87
|
let opener = null;
|
|
@@ -31,7 +31,7 @@ import {
|
|
|
31
31
|
SelectValue
|
|
32
32
|
} from "@revenexx/studio";
|
|
33
33
|
import { toast } from "../../utils/notify";
|
|
34
|
-
import { apiFieldErrors,
|
|
34
|
+
import { apiFieldErrors, errorReason } from "../../utils/apiError";
|
|
35
35
|
import { CREDENTIAL_STATES, credentialState, credentialStateLabel } from "../../utils/credentialState";
|
|
36
36
|
import { hasRevenexxSource } from "../../utils/revenexxCredentialSource";
|
|
37
37
|
import { resolveLocalized } from "../../utils/localize";
|
|
@@ -177,35 +177,23 @@ async function submit() {
|
|
|
177
177
|
}
|
|
178
178
|
} catch (e) {
|
|
179
179
|
fieldErrors.value = apiFieldErrors(e);
|
|
180
|
-
saveError.value =
|
|
180
|
+
saveError.value = errorReason(e, t("integration.credentials.error.save"));
|
|
181
181
|
toast.error(saveError.value);
|
|
182
182
|
} finally {
|
|
183
183
|
saving.value = false;
|
|
184
184
|
}
|
|
185
185
|
}
|
|
186
186
|
const connecting = ref(null);
|
|
187
|
+
const { open: openAuthorisation } = useOAuthConnect(async (outcome) => {
|
|
188
|
+
await load(true);
|
|
189
|
+
if (outcome === "completed") toast.success(t("integration.credentials.toast.connected"));
|
|
190
|
+
});
|
|
187
191
|
async function connect(c) {
|
|
188
192
|
connecting.value = c.id;
|
|
189
193
|
try {
|
|
190
|
-
|
|
191
|
-
const popup = window.open(authorizeUrl, "oauth-connect", "width=600,height=720");
|
|
192
|
-
const onMessage = async (ev) => {
|
|
193
|
-
if (ev.data?.type === "integrations-oauth-complete") {
|
|
194
|
-
window.removeEventListener("message", onMessage);
|
|
195
|
-
await load(true);
|
|
196
|
-
toast.success(t("integration.credentials.toast.connected"));
|
|
197
|
-
}
|
|
198
|
-
};
|
|
199
|
-
window.addEventListener("message", onMessage);
|
|
200
|
-
const poll = window.setInterval(async () => {
|
|
201
|
-
if (popup?.closed) {
|
|
202
|
-
window.clearInterval(poll);
|
|
203
|
-
window.removeEventListener("message", onMessage);
|
|
204
|
-
await load(true);
|
|
205
|
-
}
|
|
206
|
-
}, 1e3);
|
|
194
|
+
openAuthorisation(await oauthAuthorizeUrl(c.id));
|
|
207
195
|
} catch (e) {
|
|
208
|
-
toast.error(e
|
|
196
|
+
toast.error(errorReason(e, t("integration.credentials.error.oauthConnect")));
|
|
209
197
|
} finally {
|
|
210
198
|
connecting.value = null;
|
|
211
199
|
}
|
|
@@ -221,7 +209,7 @@ async function confirmDelete() {
|
|
|
221
209
|
toast.success(t("integration.credentials.toast.deleted"));
|
|
222
210
|
pendingDelete.value = null;
|
|
223
211
|
} catch (e) {
|
|
224
|
-
toast.error(e
|
|
212
|
+
toast.error(errorReason(e, t("integration.credentials.error.delete")));
|
|
225
213
|
} finally {
|
|
226
214
|
deleting.value = false;
|
|
227
215
|
}
|