@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
|
@@ -29,13 +29,13 @@ type __VLS_Props = {
|
|
|
29
29
|
};
|
|
30
30
|
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
31
31
|
update: (next: WorkflowTrigger | WorkflowNode) => any;
|
|
32
|
-
close: () => any;
|
|
33
32
|
remove: () => any;
|
|
33
|
+
close: () => any;
|
|
34
34
|
navigate: (id: string) => any;
|
|
35
35
|
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
36
36
|
onUpdate?: ((next: WorkflowTrigger | WorkflowNode) => any) | undefined;
|
|
37
|
-
onClose?: (() => any) | undefined;
|
|
38
37
|
onRemove?: (() => any) | undefined;
|
|
38
|
+
onClose?: (() => any) | undefined;
|
|
39
39
|
onNavigate?: ((id: string) => any) | undefined;
|
|
40
40
|
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
41
41
|
export default _default;
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
DropdownMenuTrigger
|
|
11
11
|
} from "@revenexx/studio";
|
|
12
12
|
import { toast } from "vue-sonner";
|
|
13
|
+
import { errorReason } from "../../utils/apiError";
|
|
13
14
|
const props = defineProps({
|
|
14
15
|
run: { type: Object, required: true }
|
|
15
16
|
});
|
|
@@ -23,9 +24,10 @@ function viewDetails() {
|
|
|
23
24
|
function viewReplay() {
|
|
24
25
|
void router.push({ path: `/integrations/workflows/${props.run.workflowId}`, query: { run: props.run.id, view: "replay" } });
|
|
25
26
|
}
|
|
26
|
-
const
|
|
27
|
+
const hasExecution = computed(() => !!props.run.temporalRunId);
|
|
28
|
+
const isActive = computed(() => (props.run.status === "running" || props.run.status === "queued") && hasExecution.value);
|
|
27
29
|
const isTerminal = computed(() => ["succeeded", "failed", "cancelled"].includes(props.run.status));
|
|
28
|
-
const canResume = computed(() => props.run.status === "failed");
|
|
30
|
+
const canResume = computed(() => props.run.status === "failed" && hasExecution.value);
|
|
29
31
|
const hasAny = computed(() => isActive.value || isTerminal.value);
|
|
30
32
|
const busy = ref(false);
|
|
31
33
|
function actionLabel(a) {
|
|
@@ -77,7 +79,7 @@ async function runAction(a) {
|
|
|
77
79
|
);
|
|
78
80
|
emit("changed");
|
|
79
81
|
} catch (e) {
|
|
80
|
-
toast.error(e
|
|
82
|
+
toast.error(errorReason(e, actionErrorFallback(a)));
|
|
81
83
|
} finally {
|
|
82
84
|
busy.value = false;
|
|
83
85
|
}
|
|
@@ -3,8 +3,10 @@ import { computed, onUnmounted, ref, watch } from "vue";
|
|
|
3
3
|
import { Download as DownloadIcon, RefreshCircle as RefreshIcon } from "#solar-icons";
|
|
4
4
|
import { Badge, Button, Dialog, DialogContent, DialogHeader, DialogTitle } from "@revenexx/studio";
|
|
5
5
|
import { runStatusClass, runStatusLabel } from "../../utils/statusStyle";
|
|
6
|
-
import { IntegrationsApiError } from "../../utils/apiError";
|
|
6
|
+
import { IntegrationsApiError, errorReason } from "../../utils/apiError";
|
|
7
7
|
import { createPollBudget, SAFETY_POLL_MS } from "../../utils/pollBudget";
|
|
8
|
+
import { formatDuration } from "../../utils/formatDuration";
|
|
9
|
+
import { unwrapRun } from "../../utils/runEnvelope";
|
|
8
10
|
const props = defineProps({
|
|
9
11
|
run: { type: Object, required: true },
|
|
10
12
|
view: { type: String, required: false, default: "details" }
|
|
@@ -59,14 +61,6 @@ function pickStr(obj, keys) {
|
|
|
59
61
|
const v = pick(obj, keys);
|
|
60
62
|
return v == null ? null : String(v);
|
|
61
63
|
}
|
|
62
|
-
function unwrapRun(res) {
|
|
63
|
-
if (!res || typeof res !== "object") return null;
|
|
64
|
-
const o = res;
|
|
65
|
-
if ("data" in o && o.data && typeof o.data === "object" && !("status" in o) && !("temporal_run_id" in o)) {
|
|
66
|
-
return o.data;
|
|
67
|
-
}
|
|
68
|
-
return o;
|
|
69
|
-
}
|
|
70
64
|
function isNonEmptyObject(v) {
|
|
71
65
|
return !!v && typeof v === "object" && !Array.isArray(v) && Object.keys(v).length > 0;
|
|
72
66
|
}
|
|
@@ -141,8 +135,7 @@ function statusOf(e) {
|
|
|
141
135
|
return e instanceof IntegrationsApiError ? e.status : null;
|
|
142
136
|
}
|
|
143
137
|
function genericMsg(e, fallback) {
|
|
144
|
-
|
|
145
|
-
return e?.message ?? fallback;
|
|
138
|
+
return errorReason(e, fallback);
|
|
146
139
|
}
|
|
147
140
|
function detailsErrMsg(e) {
|
|
148
141
|
const s = statusOf(e);
|
|
@@ -170,12 +163,7 @@ function stepsErrMsg(e) {
|
|
|
170
163
|
if (s === 503) return t("integration.runs.detail.error.details.unavailable");
|
|
171
164
|
return genericMsg(e, t("integration.runs.detail.error.steps.generic"));
|
|
172
165
|
}
|
|
173
|
-
|
|
174
|
-
if (ms == null) return "\u2014";
|
|
175
|
-
if (ms < 1e3) return `${ms}ms`;
|
|
176
|
-
if (ms < 6e4) return `${(ms / 1e3).toFixed(2)}s`;
|
|
177
|
-
return `${(ms / 6e4).toFixed(1)}m`;
|
|
178
|
-
}
|
|
166
|
+
const fmtMs = formatDuration;
|
|
179
167
|
function activityName(a) {
|
|
180
168
|
const at = a ? a.activity_type ?? a.activityType : void 0;
|
|
181
169
|
if (typeof at === "string") return at;
|
|
@@ -1,18 +1,40 @@
|
|
|
1
|
+
import type { RunOutput } from '../../utils/runOutputs.js';
|
|
1
2
|
/**
|
|
2
|
-
* Result surface for a manual run, sync and async alike.
|
|
3
|
-
* in a loading state, awaits the trigger, then feeds through the outcome:
|
|
3
|
+
* Result surface for a manual run, sync and async alike.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
5
|
+
* BOTH MODES END HERE, and that is the point of the component (PO-380). The
|
|
6
|
+
* parent opens it on the press, awaits the trigger, and then feeds through
|
|
7
|
+
* whatever it learns about the run — the body a sync request waited for, or the
|
|
8
|
+
* successive states of an async run the parent follows on the author's behalf.
|
|
9
|
+
* What differs between the two is only who does the waiting; the async branch
|
|
10
|
+
* used to stop at "run #99 started", which said that the press did something and
|
|
11
|
+
* nothing about what it did.
|
|
12
|
+
*
|
|
13
|
+
* WHAT IT LEADS WITH is the other half. A run's record carries its Temporal ids,
|
|
14
|
+
* its two re-run references and four timestamps, and the author pressed Run to
|
|
15
|
+
* see none of them: `outputs` is the returned value split per node and named the
|
|
16
|
+
* way the canvas names it, `result` is that value whole for a shape that cannot
|
|
17
|
+
* be split, and the record itself is a click away rather than printed here.
|
|
10
18
|
*/
|
|
19
|
+
interface RunSummary {
|
|
20
|
+
id?: unknown;
|
|
21
|
+
status?: unknown;
|
|
22
|
+
started_at?: unknown;
|
|
23
|
+
completed_at?: unknown;
|
|
24
|
+
}
|
|
11
25
|
type __VLS_Props = {
|
|
12
26
|
open: boolean;
|
|
27
|
+
/** The trigger request is still out. */
|
|
13
28
|
loading?: boolean;
|
|
14
29
|
mode?: 'sync' | 'async';
|
|
15
|
-
|
|
30
|
+
/** The run as the platform last reported it — the identity line above the result. */
|
|
31
|
+
run?: RunSummary | null;
|
|
32
|
+
/** What the run returned, per node. `null` where the value has no such shape. */
|
|
33
|
+
outputs?: RunOutput[] | null;
|
|
34
|
+
/** …and the value whole, for when it has not. */
|
|
35
|
+
result?: unknown;
|
|
36
|
+
/** The studio is still following a run that has not ended. */
|
|
37
|
+
following?: boolean;
|
|
16
38
|
error?: string | null;
|
|
17
39
|
/** The run behind this result (sync failure / async start) for deep-linking. */
|
|
18
40
|
runId?: string | null;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
+
import { computed } from "vue";
|
|
2
3
|
import { CheckCircle as CheckCircle2, RefreshCircle as Loader2 } from "#solar-icons";
|
|
3
4
|
import {
|
|
4
5
|
Button,
|
|
@@ -8,22 +9,50 @@ import {
|
|
|
8
9
|
DialogHeader,
|
|
9
10
|
DialogTitle
|
|
10
11
|
} from "@revenexx/studio";
|
|
11
|
-
|
|
12
|
+
import { formatDuration } from "../../utils/formatDuration";
|
|
13
|
+
import { runStatusClass, runStatusLabel } from "../../utils/statusStyle";
|
|
14
|
+
import { isTerminalRun } from "../../utils/runEnvelope";
|
|
15
|
+
const props = defineProps({
|
|
12
16
|
open: { type: Boolean, required: true },
|
|
13
17
|
loading: { type: Boolean, required: false },
|
|
14
18
|
mode: { type: String, required: false },
|
|
15
|
-
|
|
19
|
+
run: { type: [Object, null], required: false },
|
|
20
|
+
outputs: { type: [Array, null], required: false },
|
|
21
|
+
result: { type: null, required: false },
|
|
22
|
+
following: { type: Boolean, required: false },
|
|
16
23
|
error: { type: [String, null], required: false },
|
|
17
24
|
runId: { type: [String, null], required: false }
|
|
18
25
|
});
|
|
19
26
|
const emit = defineEmits(["update:open", "view-run"]);
|
|
20
27
|
const t = useIntegrationsT();
|
|
28
|
+
const runNumber = computed(() => props.run?.id != null ? String(props.run.id) : props.runId);
|
|
29
|
+
const status = computed(() => props.run?.status != null ? String(props.run.status) : "");
|
|
30
|
+
const duration = computed(() => {
|
|
31
|
+
const from = props.run?.started_at;
|
|
32
|
+
const to = props.run?.completed_at;
|
|
33
|
+
if (typeof from !== "string" || typeof to !== "string") return null;
|
|
34
|
+
const ms = Date.parse(to) - Date.parse(from);
|
|
35
|
+
return Number.isFinite(ms) && ms >= 0 ? ms : null;
|
|
36
|
+
});
|
|
37
|
+
const ended = computed(() => {
|
|
38
|
+
if (props.following) return false;
|
|
39
|
+
if (props.mode !== "async") return true;
|
|
40
|
+
return isTerminalRun(props.run);
|
|
41
|
+
});
|
|
42
|
+
const returnedNothing = computed(() => props.result == null || typeof props.result === "object" && !Array.isArray(props.result) && !Object.keys(props.result).length);
|
|
43
|
+
function pretty(value) {
|
|
44
|
+
return typeof value === "string" ? value : JSON.stringify(value, null, 2);
|
|
45
|
+
}
|
|
21
46
|
</script>
|
|
22
47
|
|
|
23
48
|
<template>
|
|
24
49
|
<Dialog :open="open" @update:open="(v) => emit('update:open', v)">
|
|
25
50
|
<!-- Wide result surface — but hard-capped: min-w-0 down the tree keeps the
|
|
26
|
-
JSON <pre> scrolling INSIDE instead of blowing the dialog open.
|
|
51
|
+
JSON <pre> scrolling INSIDE instead of blowing the dialog open. The same
|
|
52
|
+
had to be said about the height, and was not: the dialog grew as tall as
|
|
53
|
+
whatever came back, `overflow-hidden` clipped what stuck out, and nothing
|
|
54
|
+
scrolled — so a result of two node outputs ran off the top and the bottom
|
|
55
|
+
of the screen at once and took the buttons below it out of reach (PO-402). -->
|
|
27
56
|
<DialogContent class="max-w-[94vw] overflow-hidden sm:max-w-4xl">
|
|
28
57
|
<DialogHeader>
|
|
29
58
|
<DialogTitle>{{ mode === "async" ? t("integration.runs.response.title.async") : t("integration.runs.response.title.sync") }}</DialogTitle>
|
|
@@ -32,7 +61,10 @@ const t = useIntegrationsT();
|
|
|
32
61
|
</DialogDescription>
|
|
33
62
|
</DialogHeader>
|
|
34
63
|
|
|
35
|
-
|
|
64
|
+
<!-- The body is what scrolls, which is how the create-workflow, node-config
|
|
65
|
+
and SFTP-import dialogs solve the same thing. Capped below the viewport so
|
|
66
|
+
the dialog's own header stays put above it. -->
|
|
67
|
+
<div class="min-w-0 max-h-[70vh] max-w-full overflow-y-auto text-sm">
|
|
36
68
|
<div v-if="loading" class="flex items-center gap-2 py-6 text-muted-foreground">
|
|
37
69
|
<Loader2 :size="16" class="animate-spin" />
|
|
38
70
|
{{ mode === "async" ? t("integration.runs.response.loading.async") : t("integration.runs.response.loading.sync") }}
|
|
@@ -49,36 +81,72 @@ const t = useIntegrationsT();
|
|
|
49
81
|
</div>
|
|
50
82
|
</template>
|
|
51
83
|
|
|
52
|
-
<template v-else
|
|
53
|
-
|
|
84
|
+
<template v-else>
|
|
85
|
+
<!-- The confirmation an async press earns: the run exists and is named,
|
|
86
|
+
whatever the studio manages to read back about it afterwards. -->
|
|
87
|
+
<div
|
|
88
|
+
v-if="mode === 'async'"
|
|
89
|
+
class="flex items-center gap-2 rounded-md border border-emerald-500/20 bg-emerald-500/5 px-3 py-2 text-emerald-700"
|
|
90
|
+
>
|
|
54
91
|
<CheckCircle2 :size="15" class="shrink-0" />
|
|
55
|
-
<span v-if="
|
|
92
|
+
<span v-if="runNumber">{{ t("integration.runs.response.async.startedWithId", { id: runNumber }) }}</span>
|
|
56
93
|
<span v-else>{{ t("integration.runs.response.async.started") }}</span>
|
|
57
94
|
</div>
|
|
58
|
-
|
|
95
|
+
|
|
96
|
+
<!-- Where the run has got to: three facts, and the rest of its record
|
|
97
|
+
stays behind the button below. -->
|
|
98
|
+
<div v-if="runNumber || status" class="mt-3 flex flex-wrap items-center gap-x-2 gap-y-1 text-muted-foreground">
|
|
99
|
+
<span v-if="runNumber" class="font-mono">{{ t("integration.runs.response.runNumber", { id: runNumber }) }}</span>
|
|
100
|
+
<span
|
|
101
|
+
v-if="status"
|
|
102
|
+
class="rounded px-1.5 py-0.5 text-xs"
|
|
103
|
+
:class="runStatusClass(status)"
|
|
104
|
+
>{{ runStatusLabel(status) }}</span>
|
|
105
|
+
<span v-if="duration != null" class="tabular-nums text-xs">{{ formatDuration(duration) }}</span>
|
|
106
|
+
</div>
|
|
107
|
+
|
|
108
|
+
<div v-if="following" class="mt-3 flex items-center gap-2 py-3 text-muted-foreground">
|
|
109
|
+
<Loader2 :size="16" class="animate-spin" />
|
|
110
|
+
{{ t("integration.runs.response.following") }}
|
|
111
|
+
</div>
|
|
112
|
+
|
|
113
|
+
<!-- What it returned, one block per node that produced something. -->
|
|
114
|
+
<div v-else-if="outputs?.length" class="mt-3 space-y-3">
|
|
115
|
+
<div v-for="out in outputs" :key="out.nodeId" class="min-w-0">
|
|
116
|
+
<p class="mb-1 font-medium text-foreground">
|
|
117
|
+
{{ out.name }}
|
|
118
|
+
</p>
|
|
119
|
+
<pre
|
|
120
|
+
class="max-h-[45vh] w-full min-w-0 max-w-full overflow-auto rounded-md border border-black/[0.06] bg-slate-50 p-3 text-xs"
|
|
121
|
+
>{{ pretty(out.value) }}</pre>
|
|
122
|
+
</div>
|
|
123
|
+
</div>
|
|
124
|
+
|
|
125
|
+
<!-- Nothing at all where the run has not ended: the studio has stopped
|
|
126
|
+
looking, which is not the same as the run having finished, and the
|
|
127
|
+
confirmation and the status line above already say where it stands. -->
|
|
128
|
+
<template v-else-if="ended">
|
|
129
|
+
<p v-if="returnedNothing" class="mt-3 py-3 text-muted-foreground">
|
|
130
|
+
{{ t("integration.runs.response.nothingReturned") }}
|
|
131
|
+
</p>
|
|
132
|
+
|
|
133
|
+
<!-- A returned value this workflow's nodes cannot account for: shown
|
|
134
|
+
whole rather than filed under a name it may not belong to. -->
|
|
135
|
+
<pre
|
|
136
|
+
v-else
|
|
137
|
+
class="mt-3 max-h-[60vh] w-full min-w-0 max-w-full overflow-auto rounded-md border border-black/[0.06] bg-slate-50 p-3 text-xs"
|
|
138
|
+
>{{ pretty(result) }}</pre>
|
|
139
|
+
</template>
|
|
140
|
+
|
|
141
|
+
<div class="mt-4 flex justify-end gap-2">
|
|
59
142
|
<Button variant="outline" class="h-8 text-sm" @click="emit('update:open', false)">
|
|
60
143
|
{{ t("integration.common.action.close") }}
|
|
61
144
|
</Button>
|
|
62
|
-
<Button v-if="
|
|
145
|
+
<Button v-if="runNumber" class="h-8 text-sm" @click="emit('view-run', String(runNumber))">
|
|
63
146
|
{{ t("integration.runs.response.action.viewRun") }}
|
|
64
147
|
</Button>
|
|
65
148
|
</div>
|
|
66
149
|
</template>
|
|
67
|
-
|
|
68
|
-
<template v-else-if="response !== void 0 && response !== null">
|
|
69
|
-
<pre
|
|
70
|
-
class="max-h-[66vh] w-full min-w-0 max-w-full overflow-auto rounded-md border border-black/[0.06] bg-slate-50 p-3 text-xs"
|
|
71
|
-
>{{ JSON.stringify(response, null, 2) }}</pre>
|
|
72
|
-
<div v-if="runId" class="mt-3 flex justify-end">
|
|
73
|
-
<Button variant="outline" class="h-8 text-sm" @click="emit('view-run', runId)">
|
|
74
|
-
{{ t("integration.runs.response.action.viewRun") }}
|
|
75
|
-
</Button>
|
|
76
|
-
</div>
|
|
77
|
-
</template>
|
|
78
|
-
|
|
79
|
-
<p v-else class="py-6 text-muted-foreground">
|
|
80
|
-
{{ t("integration.runs.response.empty") }}
|
|
81
|
-
</p>
|
|
82
150
|
</div>
|
|
83
151
|
</DialogContent>
|
|
84
152
|
</Dialog>
|
|
@@ -1,18 +1,40 @@
|
|
|
1
|
+
import type { RunOutput } from '../../utils/runOutputs.js';
|
|
1
2
|
/**
|
|
2
|
-
* Result surface for a manual run, sync and async alike.
|
|
3
|
-
* in a loading state, awaits the trigger, then feeds through the outcome:
|
|
3
|
+
* Result surface for a manual run, sync and async alike.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
5
|
+
* BOTH MODES END HERE, and that is the point of the component (PO-380). The
|
|
6
|
+
* parent opens it on the press, awaits the trigger, and then feeds through
|
|
7
|
+
* whatever it learns about the run — the body a sync request waited for, or the
|
|
8
|
+
* successive states of an async run the parent follows on the author's behalf.
|
|
9
|
+
* What differs between the two is only who does the waiting; the async branch
|
|
10
|
+
* used to stop at "run #99 started", which said that the press did something and
|
|
11
|
+
* nothing about what it did.
|
|
12
|
+
*
|
|
13
|
+
* WHAT IT LEADS WITH is the other half. A run's record carries its Temporal ids,
|
|
14
|
+
* its two re-run references and four timestamps, and the author pressed Run to
|
|
15
|
+
* see none of them: `outputs` is the returned value split per node and named the
|
|
16
|
+
* way the canvas names it, `result` is that value whole for a shape that cannot
|
|
17
|
+
* be split, and the record itself is a click away rather than printed here.
|
|
10
18
|
*/
|
|
19
|
+
interface RunSummary {
|
|
20
|
+
id?: unknown;
|
|
21
|
+
status?: unknown;
|
|
22
|
+
started_at?: unknown;
|
|
23
|
+
completed_at?: unknown;
|
|
24
|
+
}
|
|
11
25
|
type __VLS_Props = {
|
|
12
26
|
open: boolean;
|
|
27
|
+
/** The trigger request is still out. */
|
|
13
28
|
loading?: boolean;
|
|
14
29
|
mode?: 'sync' | 'async';
|
|
15
|
-
|
|
30
|
+
/** The run as the platform last reported it — the identity line above the result. */
|
|
31
|
+
run?: RunSummary | null;
|
|
32
|
+
/** What the run returned, per node. `null` where the value has no such shape. */
|
|
33
|
+
outputs?: RunOutput[] | null;
|
|
34
|
+
/** …and the value whole, for when it has not. */
|
|
35
|
+
result?: unknown;
|
|
36
|
+
/** The studio is still following a run that has not ended. */
|
|
37
|
+
following?: boolean;
|
|
16
38
|
error?: string | null;
|
|
17
39
|
/** The run behind this result (sync failure / async start) for deep-linking. */
|
|
18
40
|
runId?: string | null;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { WorkflowRun } from '../../types/integrations.js';
|
|
1
|
+
import type { RunStatus, TriggerType, WorkflowRun } from '../../types/integrations.js';
|
|
2
|
+
import type { RunSort, RunSortDirection } from '../../utils/runFeedQuery.js';
|
|
2
3
|
type __VLS_Props = {
|
|
3
4
|
runs: WorkflowRun[];
|
|
4
5
|
loading?: boolean;
|
|
@@ -7,14 +8,71 @@ type __VLS_Props = {
|
|
|
7
8
|
pagination?: boolean;
|
|
8
9
|
/** false inside a workflow — the context makes the column redundant. */
|
|
9
10
|
showWorkflow?: boolean;
|
|
11
|
+
/**
|
|
12
|
+
* The owning list reads its page and its narrowing from the platform.
|
|
13
|
+
*
|
|
14
|
+
* The table then renders the rows it is handed and reports what the operator
|
|
15
|
+
* asked for, instead of narrowing and slicing an array. That is what lets the
|
|
16
|
+
* list reach past the newest hundred runs at all (PO-369).
|
|
17
|
+
*/
|
|
18
|
+
serverMode?: boolean;
|
|
19
|
+
/** How many runs match the narrowing. The pager's "of 7"; server mode only. */
|
|
20
|
+
total?: number;
|
|
21
|
+
/**
|
|
22
|
+
* How many rows a page holds — the SAME number the page asks the platform for.
|
|
23
|
+
*
|
|
24
|
+
* The shared table works its footer's "showing 1–25 of 140" out from its own
|
|
25
|
+
* page size, so a table left on its default while the request asks for another
|
|
26
|
+
* number states a range that is simply wrong: it counted twenty where
|
|
27
|
+
* twenty-five had arrived.
|
|
28
|
+
*/
|
|
29
|
+
perPage?: number;
|
|
30
|
+
/** The narrowing in force. Owned by the page, drawn here. */
|
|
31
|
+
status?: RunStatus[];
|
|
32
|
+
triggerType?: TriggerType | '';
|
|
33
|
+
/** The order the platform is reading the list in. Server mode only. */
|
|
34
|
+
sort?: RunSort;
|
|
35
|
+
direction?: RunSortDirection;
|
|
10
36
|
};
|
|
11
|
-
|
|
37
|
+
type __VLS_PublicProps = __VLS_Props & {
|
|
38
|
+
/** 1-based, as the platform pages. The shared table counts from zero. */
|
|
39
|
+
'page'?: number;
|
|
40
|
+
};
|
|
41
|
+
declare const _default: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
42
|
+
search: (text: string) => any;
|
|
12
43
|
changed: () => any;
|
|
13
|
-
|
|
44
|
+
narrow: (patch: {
|
|
45
|
+
status?: RunStatus[];
|
|
46
|
+
triggerType?: TriggerType | "";
|
|
47
|
+
}) => any;
|
|
48
|
+
"page-size": (size: number) => any;
|
|
49
|
+
reorder: (order: {
|
|
50
|
+
sort: RunSort;
|
|
51
|
+
direction: RunSortDirection;
|
|
52
|
+
}) => any;
|
|
53
|
+
"update:page": (value: number) => any;
|
|
54
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
55
|
+
onSearch?: ((text: string) => any) | undefined;
|
|
14
56
|
onChanged?: (() => any) | undefined;
|
|
57
|
+
onNarrow?: ((patch: {
|
|
58
|
+
status?: RunStatus[];
|
|
59
|
+
triggerType?: TriggerType | "";
|
|
60
|
+
}) => any) | undefined;
|
|
61
|
+
"onPage-size"?: ((size: number) => any) | undefined;
|
|
62
|
+
onReorder?: ((order: {
|
|
63
|
+
sort: RunSort;
|
|
64
|
+
direction: RunSortDirection;
|
|
65
|
+
}) => any) | undefined;
|
|
66
|
+
"onUpdate:page"?: ((value: number) => any) | undefined;
|
|
15
67
|
}>, {
|
|
68
|
+
sort: RunSort;
|
|
16
69
|
loading: boolean;
|
|
70
|
+
total: number;
|
|
71
|
+
direction: RunSortDirection;
|
|
72
|
+
triggerType: TriggerType | "";
|
|
73
|
+
perPage: number;
|
|
17
74
|
pagination: boolean;
|
|
18
75
|
showWorkflow: boolean;
|
|
76
|
+
serverMode: boolean;
|
|
19
77
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
20
78
|
export default _default;
|