@revenexx/studio-integrations 0.4.0 → 0.5.1
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/dist/module.json +1 -1
- package/dist/module.mjs +15 -2
- package/dist/runtime/components/Integrations/WorkflowEditor.d.vue.ts +2 -0
- package/dist/runtime/components/Integrations/WorkflowEditor.vue +4 -3
- package/dist/runtime/components/Integrations/WorkflowEditor.vue.d.ts +2 -0
- package/dist/runtime/pages/integrations/workflows/[id].vue +47 -17
- package/package.json +3 -3
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { existsSync, readdirSync, statSync } from 'node:fs';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
|
-
import { defineNuxtModule, createResolver, addComponentsDir, addImportsDir, extendPages } from '@nuxt/kit';
|
|
3
|
+
import { defineNuxtModule, createResolver, hasNuxtModule, installModule, addComponentsDir, addImportsDir, extendPages } from '@nuxt/kit';
|
|
4
4
|
|
|
5
5
|
function toSegment(name) {
|
|
6
6
|
if (name.startsWith("[...")) return `:${name.slice(4, -1)}(.*)*`;
|
|
@@ -27,9 +27,22 @@ const module$1 = defineNuxtModule({
|
|
|
27
27
|
name: "@revenexx/studio-integrations",
|
|
28
28
|
configKey: "studioIntegrations"
|
|
29
29
|
},
|
|
30
|
-
setup(_options, nuxt) {
|
|
30
|
+
async setup(_options, nuxt) {
|
|
31
31
|
const { resolve } = createResolver(import.meta.url);
|
|
32
32
|
const runtime = resolve("./runtime");
|
|
33
|
+
if (!hasNuxtModule("@solar-icons/nuxt", nuxt)) {
|
|
34
|
+
await installModule("@solar-icons/nuxt", {
|
|
35
|
+
namePrefix: "Solar",
|
|
36
|
+
autoImport: true,
|
|
37
|
+
provider: true,
|
|
38
|
+
color: "currentColor",
|
|
39
|
+
size: 18,
|
|
40
|
+
weight: "BoldDuotone"
|
|
41
|
+
}, nuxt);
|
|
42
|
+
}
|
|
43
|
+
if (!hasNuxtModule("@revenexx/studio-shared", nuxt) && !hasNuxtModule("studio-shared", nuxt)) {
|
|
44
|
+
await installModule("@revenexx/studio-shared", {}, nuxt);
|
|
45
|
+
}
|
|
33
46
|
nuxt.options.imports = nuxt.options.imports || {};
|
|
34
47
|
nuxt.options.imports.transform = nuxt.options.imports.transform || {};
|
|
35
48
|
nuxt.options.imports.transform.include = nuxt.options.imports.transform.include || [];
|
|
@@ -6,6 +6,8 @@ type __VLS_Props = {
|
|
|
6
6
|
workflow: Workflow;
|
|
7
7
|
/** Busy flag for the control-pane Play button (a run is being triggered). */
|
|
8
8
|
runBusy?: boolean;
|
|
9
|
+
/** The run is queued behind a bundle build — busy, but worth saying why. */
|
|
10
|
+
runWaiting?: boolean;
|
|
9
11
|
};
|
|
10
12
|
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
11
13
|
change: (blob: WorkflowBlob) => any;
|
|
@@ -50,7 +50,8 @@ import { layoutWorkflowNodes } from "./workflowLayout";
|
|
|
50
50
|
import { TRIGGER_TEMPLATES, findManifest } from "../../data/integrationNodeCatalog";
|
|
51
51
|
const props = defineProps({
|
|
52
52
|
workflow: { type: Object, required: true },
|
|
53
|
-
runBusy: { type: Boolean, required: false }
|
|
53
|
+
runBusy: { type: Boolean, required: false },
|
|
54
|
+
runWaiting: { type: Boolean, required: false }
|
|
54
55
|
});
|
|
55
56
|
const emit = defineEmits(["change", "run", "toggleActive", "openSettings"]);
|
|
56
57
|
const { keys: secretKeys } = useIntegrationsSecrets();
|
|
@@ -1472,7 +1473,7 @@ const edgeTypes = {
|
|
|
1472
1473
|
<!-- Smart Run: the page decides what "run" means — workflows that
|
|
1473
1474
|
consume trigger.payload open the payload dialog, payload-free
|
|
1474
1475
|
ones fire immediately. One button either way. -->
|
|
1475
|
-
<IntegrationsEditorTip label="Run workflow" shortcut="mod+enter">
|
|
1476
|
+
<IntegrationsEditorTip :label="runWaiting ? 'The bundle is still building \u2014 the run starts when it is ready' : 'Run workflow'" shortcut="mod+enter">
|
|
1476
1477
|
<button
|
|
1477
1478
|
type="button"
|
|
1478
1479
|
class="relative flex h-8 items-center gap-1.5 rounded-lg bg-gradient-to-b from-emerald-500 to-emerald-600 px-3.5 text-sm font-medium text-white transition after:pointer-events-none after:absolute after:inset-0 after:rounded-[inherit] after:shadow-[inset_0_1px_0_rgba(255,255,255,0.3),inset_0_-2px_0_rgba(0,0,0,0.25)] hover:from-emerald-600 hover:to-emerald-600 active:translate-y-px disabled:opacity-60"
|
|
@@ -1481,7 +1482,7 @@ const edgeTypes = {
|
|
|
1481
1482
|
>
|
|
1482
1483
|
<Loader2 v-if="runBusy" :size="14" class="animate-spin" />
|
|
1483
1484
|
<Play v-else :size="14" />
|
|
1484
|
-
Run
|
|
1485
|
+
{{ runWaiting ? "Waiting for build\u2026" : "Run" }}
|
|
1485
1486
|
</button>
|
|
1486
1487
|
</IntegrationsEditorTip>
|
|
1487
1488
|
|
|
@@ -6,6 +6,8 @@ type __VLS_Props = {
|
|
|
6
6
|
workflow: Workflow;
|
|
7
7
|
/** Busy flag for the control-pane Play button (a run is being triggered). */
|
|
8
8
|
runBusy?: boolean;
|
|
9
|
+
/** The run is queued behind a bundle build — busy, but worth saying why. */
|
|
10
|
+
runWaiting?: boolean;
|
|
9
11
|
};
|
|
10
12
|
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
11
13
|
change: (blob: WorkflowBlob) => any;
|
|
@@ -54,11 +54,33 @@ const reauthCredentials = computed(() => {
|
|
|
54
54
|
const blob = JSON.stringify(dirtyBlob.value ?? workflow.value?.blob ?? {});
|
|
55
55
|
return needsReauth.value.filter((c) => blob.includes(c.id));
|
|
56
56
|
});
|
|
57
|
-
const buildBlocked = computed(() => {
|
|
58
|
-
const s = workflow.value?.buildStatus;
|
|
59
|
-
return s === "pending" || s === "building" || s === "failed";
|
|
60
|
-
});
|
|
61
57
|
const buildWorking = computed(() => workflow.value?.buildStatus === "building" || workflow.value?.buildStatus === "pending");
|
|
58
|
+
const buildFailed = computed(() => workflow.value?.buildStatus === "failed");
|
|
59
|
+
const waitingForBuild = ref(false);
|
|
60
|
+
const BUILD_WAIT_POLL_MS = 2500;
|
|
61
|
+
const BUILD_WAIT_TIMEOUT_MS = 5 * 6e4;
|
|
62
|
+
async function waitForBuildReady() {
|
|
63
|
+
waitingForBuild.value = true;
|
|
64
|
+
try {
|
|
65
|
+
const started = Date.now();
|
|
66
|
+
while (Date.now() - started < BUILD_WAIT_TIMEOUT_MS) {
|
|
67
|
+
await new Promise((resolve) => setTimeout(resolve, BUILD_WAIT_POLL_MS));
|
|
68
|
+
if (!workflow.value) return false;
|
|
69
|
+
const fresh = await get(workflow.value.id);
|
|
70
|
+
const status = fresh?.buildStatus;
|
|
71
|
+
if (status === "pending" || status === "building") continue;
|
|
72
|
+
if (status === "failed") {
|
|
73
|
+
toast.error("The workflow bundle failed to build \u2014 the run was not started.");
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
toast.error("The bundle build is taking unusually long \u2014 try the run again once it is ready.");
|
|
79
|
+
return false;
|
|
80
|
+
} finally {
|
|
81
|
+
waitingForBuild.value = false;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
62
84
|
const buildNotice = computed(() => {
|
|
63
85
|
switch (workflow.value?.buildStatus) {
|
|
64
86
|
case "building":
|
|
@@ -101,6 +123,7 @@ async function onRevisionRestored() {
|
|
|
101
123
|
}
|
|
102
124
|
const { trigger: triggerRun, loadForWorkflow, fetchRun, retryRun } = useIntegrationsRuns();
|
|
103
125
|
const running = ref(false);
|
|
126
|
+
const waitingMode = ref(null);
|
|
104
127
|
const payloadText = ref("{}");
|
|
105
128
|
const payloadError = ref(null);
|
|
106
129
|
const primaryMode = computed(() => workflow.value?.execution_mode === "sync_only" ? "sync" : "async");
|
|
@@ -139,6 +162,12 @@ async function run(mode) {
|
|
|
139
162
|
return;
|
|
140
163
|
}
|
|
141
164
|
payloadError.value = null;
|
|
165
|
+
if (buildWorking.value) {
|
|
166
|
+
waitingMode.value = mode;
|
|
167
|
+
const ready = await waitForBuildReady();
|
|
168
|
+
waitingMode.value = null;
|
|
169
|
+
if (!ready) return;
|
|
170
|
+
}
|
|
142
171
|
runModalMode.value = mode;
|
|
143
172
|
runModalRunId.value = null;
|
|
144
173
|
syncOpen.value = true;
|
|
@@ -574,7 +603,8 @@ function formatDateTime(iso) {
|
|
|
574
603
|
<WorkflowEditor
|
|
575
604
|
:key="editorResetKey"
|
|
576
605
|
:workflow="workflow"
|
|
577
|
-
:run-busy="running || syncLoading"
|
|
606
|
+
:run-busy="running || syncLoading || waitingForBuild"
|
|
607
|
+
:run-waiting="waitingForBuild"
|
|
578
608
|
@change="onChange"
|
|
579
609
|
@run="runFromEditor"
|
|
580
610
|
@toggle-active="toggleActive(workflow.id)"
|
|
@@ -669,36 +699,36 @@ function formatDateTime(iso) {
|
|
|
669
699
|
<template v-if="workflow.execution_mode === 'caller_decides'">
|
|
670
700
|
<Button
|
|
671
701
|
variant="outline"
|
|
672
|
-
:disabled="running || syncLoading ||
|
|
673
|
-
:title="
|
|
702
|
+
:disabled="running || syncLoading || waitingForBuild || buildFailed"
|
|
703
|
+
:title="buildFailed ? 'The workflow bundle failed to build.' : void 0"
|
|
674
704
|
class="h-8 text-sm"
|
|
675
705
|
@click="runFromPayloadDialog('sync')"
|
|
676
706
|
>
|
|
677
|
-
<Loader2 v-if="syncLoading" :size="14" class="animate-spin" />
|
|
707
|
+
<Loader2 v-if="syncLoading || waitingMode === 'sync'" :size="14" class="animate-spin" />
|
|
678
708
|
<Play v-else :size="14" />
|
|
679
|
-
Run (sync)
|
|
709
|
+
{{ waitingMode === "sync" ? "Waiting for build\u2026" : "Run (sync)" }}
|
|
680
710
|
</Button>
|
|
681
711
|
<Button
|
|
682
|
-
:disabled="running || syncLoading ||
|
|
683
|
-
:title="
|
|
712
|
+
:disabled="running || syncLoading || waitingForBuild || buildFailed"
|
|
713
|
+
:title="buildFailed ? 'The workflow bundle failed to build.' : void 0"
|
|
684
714
|
class="h-8 text-sm"
|
|
685
715
|
@click="runFromPayloadDialog('async')"
|
|
686
716
|
>
|
|
687
|
-
<Loader2 v-if="running" :size="14" class="animate-spin" />
|
|
717
|
+
<Loader2 v-if="running || waitingMode === 'async'" :size="14" class="animate-spin" />
|
|
688
718
|
<Play v-else :size="14" />
|
|
689
|
-
Run (async)
|
|
719
|
+
{{ waitingMode === "async" ? "Waiting for build\u2026" : "Run (async)" }}
|
|
690
720
|
</Button>
|
|
691
721
|
</template>
|
|
692
722
|
<Button
|
|
693
723
|
v-else
|
|
694
|
-
:disabled="running || syncLoading ||
|
|
695
|
-
:title="
|
|
724
|
+
:disabled="running || syncLoading || waitingForBuild || buildFailed"
|
|
725
|
+
:title="buildFailed ? 'The workflow bundle failed to build.' : void 0"
|
|
696
726
|
class="h-8 text-sm"
|
|
697
727
|
@click="runFromPayloadDialog(primaryMode)"
|
|
698
728
|
>
|
|
699
|
-
<Loader2 v-if="running || syncLoading" :size="14" class="animate-spin" />
|
|
729
|
+
<Loader2 v-if="running || syncLoading || waitingForBuild" :size="14" class="animate-spin" />
|
|
700
730
|
<Play v-else :size="14" />
|
|
701
|
-
Run ({
|
|
731
|
+
{{ waitingForBuild ? "Waiting for build\u2026" : `Run (${primaryMode})` }}
|
|
702
732
|
</Button>
|
|
703
733
|
</div>
|
|
704
734
|
</DialogContent>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@revenexx/studio-integrations",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Integration Studio (core: workflows, node editor, runs, schedules, credentials, secrets, audit) as a standalone, publishable Nuxt module.",
|
|
6
6
|
"repository": {
|
|
@@ -25,13 +25,13 @@
|
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"@nuxt/kit": "^4.0.0",
|
|
28
|
+
"@revenexx/studio-shared": "^0.2.0",
|
|
29
|
+
"@solar-icons/nuxt": "^1.2.0",
|
|
28
30
|
"marked": "^18.0.5"
|
|
29
31
|
},
|
|
30
32
|
"peerDependencies": {
|
|
31
33
|
"@dagrejs/dagre": "^3.0.0",
|
|
32
34
|
"@revenexx/studio": "*",
|
|
33
|
-
"@revenexx/studio-shared": "^0.2.0",
|
|
34
|
-
"@solar-icons/nuxt": "^1.2.0",
|
|
35
35
|
"@tiptap/core": "^3.28.0",
|
|
36
36
|
"@tiptap/extension-document": "^3.28.0",
|
|
37
37
|
"@tiptap/extension-history": "^3.28.0",
|