@revenexx/studio-integrations 2.0.0 → 2.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 +141 -0
- package/README.md +1 -0
- 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 +28 -9
- 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 +7 -26
- package/dist/runtime/components/Integrations/StickyNoteView.vue +1 -0
- package/dist/runtime/components/Integrations/WorkflowCreateDialog.vue +10 -6
- package/dist/runtime/components/Integrations/WorkflowEditor.vue +224 -225
- 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 +42 -0
- package/dist/runtime/i18n/messages/en.json +42 -0
- 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/index.vue +5 -10
- package/dist/runtime/pages/integrations/schedules.vue +13 -1
- package/dist/runtime/pages/integrations/templates/index.vue +40 -40
- package/dist/runtime/pages/integrations/workflows/[id].vue +324 -244
- package/dist/runtime/types/integrations.d.ts +13 -0
- package/dist/runtime/utils/credentialState.d.ts +0 -7
- package/dist/runtime/utils/credentialState.js +0 -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 +8 -3
|
@@ -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") {
|
|
@@ -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",
|
|
@@ -978,6 +987,7 @@
|
|
|
978
987
|
"integration.runs.tabs.runs.label": "Runs",
|
|
979
988
|
"integration.runs.toast.action.requested": "{action} angefordert",
|
|
980
989
|
"integration.runs.toast.action.started": "Run #{id} gestartet",
|
|
990
|
+
"integration.runs.toast.cancel.confirm": "Run #{id} stoppen?",
|
|
981
991
|
"integration.runs.toast.terminate.confirm": "Run #{id} terminieren?",
|
|
982
992
|
"integration.schedules.cell.customSchedule": "Individueller Zeitplan",
|
|
983
993
|
"integration.schedules.cell.noSchedule": "Kein Zeitplan festgelegt",
|
|
@@ -1007,6 +1017,11 @@
|
|
|
1007
1017
|
"integration.schedules.head.title": "Zeitpläne · Integration Studio",
|
|
1008
1018
|
"integration.schedules.header.description": "Jeder Zeitplan-Trigger aus allen Ihren Workflows. Klicken Sie auf eine Zeile, um den Workflow zu öffnen.",
|
|
1009
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",
|
|
1010
1025
|
"integration.schedules.search.placeholder": "Nach Workflow, Zeitplan, Zeitzone suchen…",
|
|
1011
1026
|
"integration.schedules.stat.active": "aktiv",
|
|
1012
1027
|
"integration.schedules.state.empty": "Noch keine Zeitpläne. Fügen Sie einem Workflow einen Zeitplan-Trigger hinzu.",
|
|
@@ -1147,6 +1162,32 @@
|
|
|
1147
1162
|
"integration.templates.trigger.manual": "Bei Bedarf ausführen",
|
|
1148
1163
|
"integration.templates.trigger.webhook": "Webhook",
|
|
1149
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.",
|
|
1150
1191
|
"integration.workflows.action.duplicate": "Duplizieren",
|
|
1151
1192
|
"integration.workflows.create.action.submit": "Erstellen und Editor öffnen",
|
|
1152
1193
|
"integration.workflows.create.action.submitting": "Wird erstellt…",
|
|
@@ -1168,6 +1209,7 @@
|
|
|
1168
1209
|
"integration.workflows.create.field.tags.label": "Tags",
|
|
1169
1210
|
"integration.workflows.create.field.trigger.label": "Trigger",
|
|
1170
1211
|
"integration.workflows.create.tab.blank": "Leer starten",
|
|
1212
|
+
"integration.workflows.create.tab.file": "Aus Datei importieren",
|
|
1171
1213
|
"integration.workflows.create.tab.template": "Aus Vorlage starten",
|
|
1172
1214
|
"integration.workflows.create.template.backToPicker": "Zurück zu den Vorlagen",
|
|
1173
1215
|
"integration.workflows.create.template.browseAll": "Gesamten Vorlagenkatalog durchsuchen",
|
|
@@ -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",
|
|
@@ -978,6 +987,7 @@
|
|
|
978
987
|
"integration.runs.tabs.runs.label": "Runs",
|
|
979
988
|
"integration.runs.toast.action.requested": "{action} requested",
|
|
980
989
|
"integration.runs.toast.action.started": "Started run #{id}",
|
|
990
|
+
"integration.runs.toast.cancel.confirm": "Cancel run #{id}?",
|
|
981
991
|
"integration.runs.toast.terminate.confirm": "Terminate run #{id}?",
|
|
982
992
|
"integration.schedules.cell.customSchedule": "Custom schedule",
|
|
983
993
|
"integration.schedules.cell.noSchedule": "No schedule set",
|
|
@@ -1007,6 +1017,11 @@
|
|
|
1007
1017
|
"integration.schedules.head.title": "Schedules · Integration Studio",
|
|
1008
1018
|
"integration.schedules.header.description": "Every scheduled trigger across your workflows. Click a row to open the workflow.",
|
|
1009
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",
|
|
1010
1025
|
"integration.schedules.search.placeholder": "Search by workflow, schedule, timezone…",
|
|
1011
1026
|
"integration.schedules.stat.active": "active",
|
|
1012
1027
|
"integration.schedules.state.empty": "No schedules yet. Add a schedule trigger to any workflow.",
|
|
@@ -1147,6 +1162,32 @@
|
|
|
1147
1162
|
"integration.templates.trigger.manual": "Run on demand",
|
|
1148
1163
|
"integration.templates.trigger.webhook": "Webhook",
|
|
1149
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.",
|
|
1150
1191
|
"integration.workflows.action.duplicate": "Duplicate",
|
|
1151
1192
|
"integration.workflows.create.action.submit": "Create and open editor",
|
|
1152
1193
|
"integration.workflows.create.action.submitting": "Creating…",
|
|
@@ -1168,6 +1209,7 @@
|
|
|
1168
1209
|
"integration.workflows.create.field.tags.label": "Tags",
|
|
1169
1210
|
"integration.workflows.create.field.trigger.label": "Trigger",
|
|
1170
1211
|
"integration.workflows.create.tab.blank": "Start blank",
|
|
1212
|
+
"integration.workflows.create.tab.file": "Import from file",
|
|
1171
1213
|
"integration.workflows.create.tab.template": "Start from template",
|
|
1172
1214
|
"integration.workflows.create.template.backToPicker": "Back to templates",
|
|
1173
1215
|
"integration.workflows.create.template.browseAll": "Browse the full template catalogue",
|
|
@@ -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") }}
|
|
@@ -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";
|
|
@@ -190,7 +202,7 @@ const columns = computed(() => [
|
|
|
190
202
|
<span
|
|
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
|
<!--
|
|
@@ -68,47 +68,47 @@ const awaitingCatalogue = computed(() => loading.value && !templates.value.lengt
|
|
|
68
68
|
>
|
|
69
69
|
<template #tabs>
|
|
70
70
|
<div class="-mx-3 w-[calc(100%+1.5rem)] flex items-center gap-3 border-t border-black/[0.06] px-4 pt-2.5 pb-1">
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
71
|
+
<div class="flex min-w-0 flex-1 items-center gap-1.5 overflow-x-auto">
|
|
72
|
+
<button
|
|
73
|
+
type="button"
|
|
74
|
+
class="inline-flex h-7 shrink-0 items-center rounded-full border px-3 text-sm transition"
|
|
75
|
+
:class="activeCategory === 'all' ? 'border-primary/30 bg-primary/10 text-primary font-medium' : 'border-black/[0.08] text-muted-foreground hover:border-black/20'"
|
|
76
|
+
@click="activeCategory = 'all'"
|
|
77
|
+
>
|
|
78
|
+
{{ t("integration.templates.gallery.filter.all") }} <span class="opacity-70">({{ templates.length }})</span>
|
|
79
|
+
</button>
|
|
80
|
+
<button
|
|
81
|
+
v-for="cat in categories"
|
|
82
|
+
:key="cat.key"
|
|
83
|
+
type="button"
|
|
84
|
+
class="inline-flex h-7 shrink-0 items-center rounded-full border px-3 text-sm transition"
|
|
85
|
+
:class="activeCategory === cat.key ? 'border-primary/30 bg-primary/10 text-primary font-medium' : 'border-black/[0.08] text-muted-foreground hover:border-black/20'"
|
|
86
|
+
@click="activeCategory = activeCategory === cat.key ? 'all' : cat.key"
|
|
87
|
+
>
|
|
88
|
+
{{ cat.label }} <span class="opacity-70">({{ cat.count }})</span>
|
|
89
|
+
</button>
|
|
90
|
+
</div>
|
|
91
91
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
92
|
+
<Select v-model="activeLevel">
|
|
93
|
+
<SelectTrigger :aria-label="t('integration.templates.gallery.filter.levelAria')" class="h-7 data-[size=default]:h-7 min-h-0 py-0 w-36 rounded-full bg-white text-sm">
|
|
94
|
+
<SelectValue />
|
|
95
|
+
</SelectTrigger>
|
|
96
|
+
<SelectContent>
|
|
97
|
+
<SelectItem value="all">{{ t("integration.templates.gallery.filter.levelAllOption") }}</SelectItem>
|
|
98
|
+
<SelectItem v-for="opt in levelOptions" :key="opt.value" :value="opt.value">{{ opt.label }}</SelectItem>
|
|
99
|
+
</SelectContent>
|
|
100
|
+
</Select>
|
|
101
|
+
<Select v-model="sortBy">
|
|
102
|
+
<SelectTrigger :aria-label="t('integration.templates.gallery.sort.aria')" class="h-7 data-[size=default]:h-7 min-h-0 py-0 w-40 rounded-full bg-white text-sm">
|
|
103
|
+
<SelectValue />
|
|
104
|
+
</SelectTrigger>
|
|
105
|
+
<SelectContent>
|
|
106
|
+
<SelectItem v-for="opt in sortOptions" :key="opt.value" :value="opt.value">{{ opt.label }}</SelectItem>
|
|
107
|
+
</SelectContent>
|
|
108
|
+
</Select>
|
|
109
|
+
<div class="relative w-60">
|
|
110
|
+
<Search :size="12" class="absolute left-2 top-1/2 -translate-y-1/2 text-muted-foreground" />
|
|
111
|
+
<Input v-model="search" :aria-label="t('integration.templates.gallery.search.aria')" :placeholder="t('integration.templates.gallery.search.placeholder')" class="h-7 min-h-0 py-0 rounded-full pl-7 text-sm bg-white" />
|
|
112
112
|
</div>
|
|
113
113
|
</div>
|
|
114
114
|
</template>
|