@revenexx/studio-integrations 1.4.1 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +297 -0
- package/README.md +2 -1
- package/dist/module.json +1 -1
- package/dist/runtime/components/Integrations/CredentialCreateDialog.vue +6 -6
- package/dist/runtime/components/Integrations/CredentialDetailDialog.vue +134 -131
- package/dist/runtime/components/Integrations/CredentialLogo.vue +1 -1
- package/dist/runtime/components/Integrations/CredentialRevenexxSource.vue +1 -1
- package/dist/runtime/components/Integrations/CredentialTypePicker.vue +6 -6
- package/dist/runtime/components/Integrations/ExpressionInput.d.vue.ts +2 -0
- package/dist/runtime/components/Integrations/ExpressionInput.vue +90 -11
- package/dist/runtime/components/Integrations/ExpressionInput.vue.d.ts +2 -0
- package/dist/runtime/components/Integrations/GroupFrameView.vue +121 -121
- package/dist/runtime/components/Integrations/NodeConfigField.vue +20 -5
- package/dist/runtime/components/Integrations/NodeInspector.vue +44 -41
- package/dist/runtime/components/Integrations/NodePalette.vue +52 -37
- package/dist/runtime/components/Integrations/RunActionsMenu.vue +6 -5
- package/dist/runtime/components/Integrations/RunDetailPanel.d.vue.ts +7 -0
- package/dist/runtime/components/Integrations/RunDetailPanel.vue +14 -2
- package/dist/runtime/components/Integrations/RunDetailPanel.vue.d.ts +7 -0
- package/dist/runtime/components/Integrations/RunsTable.vue +72 -70
- package/dist/runtime/components/Integrations/SftpAccountImportDialog.vue +20 -6
- package/dist/runtime/components/Integrations/StickyNoteView.vue +1 -0
- package/dist/runtime/components/Integrations/WorkflowCreateDialog.vue +10 -6
- package/dist/runtime/components/Integrations/WorkflowEditor.d.vue.ts +0 -34
- package/dist/runtime/components/Integrations/WorkflowEditor.vue +226 -277
- package/dist/runtime/components/Integrations/WorkflowEditor.vue.d.ts +0 -34
- package/dist/runtime/components/Integrations/WorkflowExportDialog.d.vue.ts +6 -0
- package/dist/runtime/components/Integrations/WorkflowExportDialog.vue +71 -0
- package/dist/runtime/components/Integrations/WorkflowExportDialog.vue.d.ts +6 -0
- package/dist/runtime/components/Integrations/WorkflowImportFileStep.d.vue.ts +8 -0
- package/dist/runtime/components/Integrations/WorkflowImportFileStep.vue +95 -0
- package/dist/runtime/components/Integrations/WorkflowImportFileStep.vue.d.ts +8 -0
- package/dist/runtime/components/Integrations/WorkflowNodeView.vue +5 -4
- package/dist/runtime/components/Integrations/WorkflowRunReplayPanel.vue +0 -7
- package/dist/runtime/components/Integrations/WorkflowTriggerView.vue +2 -2
- package/dist/runtime/components/Integrations/WorkflowVariablesDialog.vue +2 -3
- package/dist/runtime/components/Integrations/WorkflowsTable.vue +14 -8
- package/dist/runtime/composables/useIntegrationsNodes.js +4 -1
- package/dist/runtime/composables/useIntegrationsWorkflows.d.ts +3 -1
- package/dist/runtime/composables/useIntegrationsWorkflows.js +5 -22
- package/dist/runtime/composables/useNow.d.ts +17 -0
- package/dist/runtime/composables/useNow.js +16 -0
- package/dist/runtime/composables/useWorkflowFile.d.ts +21 -0
- package/dist/runtime/composables/useWorkflowFile.js +63 -0
- package/dist/runtime/data/expressionEditor.d.ts +11 -1
- package/dist/runtime/data/expressionEditor.js +2 -1
- package/dist/runtime/data/nodeIcons.d.ts +14 -0
- package/dist/runtime/data/nodeIcons.js +57 -14
- package/dist/runtime/data/nodeRunData.js +1 -1
- package/dist/runtime/data/payloadForm.js +1 -1
- package/dist/runtime/i18n/messages/de.json +47 -11
- package/dist/runtime/i18n/messages/en.json +47 -11
- package/dist/runtime/pages/integrations/audit.vue +3 -3
- package/dist/runtime/pages/integrations/credentials/oauth-complete.vue +2 -2
- package/dist/runtime/pages/integrations/credentials.vue +17 -5
- package/dist/runtime/pages/integrations/index.vue +5 -10
- package/dist/runtime/pages/integrations/schedules.vue +24 -13
- package/dist/runtime/pages/integrations/templates/index.vue +40 -40
- package/dist/runtime/pages/integrations/workflows/[id].vue +324 -324
- package/dist/runtime/types/integrations.d.ts +13 -0
- package/dist/runtime/utils/cockpitSources.d.ts +68 -1
- package/dist/runtime/utils/credentialState.d.ts +15 -7
- package/dist/runtime/utils/credentialState.js +4 -12
- package/dist/runtime/utils/localize.d.ts +12 -0
- package/dist/runtime/utils/localize.js +1 -1
- package/dist/runtime/utils/paletteOrder.d.ts +29 -0
- package/dist/runtime/utils/paletteOrder.js +46 -0
- package/dist/runtime/utils/relativeTime.d.ts +29 -0
- package/dist/runtime/utils/relativeTime.js +23 -0
- package/dist/runtime/utils/runFeedQuery.d.ts +12 -6
- package/dist/runtime/utils/runFeedQuery.js +3 -18
- package/dist/runtime/utils/settingValue.d.ts +33 -0
- package/dist/runtime/utils/settingValue.js +8 -0
- package/dist/runtime/utils/statusStyle.d.ts +8 -8
- package/dist/runtime/utils/statusStyle.js +4 -1
- package/dist/runtime/utils/workflowFile.d.ts +119 -0
- package/dist/runtime/utils/workflowFile.js +192 -0
- package/package.json +10 -5
- package/dist/runtime/utils/errorPathAdvice.d.ts +0 -60
- package/dist/runtime/utils/errorPathAdvice.js +0 -19
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
import * as Lucide from "lucide-vue-next";
|
|
2
|
-
const MDI_TO_LUCIDE = {
|
|
2
|
+
export const MDI_TO_LUCIDE = {
|
|
3
|
+
"account-arrow-down-outline": "Import",
|
|
3
4
|
"account-group-outline": "Users",
|
|
5
|
+
"account-multiple-check-outline": "UserCheck",
|
|
4
6
|
"account-outline": "User",
|
|
5
7
|
"account-plus-outline": "UserPlus",
|
|
6
8
|
"alert-octagon": "OctagonAlert",
|
|
7
|
-
|
|
9
|
+
api: "Webhook",
|
|
8
10
|
"book-open-outline": "BookOpen",
|
|
11
|
+
"bookmark-outline": "Bookmark",
|
|
9
12
|
"bullseye-arrow": "Target",
|
|
10
13
|
"calendar-check-outline": "CalendarCheck",
|
|
11
14
|
"card-account-details-outline": "IdCard",
|
|
12
15
|
"cart-outline": "ShoppingCart",
|
|
13
16
|
"cart-plus": "ShoppingBasket",
|
|
17
|
+
"chart-timeline-variant": "ChartLine",
|
|
18
|
+
"checkbox-marked-circle-plus-outline": "ListTodo",
|
|
14
19
|
"circle-outline": "Circle",
|
|
15
20
|
"clock-outline": "Clock",
|
|
16
21
|
"cloud-download": "CloudDownload",
|
|
@@ -20,20 +25,30 @@ const MDI_TO_LUCIDE = {
|
|
|
20
25
|
"code-json": "Braces",
|
|
21
26
|
"code-tags": "Code",
|
|
22
27
|
"compare-horizontal": "ArrowLeftRight",
|
|
28
|
+
"content-duplicate": "Copy",
|
|
23
29
|
"currency-eur": "Euro",
|
|
24
30
|
"database-cog-outline": "Database",
|
|
25
31
|
"database-export-outline": "HardDriveUpload",
|
|
26
32
|
"database-import-outline": "HardDriveDownload",
|
|
27
|
-
"
|
|
33
|
+
"delete-clock-outline": "Trash2",
|
|
34
|
+
"delete-outline": "Trash2",
|
|
35
|
+
discord: "MessagesSquare",
|
|
36
|
+
domain: "Building2",
|
|
37
|
+
"email-open-outline": "MailOpen",
|
|
38
|
+
"email-remove-outline": "MailX",
|
|
39
|
+
"email-search-outline": "MailSearch",
|
|
28
40
|
"email-send": "Send",
|
|
41
|
+
"file-document-arrow-right": "FileOutput",
|
|
42
|
+
"file-document-outline": "FileText",
|
|
29
43
|
"file-edit-outline": "FilePen",
|
|
30
44
|
"file-export-outline": "FileOutput",
|
|
31
45
|
"file-import-outline": "FileInput",
|
|
32
46
|
"file-move-outline": "FileSymlink",
|
|
33
47
|
"file-plus": "FilePlus",
|
|
48
|
+
"file-plus-outline": "FilePlus",
|
|
34
49
|
"file-question-outline": "FileQuestion",
|
|
35
50
|
"file-remove-outline": "FileX",
|
|
36
|
-
|
|
51
|
+
filter: "Filter",
|
|
37
52
|
"find-replace": "Replace",
|
|
38
53
|
"folder-download-outline": "FolderDown",
|
|
39
54
|
"folder-plus-outline": "FolderPlus",
|
|
@@ -41,25 +56,53 @@ const MDI_TO_LUCIDE = {
|
|
|
41
56
|
"folder-upload-outline": "FolderUp",
|
|
42
57
|
"folder-zip-outline": "FolderArchive",
|
|
43
58
|
"format-list-bulleted-type": "List",
|
|
44
|
-
"
|
|
59
|
+
"format-list-checks": "ListChecks",
|
|
60
|
+
"hand-wave-outline": "Hand",
|
|
61
|
+
handshake: "Handshake",
|
|
45
62
|
"handshake-outline": "Handshake",
|
|
63
|
+
"inbox-arrow-down": "Inbox",
|
|
64
|
+
"inbox-full": "Archive",
|
|
65
|
+
"language-html5": "CodeXml",
|
|
66
|
+
"lightbulb-group-outline": "Lamp",
|
|
67
|
+
"lightbulb-on-outline": "SunMedium",
|
|
68
|
+
"lightbulb-outline": "Lightbulb",
|
|
69
|
+
"lightning-bolt-circle": "Zap",
|
|
46
70
|
"link-lock": "Link2",
|
|
47
|
-
"
|
|
71
|
+
"link-variant": "Link",
|
|
72
|
+
"lock-check": "ShieldCheck",
|
|
73
|
+
magnify: "Search",
|
|
74
|
+
"map-marker-path": "MapPin",
|
|
75
|
+
"map-marker-radius-outline": "MapPinned",
|
|
76
|
+
"message-processing": "MessageSquareMore",
|
|
77
|
+
"microsoft-teams": "Users",
|
|
78
|
+
"note-multiple-outline": "StickyNote",
|
|
79
|
+
"note-text-outline": "NotebookPen",
|
|
48
80
|
"office-building-outline": "Building",
|
|
81
|
+
"package-variant-closed-plus": "PackagePlus",
|
|
82
|
+
"package-variant-remove": "PackageX",
|
|
49
83
|
"pencil-box-outline": "SquarePen",
|
|
50
|
-
|
|
84
|
+
pipe: "Workflow",
|
|
85
|
+
"progress-clock": "Hourglass",
|
|
51
86
|
"receipt-outline": "Receipt",
|
|
52
87
|
"receipt-text-outline": "ReceiptText",
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
88
|
+
regex: "Regex",
|
|
89
|
+
repeat: "Repeat",
|
|
90
|
+
ruler: "Ruler",
|
|
91
|
+
"send-outline": "Send",
|
|
56
92
|
"source-branch": "GitBranch",
|
|
57
93
|
"tag-multiple-outline": "Tags",
|
|
58
|
-
"
|
|
59
|
-
|
|
94
|
+
"tag-plus-outline": "Tag",
|
|
95
|
+
telegram: "Send",
|
|
96
|
+
"timeline-text-outline": "Activity",
|
|
97
|
+
transfer: "ArrowRightLeft",
|
|
98
|
+
translate: "Languages",
|
|
99
|
+
"tray-arrow-up": "Upload",
|
|
100
|
+
"truck-check-outline": "PackageCheck",
|
|
101
|
+
"truck-delivery": "Truck",
|
|
60
102
|
"truck-outline": "Truck",
|
|
61
|
-
|
|
62
|
-
|
|
103
|
+
web: "Globe",
|
|
104
|
+
whatsapp: "MessageCircle",
|
|
105
|
+
xml: "CodeXml"
|
|
63
106
|
};
|
|
64
107
|
export function nodeIcon(name) {
|
|
65
108
|
if (!name) return Lucide.Box;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useIntegrationsT } from "../composables/useIntegrationsT.js";
|
|
2
2
|
import { deepClone } from "../utils/deepClone.js";
|
|
3
|
-
const PAYLOAD_REF_RE = /\$\{\{\s*trigger\.payload\.([
|
|
3
|
+
const PAYLOAD_REF_RE = /\$\{\{\s*trigger\.payload\.([\w.-]+)/g;
|
|
4
4
|
const FILE_KEYS = /* @__PURE__ */ new Set(["data", "filename", "contentType", "size"]);
|
|
5
5
|
function collectRefs(value, out) {
|
|
6
6
|
if (typeof value === "string") {
|
|
@@ -28,8 +28,8 @@
|
|
|
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",
|
|
32
31
|
"integration.audit.toast.copied": "Kopiert",
|
|
32
|
+
"integration.audit.toast.copyFailed": "Kopieren fehlgeschlagen",
|
|
33
33
|
"integration.canvas.badge.trigger": "Trigger",
|
|
34
34
|
"integration.canvas.color.amber": "Bernstein",
|
|
35
35
|
"integration.canvas.color.blue": "Blau",
|
|
@@ -81,6 +81,15 @@
|
|
|
81
81
|
"integration.canvas.node.port.resolving": "Ports",
|
|
82
82
|
"integration.canvas.palette.action.back": "Zurück",
|
|
83
83
|
"integration.canvas.palette.footer.hint": "Auf den Canvas ziehen — oder zum Einfügen klicken.",
|
|
84
|
+
"integration.canvas.palette.folder.actions": "Aktionen",
|
|
85
|
+
"integration.canvas.palette.folder.data": "Daten",
|
|
86
|
+
"integration.canvas.palette.folder.files": "Dateien",
|
|
87
|
+
"integration.canvas.palette.folder.flow": "Ablauf",
|
|
88
|
+
"integration.canvas.palette.folder.ftpSftp": "FTP / SFTP",
|
|
89
|
+
"integration.canvas.palette.folder.messaging": "Nachrichten",
|
|
90
|
+
"integration.canvas.palette.folder.misc": "Sonstiges",
|
|
91
|
+
"integration.canvas.palette.folder.textAndFormats": "Text & Formate",
|
|
92
|
+
"integration.canvas.palette.folder.web": "Web",
|
|
84
93
|
"integration.canvas.palette.group.core": "Kernfunktionen",
|
|
85
94
|
"integration.canvas.palette.group.integrations": "Integrations",
|
|
86
95
|
"integration.canvas.palette.group.triggers": "Trigger",
|
|
@@ -170,6 +179,8 @@
|
|
|
170
179
|
"integration.credentials.error.oauthConnect": "OAuth-Verbindung konnte nicht gestartet werden.",
|
|
171
180
|
"integration.credentials.error.save": "Zugangsdaten konnten nicht gespeichert werden.",
|
|
172
181
|
"integration.credentials.error.testFailed": "Verbindungstest fehlgeschlagen.",
|
|
182
|
+
"integration.credentials.list.action.connect": "Verbinden",
|
|
183
|
+
"integration.credentials.list.action.connect.aria": "{name} verbinden",
|
|
173
184
|
"integration.credentials.list.action.delete.aria": "{name} löschen",
|
|
174
185
|
"integration.credentials.list.action.new": "Zugangsdaten anlegen",
|
|
175
186
|
"integration.credentials.list.action.reconnect": "Erneut verbinden",
|
|
@@ -244,6 +255,7 @@
|
|
|
244
255
|
"integration.credentials.sftpImport.empty": "Keine aktiven Plattform-SFTP-Konten. Zuerst eines unter Integration Studio → SFTP anlegen.",
|
|
245
256
|
"integration.credentials.sftpImport.error.importFailed": "Import fehlgeschlagen.",
|
|
246
257
|
"integration.credentials.sftpImport.error.readPassword": "Das Kontopasswort konnte nicht gelesen werden.",
|
|
258
|
+
"integration.credentials.sftpImport.state.loadFailed": "Die Plattform-SFTP-Konten konnten nicht geladen werden: {message}",
|
|
247
259
|
"integration.credentials.sftpImport.state.loading": "SFTP-Konten werden geladen…",
|
|
248
260
|
"integration.credentials.sftpImport.title": "Plattform-SFTP-Konto importieren",
|
|
249
261
|
"integration.credentials.shared.action.testConnection": "Verbindung testen",
|
|
@@ -377,13 +389,6 @@
|
|
|
377
389
|
"integration.editor.dropGhost.label": "Loslassen zum Hinzufügen",
|
|
378
390
|
"integration.editor.emptyState.hint": "Ziehen Sie einen Trigger und eine Aktion aus dem Panel links.",
|
|
379
391
|
"integration.editor.emptyState.title": "Leere Arbeitsfläche",
|
|
380
|
-
"integration.editor.errorPath.action.stop": "Fehlerausgang stoppen lassen",
|
|
381
|
-
"integration.editor.errorPath.advice": "{n} Node leitet Fehler auf einen Ausgang, an dem nichts hängt — der Fehler wird dort nicht behandelt. | {n} Nodes leiten Fehler auf einen Ausgang, an dem nichts hängt — der Fehler wird dort nicht behandelt.",
|
|
382
|
-
"integration.editor.errorPath.ariaFix": "Ausgang „{port}“ von {label} auf Stop und Fehler legen",
|
|
383
|
-
"integration.editor.errorPath.ariaReveal": "{label} auf der Canvas zeigen — der Ausgang „{port}“ ist nicht verbunden",
|
|
384
|
-
"integration.editor.errorPath.message": "{label} fehlgeschlagen: ${{ nodes.{nodeId}.outputs.{port}.message }}",
|
|
385
|
-
"integration.editor.errorPath.more": "…und {n} weitere",
|
|
386
|
-
"integration.editor.errorPath.toast.added": "Stop und Fehler an {label} gehängt — noch nicht gespeichert.",
|
|
387
392
|
"integration.editor.event.toast.noneReceived": "Noch kein {topic}-Event empfangen.",
|
|
388
393
|
"integration.editor.executionMode.async.hint": "Runs werden immer in die Warteschlange gestellt; der Trigger antwortet sofort.",
|
|
389
394
|
"integration.editor.executionMode.async.label": "Nur asynchron",
|
|
@@ -982,11 +987,10 @@
|
|
|
982
987
|
"integration.runs.tabs.runs.label": "Runs",
|
|
983
988
|
"integration.runs.toast.action.requested": "{action} angefordert",
|
|
984
989
|
"integration.runs.toast.action.started": "Run #{id} gestartet",
|
|
990
|
+
"integration.runs.toast.cancel.confirm": "Run #{id} stoppen?",
|
|
985
991
|
"integration.runs.toast.terminate.confirm": "Run #{id} terminieren?",
|
|
986
|
-
"integration.schedules.cell.cronExpression.aria": "Cron-Ausdruck",
|
|
987
992
|
"integration.schedules.cell.customSchedule": "Individueller Zeitplan",
|
|
988
993
|
"integration.schedules.cell.noSchedule": "Kein Zeitplan festgelegt",
|
|
989
|
-
"integration.schedules.cell.whenItFires.aria": "Wann er ausgelöst wird",
|
|
990
994
|
"integration.schedules.cron.dailyAt": "Täglich um {time}",
|
|
991
995
|
"integration.schedules.cron.day.daily": "Täglich",
|
|
992
996
|
"integration.schedules.cron.day.weekdays": "Wochentags",
|
|
@@ -1013,6 +1017,11 @@
|
|
|
1013
1017
|
"integration.schedules.head.title": "Zeitpläne · Integration Studio",
|
|
1014
1018
|
"integration.schedules.header.description": "Jeder Zeitplan-Trigger aus allen Ihren Workflows. Klicken Sie auf eine Zeile, um den Workflow zu öffnen.",
|
|
1015
1019
|
"integration.schedules.header.title": "Zeitpläne",
|
|
1020
|
+
"integration.schedules.notFiring.invalidCron": "Zeitplan nicht lesbar",
|
|
1021
|
+
"integration.schedules.notFiring.unknownTimezone": "Unbekannte Zeitzone",
|
|
1022
|
+
"integration.schedules.notFiring.unsatisfiable": "Tritt nie ein",
|
|
1023
|
+
"integration.schedules.notFiring.workflowInactive": "Workflow inaktiv",
|
|
1024
|
+
"integration.schedules.notFiring.workflowNotReady": "Workflow nicht gebaut",
|
|
1016
1025
|
"integration.schedules.search.placeholder": "Nach Workflow, Zeitplan, Zeitzone suchen…",
|
|
1017
1026
|
"integration.schedules.stat.active": "aktiv",
|
|
1018
1027
|
"integration.schedules.state.empty": "Noch keine Zeitpläne. Fügen Sie einem Workflow einen Zeitplan-Trigger hinzu.",
|
|
@@ -1153,6 +1162,32 @@
|
|
|
1153
1162
|
"integration.templates.trigger.manual": "Bei Bedarf ausführen",
|
|
1154
1163
|
"integration.templates.trigger.webhook": "Webhook",
|
|
1155
1164
|
"integration.triggers.error.loadFailed": "Trigger konnten nicht geladen werden.",
|
|
1165
|
+
"integration.workflowFile.action.export": "Als Datei exportieren",
|
|
1166
|
+
"integration.workflowFile.action.import": "Aus Datei importieren…",
|
|
1167
|
+
"integration.workflowFile.count.both": "{nodes}, {triggers}",
|
|
1168
|
+
"integration.workflowFile.count.nodes": "{n} Node | {n} Nodes",
|
|
1169
|
+
"integration.workflowFile.count.triggers": "{n} Trigger | {n} Trigger",
|
|
1170
|
+
"integration.workflowFile.error.catalogue": "Die Schritte dieses Workflows konnten nicht nachgeschlagen werden, daher lässt er sich nicht auf Zugangsdaten prüfen. Versuchen Sie es erneut.",
|
|
1171
|
+
"integration.workflowFile.export.error": "Der Workflow konnte nicht exportiert werden.",
|
|
1172
|
+
"integration.workflowFile.export.notice.confirm": "Exportieren",
|
|
1173
|
+
"integration.workflowFile.export.notice.description": "Die Datei enthält die Einstellungen dieses Workflows und die Werte seiner Variablen. Zugangsdaten und die Werte von Secrets enthält sie nicht.",
|
|
1174
|
+
"integration.workflowFile.export.notice.title": "Workflow exportieren",
|
|
1175
|
+
"integration.workflowFile.export.toast": "„{name}“ exportiert",
|
|
1176
|
+
"integration.workflowFile.field.file": "Workflow-Datei",
|
|
1177
|
+
"integration.workflowFile.import.arrives": "Der Workflow wird pausiert erstellt, alle Trigger sind aus, und die Zugangsdaten wählen Sie danach.",
|
|
1178
|
+
"integration.workflowFile.import.error": "Aus dieser Datei konnte kein Workflow erstellt werden.",
|
|
1179
|
+
"integration.workflowFile.import.planError": "Die Datei konnte nicht für diesen Workflow vorbereitet werden. Versuchen Sie es erneut.",
|
|
1180
|
+
"integration.workflowFile.overwrite.active": "Dieser Workflow ist aktiv. Er läuft im bisherigen Stand weiter, bis ein gültiger Stand gespeichert ist.",
|
|
1181
|
+
"integration.workflowFile.overwrite.confirm": "Ersetzen",
|
|
1182
|
+
"integration.workflowFile.overwrite.description": "Alles auf dem Canvas von „{name}“ ({current}) wird durch den Inhalt der Datei ersetzt ({incoming}). Name und Beschreibung bleiben. Zugangsdaten müssen neu gewählt werden.",
|
|
1183
|
+
"integration.workflowFile.overwrite.draft": "Ihre ungespeicherten Änderungen werden verworfen.",
|
|
1184
|
+
"integration.workflowFile.overwrite.save": "Bis zum Speichern ändert sich nichts, und die vorige Version bleibt in der Historie.",
|
|
1185
|
+
"integration.workflowFile.overwrite.title": "Inhalt dieses Workflows ersetzen?",
|
|
1186
|
+
"integration.workflowFile.overwrite.toast": "Importiert. Wählen Sie die Zugangsdaten und speichern Sie dann.",
|
|
1187
|
+
"integration.workflowFile.refused.definition": "Dieser Workflow wurde für eine neuere Version der Plattform erstellt.",
|
|
1188
|
+
"integration.workflowFile.refused.kind": "Diese Datei enthält etwas anderes als einen Workflow.",
|
|
1189
|
+
"integration.workflowFile.refused.unreadable": "Diese Datei ist keine Workflow-Datei oder sie ist beschädigt.",
|
|
1190
|
+
"integration.workflowFile.refused.version": "Diese Datei wurde in einem neueren Format geschrieben, als dieses Studio lesen kann.",
|
|
1156
1191
|
"integration.workflows.action.duplicate": "Duplizieren",
|
|
1157
1192
|
"integration.workflows.create.action.submit": "Erstellen und Editor öffnen",
|
|
1158
1193
|
"integration.workflows.create.action.submitting": "Wird erstellt…",
|
|
@@ -1174,6 +1209,7 @@
|
|
|
1174
1209
|
"integration.workflows.create.field.tags.label": "Tags",
|
|
1175
1210
|
"integration.workflows.create.field.trigger.label": "Trigger",
|
|
1176
1211
|
"integration.workflows.create.tab.blank": "Leer starten",
|
|
1212
|
+
"integration.workflows.create.tab.file": "Aus Datei importieren",
|
|
1177
1213
|
"integration.workflows.create.tab.template": "Aus Vorlage starten",
|
|
1178
1214
|
"integration.workflows.create.template.backToPicker": "Zurück zu den Vorlagen",
|
|
1179
1215
|
"integration.workflows.create.template.browseAll": "Gesamten Vorlagenkatalog durchsuchen",
|
|
@@ -1229,6 +1265,7 @@
|
|
|
1229
1265
|
"integration.workflows.state.action.remove.hint": "Das Entfernen nimmt diesem Workflow den Zugriff. Die gespeicherten Einträge bleiben bestehen.",
|
|
1230
1266
|
"integration.workflows.state.dialog.description": "Was sich dieser Workflow zwischen Läufen merken darf. Er erreicht ausschließlich die hier deklarierten Namespaces — alles andere wird beim Lauf abgewiesen.",
|
|
1231
1267
|
"integration.workflows.state.dialog.title": "Zustands-Namespaces",
|
|
1268
|
+
"integration.workflows.state.empty": "Dieser Workflow merkt sich noch nichts zwischen Läufen.",
|
|
1232
1269
|
"integration.workflows.state.error.invalidName": "Kleinbuchstaben, Ziffern und . - _, beginnend mit einem Buchstaben — zum Beispiel article oder crm.customers.",
|
|
1233
1270
|
"integration.workflows.state.error.nameExists": "Dieser Workflow deklariert diesen Namespace bereits.",
|
|
1234
1271
|
"integration.workflows.state.field.newName.label": "Namespace deklarieren",
|
|
@@ -1246,7 +1283,6 @@
|
|
|
1246
1283
|
"integration.workflows.state.role.mapping.hint": "Verknüpft je eine ID auf beiden Seiten, damit ein späterer Lauf weiß, ob er anlegen oder aktualisieren muss.",
|
|
1247
1284
|
"integration.workflows.state.role.mapping.label": "Zuordnung",
|
|
1248
1285
|
"integration.workflows.state.row.aria": "Zustands-Namespace {namespace}",
|
|
1249
|
-
"integration.workflows.state.empty": "Dieser Workflow merkt sich noch nichts zwischen Läufen.",
|
|
1250
1286
|
"integration.workflows.state.visibility.private.hint": "Nur dieser Workflow liest und schreibt ihn, und er wird mit dem Workflow gelöscht.",
|
|
1251
1287
|
"integration.workflows.state.visibility.private.label": "Diesen Workflow",
|
|
1252
1288
|
"integration.workflows.state.visibility.shared.hint": "Jeder Workflow dieses Mandanten liest und schreibt diese Einträge, und der Namespace bleibt bestehen, wenn dieser Workflow gelöscht wird.",
|
|
@@ -28,8 +28,8 @@
|
|
|
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",
|
|
32
31
|
"integration.audit.toast.copied": "Copied",
|
|
32
|
+
"integration.audit.toast.copyFailed": "Could not copy",
|
|
33
33
|
"integration.canvas.badge.trigger": "Trigger",
|
|
34
34
|
"integration.canvas.color.amber": "Amber",
|
|
35
35
|
"integration.canvas.color.blue": "Blue",
|
|
@@ -81,6 +81,15 @@
|
|
|
81
81
|
"integration.canvas.node.port.resolving": "Ports",
|
|
82
82
|
"integration.canvas.palette.action.back": "Back",
|
|
83
83
|
"integration.canvas.palette.footer.hint": "Drag onto the canvas — or click to insert.",
|
|
84
|
+
"integration.canvas.palette.folder.actions": "Actions",
|
|
85
|
+
"integration.canvas.palette.folder.data": "Data",
|
|
86
|
+
"integration.canvas.palette.folder.files": "Files",
|
|
87
|
+
"integration.canvas.palette.folder.flow": "Flow",
|
|
88
|
+
"integration.canvas.palette.folder.ftpSftp": "FTP / SFTP",
|
|
89
|
+
"integration.canvas.palette.folder.messaging": "Messaging",
|
|
90
|
+
"integration.canvas.palette.folder.misc": "Other",
|
|
91
|
+
"integration.canvas.palette.folder.textAndFormats": "Text & Formats",
|
|
92
|
+
"integration.canvas.palette.folder.web": "Web",
|
|
84
93
|
"integration.canvas.palette.group.core": "Core",
|
|
85
94
|
"integration.canvas.palette.group.integrations": "Integrations",
|
|
86
95
|
"integration.canvas.palette.group.triggers": "Triggers",
|
|
@@ -170,6 +179,8 @@
|
|
|
170
179
|
"integration.credentials.error.oauthConnect": "Could not start OAuth connect.",
|
|
171
180
|
"integration.credentials.error.save": "Could not save credential.",
|
|
172
181
|
"integration.credentials.error.testFailed": "Connection test failed.",
|
|
182
|
+
"integration.credentials.list.action.connect": "Connect",
|
|
183
|
+
"integration.credentials.list.action.connect.aria": "Connect {name}",
|
|
173
184
|
"integration.credentials.list.action.delete.aria": "Delete {name}",
|
|
174
185
|
"integration.credentials.list.action.new": "New credential",
|
|
175
186
|
"integration.credentials.list.action.reconnect": "Reconnect",
|
|
@@ -244,6 +255,7 @@
|
|
|
244
255
|
"integration.credentials.sftpImport.empty": "No active platform SFTP accounts. Create one under Integration Studio → SFTP first.",
|
|
245
256
|
"integration.credentials.sftpImport.error.importFailed": "Import failed.",
|
|
246
257
|
"integration.credentials.sftpImport.error.readPassword": "Could not read the account password.",
|
|
258
|
+
"integration.credentials.sftpImport.state.loadFailed": "The platform SFTP accounts could not be loaded: {message}",
|
|
247
259
|
"integration.credentials.sftpImport.state.loading": "Loading the SFTP accounts…",
|
|
248
260
|
"integration.credentials.sftpImport.title": "Import platform SFTP account",
|
|
249
261
|
"integration.credentials.shared.action.testConnection": "Connect",
|
|
@@ -377,13 +389,6 @@
|
|
|
377
389
|
"integration.editor.dropGhost.label": "Drop to add",
|
|
378
390
|
"integration.editor.emptyState.hint": "Drag a trigger and an action from the panel on the left.",
|
|
379
391
|
"integration.editor.emptyState.title": "Empty canvas",
|
|
380
|
-
"integration.editor.errorPath.action.stop": "Stop the run on error",
|
|
381
|
-
"integration.editor.errorPath.advice": "{n} node routes failures to an output with nothing attached — nothing handles the failure there. | {n} nodes route failures to an output with nothing attached — nothing handles the failure there.",
|
|
382
|
-
"integration.editor.errorPath.ariaFix": "Route {label}'s \"{port}\" output to Stop and Error",
|
|
383
|
-
"integration.editor.errorPath.ariaReveal": "Show {label} on the canvas — its \"{port}\" output is not connected",
|
|
384
|
-
"integration.editor.errorPath.message": "{label} failed: ${{ nodes.{nodeId}.outputs.{port}.message }}",
|
|
385
|
-
"integration.editor.errorPath.more": "…and {n} more",
|
|
386
|
-
"integration.editor.errorPath.toast.added": "Stop and Error attached to {label} — not saved yet.",
|
|
387
392
|
"integration.editor.event.toast.noneReceived": "No {topic} event received yet.",
|
|
388
393
|
"integration.editor.executionMode.async.hint": "Runs are always queued; the trigger returns immediately.",
|
|
389
394
|
"integration.editor.executionMode.async.label": "Async only",
|
|
@@ -982,11 +987,10 @@
|
|
|
982
987
|
"integration.runs.tabs.runs.label": "Runs",
|
|
983
988
|
"integration.runs.toast.action.requested": "{action} requested",
|
|
984
989
|
"integration.runs.toast.action.started": "Started run #{id}",
|
|
990
|
+
"integration.runs.toast.cancel.confirm": "Cancel run #{id}?",
|
|
985
991
|
"integration.runs.toast.terminate.confirm": "Terminate run #{id}?",
|
|
986
|
-
"integration.schedules.cell.cronExpression.aria": "Cron expression",
|
|
987
992
|
"integration.schedules.cell.customSchedule": "Custom schedule",
|
|
988
993
|
"integration.schedules.cell.noSchedule": "No schedule set",
|
|
989
|
-
"integration.schedules.cell.whenItFires.aria": "When it fires",
|
|
990
994
|
"integration.schedules.cron.dailyAt": "Daily at {time}",
|
|
991
995
|
"integration.schedules.cron.day.daily": "Daily",
|
|
992
996
|
"integration.schedules.cron.day.weekdays": "Weekdays",
|
|
@@ -1013,6 +1017,11 @@
|
|
|
1013
1017
|
"integration.schedules.head.title": "Schedules · Integration Studio",
|
|
1014
1018
|
"integration.schedules.header.description": "Every scheduled trigger across your workflows. Click a row to open the workflow.",
|
|
1015
1019
|
"integration.schedules.header.title": "Schedules",
|
|
1020
|
+
"integration.schedules.notFiring.invalidCron": "Schedule cannot be read",
|
|
1021
|
+
"integration.schedules.notFiring.unknownTimezone": "Unknown timezone",
|
|
1022
|
+
"integration.schedules.notFiring.unsatisfiable": "Never comes round",
|
|
1023
|
+
"integration.schedules.notFiring.workflowInactive": "Workflow inactive",
|
|
1024
|
+
"integration.schedules.notFiring.workflowNotReady": "Workflow not built",
|
|
1016
1025
|
"integration.schedules.search.placeholder": "Search by workflow, schedule, timezone…",
|
|
1017
1026
|
"integration.schedules.stat.active": "active",
|
|
1018
1027
|
"integration.schedules.state.empty": "No schedules yet. Add a schedule trigger to any workflow.",
|
|
@@ -1153,6 +1162,32 @@
|
|
|
1153
1162
|
"integration.templates.trigger.manual": "Run on demand",
|
|
1154
1163
|
"integration.templates.trigger.webhook": "Webhook",
|
|
1155
1164
|
"integration.triggers.error.loadFailed": "Could not load triggers.",
|
|
1165
|
+
"integration.workflowFile.action.export": "Export as file",
|
|
1166
|
+
"integration.workflowFile.action.import": "Import from file…",
|
|
1167
|
+
"integration.workflowFile.count.both": "{nodes}, {triggers}",
|
|
1168
|
+
"integration.workflowFile.count.nodes": "{n} node | {n} nodes",
|
|
1169
|
+
"integration.workflowFile.count.triggers": "{n} trigger | {n} triggers",
|
|
1170
|
+
"integration.workflowFile.error.catalogue": "The steps this workflow uses could not be looked up, so it cannot be checked for credentials. Try again.",
|
|
1171
|
+
"integration.workflowFile.export.error": "Could not export the workflow.",
|
|
1172
|
+
"integration.workflowFile.export.notice.confirm": "Export",
|
|
1173
|
+
"integration.workflowFile.export.notice.description": "The file contains this workflow’s settings and the values of its variables. It contains no credentials and no secret values.",
|
|
1174
|
+
"integration.workflowFile.export.notice.title": "Export workflow",
|
|
1175
|
+
"integration.workflowFile.export.toast": "Exported “{name}”",
|
|
1176
|
+
"integration.workflowFile.field.file": "Workflow file",
|
|
1177
|
+
"integration.workflowFile.import.arrives": "Created paused, with every trigger off and the credentials still to choose.",
|
|
1178
|
+
"integration.workflowFile.import.error": "Could not create a workflow from this file.",
|
|
1179
|
+
"integration.workflowFile.import.planError": "The file could not be prepared for this workflow. Try again.",
|
|
1180
|
+
"integration.workflowFile.overwrite.active": "This workflow is active. It keeps running as it is until a valid version is saved.",
|
|
1181
|
+
"integration.workflowFile.overwrite.confirm": "Replace",
|
|
1182
|
+
"integration.workflowFile.overwrite.description": "Everything on the canvas of “{name}” ({current}) is replaced by the file’s content ({incoming}). The name and the description stay. Credentials have to be chosen again.",
|
|
1183
|
+
"integration.workflowFile.overwrite.draft": "Your unsaved changes are discarded.",
|
|
1184
|
+
"integration.workflowFile.overwrite.save": "Nothing changes until you save, and the previous version stays in the history.",
|
|
1185
|
+
"integration.workflowFile.overwrite.title": "Replace this workflow’s content?",
|
|
1186
|
+
"integration.workflowFile.overwrite.toast": "Imported. Choose the credentials, then save.",
|
|
1187
|
+
"integration.workflowFile.refused.definition": "This workflow was made for a newer version of the platform.",
|
|
1188
|
+
"integration.workflowFile.refused.kind": "This file holds something other than a workflow.",
|
|
1189
|
+
"integration.workflowFile.refused.unreadable": "This file is not a workflow file, or it is damaged.",
|
|
1190
|
+
"integration.workflowFile.refused.version": "This file was written in a newer format than this studio can read.",
|
|
1156
1191
|
"integration.workflows.action.duplicate": "Duplicate",
|
|
1157
1192
|
"integration.workflows.create.action.submit": "Create and open editor",
|
|
1158
1193
|
"integration.workflows.create.action.submitting": "Creating…",
|
|
@@ -1174,6 +1209,7 @@
|
|
|
1174
1209
|
"integration.workflows.create.field.tags.label": "Tags",
|
|
1175
1210
|
"integration.workflows.create.field.trigger.label": "Trigger",
|
|
1176
1211
|
"integration.workflows.create.tab.blank": "Start blank",
|
|
1212
|
+
"integration.workflows.create.tab.file": "Import from file",
|
|
1177
1213
|
"integration.workflows.create.tab.template": "Start from template",
|
|
1178
1214
|
"integration.workflows.create.template.backToPicker": "Back to templates",
|
|
1179
1215
|
"integration.workflows.create.template.browseAll": "Browse the full template catalogue",
|
|
@@ -1229,6 +1265,7 @@
|
|
|
1229
1265
|
"integration.workflows.state.action.remove.hint": "Removing the declaration takes this workflow's access away. The stored entries stay where they are.",
|
|
1230
1266
|
"integration.workflows.state.dialog.description": "What this workflow may remember between runs. It can only reach the namespaces declared here — anything else is refused when the workflow runs.",
|
|
1231
1267
|
"integration.workflows.state.dialog.title": "State namespaces",
|
|
1268
|
+
"integration.workflows.state.empty": "This workflow remembers nothing between runs yet.",
|
|
1232
1269
|
"integration.workflows.state.error.invalidName": "Use lowercase letters, digits and . - _, starting with a letter — for example article or crm.customers.",
|
|
1233
1270
|
"integration.workflows.state.error.nameExists": "This workflow already declares that namespace.",
|
|
1234
1271
|
"integration.workflows.state.field.newName.label": "Declare a namespace",
|
|
@@ -1246,7 +1283,6 @@
|
|
|
1246
1283
|
"integration.workflows.state.role.mapping.hint": "Correlates an id on each side, so a later run knows whether to create or update.",
|
|
1247
1284
|
"integration.workflows.state.role.mapping.label": "Mapping",
|
|
1248
1285
|
"integration.workflows.state.row.aria": "State namespace {namespace}",
|
|
1249
|
-
"integration.workflows.state.empty": "This workflow remembers nothing between runs yet.",
|
|
1250
1286
|
"integration.workflows.state.visibility.private.hint": "Only this workflow reads and writes it, and it is deleted along with the workflow.",
|
|
1251
1287
|
"integration.workflows.state.visibility.private.label": "This workflow",
|
|
1252
1288
|
"integration.workflows.state.visibility.shared.hint": "Every workflow in this tenant reads and writes these entries, and the namespace stays when this workflow is deleted.",
|
|
@@ -34,9 +34,9 @@ const resourceTypeKeys = {
|
|
|
34
34
|
workflow_run: "integration.audit.resourceType.workflowRun"
|
|
35
35
|
};
|
|
36
36
|
const actionKeys = {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
create: "integration.audit.action.create",
|
|
38
|
+
update: "integration.audit.action.update",
|
|
39
|
+
delete: "integration.audit.action.delete",
|
|
40
40
|
"run.started": "integration.audit.action.runStarted",
|
|
41
41
|
"run.finished": "integration.audit.action.runFinished",
|
|
42
42
|
"run.failed": "integration.audit.action.runFailed"
|
|
@@ -16,9 +16,9 @@ onMounted(() => {
|
|
|
16
16
|
</script>
|
|
17
17
|
|
|
18
18
|
<template>
|
|
19
|
-
<!-- Own landmark and heading: this popup renders without the studio shell
|
|
20
|
-
(`layout: false`), so it would otherwise be the one page with neither. -->
|
|
21
19
|
<main class="flex min-h-screen items-center justify-center bg-white text-center">
|
|
20
|
+
<!-- Own landmark and heading: this popup renders without the studio shell
|
|
21
|
+
(`layout: false`), so it would otherwise be the one page with neither. -->
|
|
22
22
|
<div class="space-y-2">
|
|
23
23
|
<h1 class="text-sm font-medium text-foreground">
|
|
24
24
|
{{ t("integration.credentials.oauthComplete.title") }}
|
|
@@ -32,7 +32,7 @@ import {
|
|
|
32
32
|
} from "@revenexx/studio";
|
|
33
33
|
import { toast } from "../../utils/notify";
|
|
34
34
|
import { apiRefusal, errorReason } from "../../utils/apiError";
|
|
35
|
-
import { CREDENTIAL_STATES, credentialState, credentialStateLabel } from "../../utils/credentialState";
|
|
35
|
+
import { CREDENTIAL_STATES, credentialState, credentialStateLabel, providerStepWord } from "../../utils/credentialState";
|
|
36
36
|
import { hasRevenexxSource } from "../../utils/revenexxCredentialSource";
|
|
37
37
|
import { resolveLocalized } from "../../utils/localize";
|
|
38
38
|
const t = useIntegrationsT();
|
|
@@ -51,6 +51,17 @@ function typeName(slug) {
|
|
|
51
51
|
function isOAuthAuthcode(t2) {
|
|
52
52
|
return t2?.auth_kind === "oauth2-authcode";
|
|
53
53
|
}
|
|
54
|
+
function providerStep(c) {
|
|
55
|
+
if (!isOAuthAuthcode(typeFor(c.credential_type_slug))) return null;
|
|
56
|
+
const state = credentialState(c).key;
|
|
57
|
+
const word = providerStepWord(state);
|
|
58
|
+
if (!word) return null;
|
|
59
|
+
return {
|
|
60
|
+
label: t(`integration.credentials.list.action.${word}`),
|
|
61
|
+
aria: t(`integration.credentials.list.action.${word}.aria`, { name: c.name }),
|
|
62
|
+
expired: state === "needs_reauth"
|
|
63
|
+
};
|
|
64
|
+
}
|
|
54
65
|
function formatDateTime(iso) {
|
|
55
66
|
if (!iso) return "\u2014";
|
|
56
67
|
try {
|
|
@@ -306,15 +317,16 @@ async function confirmDelete() {
|
|
|
306
317
|
<template #cell-actions="{ row: c }">
|
|
307
318
|
<div class="flex items-center justify-end gap-2 text-sm" @click.stop>
|
|
308
319
|
<Button
|
|
309
|
-
v-if="
|
|
320
|
+
v-if="providerStep(c)"
|
|
310
321
|
variant="outline"
|
|
311
322
|
size="sm"
|
|
312
|
-
class="h-7
|
|
323
|
+
class="h-7"
|
|
324
|
+
:class="providerStep(c).expired ? 'text-amber-600' : ''"
|
|
313
325
|
:disabled="connecting === c.id"
|
|
314
|
-
:aria-label="
|
|
326
|
+
:aria-label="providerStep(c).aria"
|
|
315
327
|
@click="connect(c)"
|
|
316
328
|
>
|
|
317
|
-
{{
|
|
329
|
+
{{ providerStep(c).label }}
|
|
318
330
|
</Button>
|
|
319
331
|
<button type="button" class="flex size-7 items-center justify-center rounded text-foreground/40 hover:text-rose-600 hover:bg-rose-500/10" :title="t('integration.credentials.list.action.delete.aria', { name: c.name })" :aria-label="t('integration.credentials.list.action.delete.aria', { name: c.name })" @click="pendingDelete = c">
|
|
320
332
|
<TrashBin :size="13" />
|
|
@@ -7,10 +7,13 @@ import WorkflowCreateDialog from "../../components/Integrations/WorkflowCreateDi
|
|
|
7
7
|
import { Pulse as Activity, DangerTriangle as AlertTriangle, ArrowRight, Box as Boxes, ClockCircle as Clock, Database, Layers, AddCircle as Plus, Radio, MagicStick as Sparkles, LinkRound as Webhook, Programming as Workflow } from "#solar-icons";
|
|
8
8
|
import { Badge, Button } from "@revenexx/studio";
|
|
9
9
|
import { formatDuration } from "../../utils/formatDuration";
|
|
10
|
+
import { relativeTime } from "../../utils/relativeTime";
|
|
11
|
+
import { useNow } from "../../composables/useNow";
|
|
10
12
|
import { servedPaths } from "../../utils/servedPaths";
|
|
11
13
|
import { RUN_STATUS_COLUMN_WIDTH, runStatusClass, runStatusLabel } from "../../utils/statusStyle";
|
|
12
14
|
const LATEST_RUN_COLUMNS = `${RUN_STATUS_COLUMN_WIDTH} minmax(0,1fr) 100px 70px`;
|
|
13
15
|
const t = useIntegrationsT();
|
|
16
|
+
const now = useNow();
|
|
14
17
|
useHead({ title: () => t("integration.dashboard.head.title") });
|
|
15
18
|
const { workflows, activeCount: activeWorkflows, loading: workflowsLoading, load: loadWorkflows } = useIntegrationsWorkflows();
|
|
16
19
|
const {
|
|
@@ -51,14 +54,6 @@ onMounted(() => {
|
|
|
51
54
|
const latestByWorkflow = computed(() => latestRunPerWorkflow.value);
|
|
52
55
|
const latestPerWorkflow = computed(() => latestByWorkflow.value.slice(0, 10));
|
|
53
56
|
const failedRecent = computed(() => latestByWorkflow.value.filter((r) => r.status === "failed").slice(0, 3));
|
|
54
|
-
function formatRelative(iso) {
|
|
55
|
-
if (!iso) return "\u2014";
|
|
56
|
-
const ms = Date.now() - new Date(iso).getTime();
|
|
57
|
-
if (ms < 6e4) return t("integration.common.time.justNow");
|
|
58
|
-
if (ms < 36e5) return t("integration.common.time.minutesAgo", Math.floor(ms / 6e4));
|
|
59
|
-
if (ms < 864e5) return t("integration.common.time.hoursAgo", Math.floor(ms / 36e5));
|
|
60
|
-
return t("integration.common.time.daysAgo", Math.floor(ms / 864e5));
|
|
61
|
-
}
|
|
62
57
|
const kpis = computed(() => [
|
|
63
58
|
{
|
|
64
59
|
key: "activeWorkflows",
|
|
@@ -226,7 +221,7 @@ function surfaceCards() {
|
|
|
226
221
|
<div class="font-mono text-xs text-muted-foreground truncate">{{ r.temporalRunId ?? "\u2014" }}</div>
|
|
227
222
|
</div>
|
|
228
223
|
<div class="text-sm text-muted-foreground tabular-nums truncate">
|
|
229
|
-
{{
|
|
224
|
+
{{ relativeTime(r.startedAt, now) }}
|
|
230
225
|
</div>
|
|
231
226
|
<!-- The ellipsis is this panel's own answer and not the formatter's em
|
|
232
227
|
dash: an entry here is the latest run of a workflow, so a missing
|
|
@@ -307,7 +302,7 @@ function surfaceCards() {
|
|
|
307
302
|
<!-- When it failed is when it ended, not when it set off: a run
|
|
308
303
|
that broke after an hour would otherwise be dated an hour early. -->
|
|
309
304
|
<div class="text-sm text-muted-foreground tabular-nums">
|
|
310
|
-
{{
|
|
305
|
+
{{ relativeTime(r.finishedAt ?? r.startedAt, now) }}
|
|
311
306
|
</div>
|
|
312
307
|
</NuxtLink>
|
|
313
308
|
</div>
|
|
@@ -32,6 +32,18 @@ function formatRelative(iso, timezone) {
|
|
|
32
32
|
}
|
|
33
33
|
return inScheduleZone(iso, timezone);
|
|
34
34
|
}
|
|
35
|
+
const notFiringKeys = {
|
|
36
|
+
workflow_inactive: "integration.schedules.notFiring.workflowInactive",
|
|
37
|
+
workflow_not_ready: "integration.schedules.notFiring.workflowNotReady",
|
|
38
|
+
invalid_cron: "integration.schedules.notFiring.invalidCron",
|
|
39
|
+
unknown_timezone: "integration.schedules.notFiring.unknownTimezone",
|
|
40
|
+
unsatisfiable: "integration.schedules.notFiring.unsatisfiable"
|
|
41
|
+
};
|
|
42
|
+
function nextRunText(e) {
|
|
43
|
+
if (e.nextRunAt) return formatRelative(e.nextRunAt, e.timezone);
|
|
44
|
+
const key = e.notFiringReason ? notFiringKeys[e.notFiringReason] : void 0;
|
|
45
|
+
return key ? t(key) : "\u2014";
|
|
46
|
+
}
|
|
35
47
|
function lastRunText(e) {
|
|
36
48
|
if (e.lastRunAt) return formatRelative(e.lastRunAt, e.timezone);
|
|
37
49
|
return e.lastRunStatus ? runStatusLabel(e.lastRunStatus) : "\u2014";
|
|
@@ -147,16 +159,16 @@ const columns = computed(() => [
|
|
|
147
159
|
at several named times is a long sentence, and half of one is
|
|
148
160
|
the wrong half. Its title is the expression, so there is no
|
|
149
161
|
tooltip left to carry the rest of the words. -->
|
|
150
|
-
<div v-if="describeCron(e.cron)" :
|
|
162
|
+
<div v-if="describeCron(e.cron)" :title="e.cron ?? void 0" class="text-sm leading-snug">
|
|
151
163
|
{{ describeCron(e.cron) }}
|
|
152
164
|
</div>
|
|
153
165
|
<template v-else-if="e.cron">
|
|
154
|
-
<div
|
|
166
|
+
<div class="text-sm truncate">
|
|
155
167
|
{{ t("integration.schedules.cell.customSchedule") }}
|
|
156
168
|
</div>
|
|
157
|
-
<code
|
|
169
|
+
<code class="block font-mono text-xs text-muted-foreground truncate">{{ e.cron }}</code>
|
|
158
170
|
</template>
|
|
159
|
-
<div v-else
|
|
171
|
+
<div v-else class="text-sm text-muted-foreground truncate">
|
|
160
172
|
{{ t("integration.schedules.cell.noSchedule") }}
|
|
161
173
|
</div>
|
|
162
174
|
</div>
|
|
@@ -170,12 +182,13 @@ const columns = computed(() => [
|
|
|
170
182
|
</template>
|
|
171
183
|
|
|
172
184
|
<!--
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
185
|
+
Neither time cell carries a name of its own, and that is the fix rather
|
|
186
|
+
than an omission. Since studio-shared 0.3.2 the cell is a `role="cell"`
|
|
187
|
+
under a `columnheader`, so a screen reader reads "Next run, in 5h" from
|
|
188
|
+
the table itself. A name written here would be read *instead of* the
|
|
189
|
+
value — the row announced "Next run" where the time should be — so the
|
|
190
|
+
labels these cells used to carry to be addressable by a test were
|
|
191
|
+
removed with the semantics that replaced them (PO-233).
|
|
179
192
|
-->
|
|
180
193
|
<!--
|
|
181
194
|
The instant the platform holds, shown as a distance from now, with the
|
|
@@ -187,10 +200,9 @@ const columns = computed(() => [
|
|
|
187
200
|
-->
|
|
188
201
|
<template #cell-nextRun="{ row: e }">
|
|
189
202
|
<span
|
|
190
|
-
:aria-label="t('integration.schedules.table.column.nextRun')"
|
|
191
203
|
:title="e.nextRunLocal ?? void 0"
|
|
192
204
|
class="text-sm tabular-nums"
|
|
193
|
-
>{{
|
|
205
|
+
>{{ nextRunText(e) }}</span>
|
|
194
206
|
</template>
|
|
195
207
|
|
|
196
208
|
<!--
|
|
@@ -202,7 +214,6 @@ const columns = computed(() => [
|
|
|
202
214
|
-->
|
|
203
215
|
<template #cell-lastRun="{ row: e }">
|
|
204
216
|
<span
|
|
205
|
-
:aria-label="t('integration.schedules.table.column.lastRun')"
|
|
206
217
|
:title="e.lastRunAt ?? void 0"
|
|
207
218
|
class="text-sm tabular-nums text-muted-foreground"
|
|
208
219
|
>{{ lastRunText(e) }}</span>
|