@burdenoff/microfe-devportal 2026.1026.3 → 2026.1031.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/devportal/DevportalRoutes.d.ts.map +1 -1
- package/dist/devportal/DevportalRoutes.js +127 -123
- package/dist/devportal/DevportalRoutes.js.map +1 -1
- package/dist/devportal/pages/ApplicationVersionsPage.d.ts.map +1 -1
- package/dist/devportal/pages/ApplicationVersionsPage.js +469 -454
- package/dist/devportal/pages/ApplicationVersionsPage.js.map +1 -1
- package/dist/devportal/pages/NodeLifecyclePage.d.ts +7 -0
- package/dist/devportal/pages/NodeLifecyclePage.d.ts.map +1 -0
- package/dist/devportal/pages/NodeLifecyclePage.js +649 -0
- package/dist/devportal/pages/NodeLifecyclePage.js.map +1 -0
- package/dist/devportal/utils/nodeLifecycle.d.ts +81 -0
- package/dist/devportal/utils/nodeLifecycle.d.ts.map +1 -0
- package/dist/devportal/utils/nodeLifecycle.js +280 -0
- package/dist/devportal/utils/nodeLifecycle.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,649 @@
|
|
|
1
|
+
import { useDevportal as e } from "../providers/DevportalProvider.js";
|
|
2
|
+
import { useTr as t } from "../utils/i18n.js";
|
|
3
|
+
import { cn as n } from "../utils/cn.js";
|
|
4
|
+
import { LoadingState as r } from "../components/LoadingState.js";
|
|
5
|
+
import { EmptyState as i } from "../components/EmptyState.js";
|
|
6
|
+
import { useGetApplicationQuery as a, usePublishApplicationVersionMutation as o, usePublishApplicationVersionToOrganizationMutation as s, useUpdateApplicationVersionMutation as ee } from "../../generated/global-operations.js";
|
|
7
|
+
import { PageLayout as c } from "../components/PageLayout.js";
|
|
8
|
+
import { useDevportalPermission as l } from "../hooks/usePermission.js";
|
|
9
|
+
import "../hooks/index.js";
|
|
10
|
+
import { DEVPORTAL_PERMISSIONS as u } from "../constants/permissions.js";
|
|
11
|
+
import { usePackageUpload as te } from "../hooks/usePackageUpload.js";
|
|
12
|
+
import { deployBlocker as ne, deriveNodeLifecycle as re, visibilityForApp as ie } from "../utils/nodeLifecycle.js";
|
|
13
|
+
import { useCallback as ae, useEffect as oe, useMemo as d, useRef as se, useState as f } from "react";
|
|
14
|
+
import { AlertTriangle as ce, BookOpen as le, Building2 as ue, Check as p, CheckCircle2 as m, ChevronDown as h, ChevronUp as g, Copy as de, FileCode2 as _, FlaskConical as v, Globe as fe, Loader2 as y, Lock as pe, MinusCircle as b, Package as x, Rocket as me, Server as he, ShieldCheck as S, Upload as C, XCircle as w } from "lucide-react";
|
|
15
|
+
import { useParams as ge } from "react-router";
|
|
16
|
+
import { Fragment as _e, jsx as T, jsxs as E } from "react/jsx-runtime";
|
|
17
|
+
//#region src/devportal/pages/NodeLifecyclePage.tsx
|
|
18
|
+
var ve = 1e4, D = {
|
|
19
|
+
upload: ["devportal.nodeLifecycle.step.upload", "Upload ZIP"],
|
|
20
|
+
validate: ["devportal.nodeLifecycle.step.validate", "Validate manifest"],
|
|
21
|
+
test: ["devportal.nodeLifecycle.step.test", "Run tests"],
|
|
22
|
+
approval: ["devportal.nodeLifecycle.step.approval", "Approval"],
|
|
23
|
+
deploy: ["devportal.nodeLifecycle.step.deploy", "Deploy"]
|
|
24
|
+
}, O = {
|
|
25
|
+
uploaded: "Completed",
|
|
26
|
+
noPackage: "Upload the node package",
|
|
27
|
+
waitingForPackage: "Pending",
|
|
28
|
+
passed: "Completed",
|
|
29
|
+
failed: "Failed — see checks",
|
|
30
|
+
validating: "In progress",
|
|
31
|
+
notValidated: "Upload the package again to validate it",
|
|
32
|
+
waitingForValidation: "Pending",
|
|
33
|
+
building: "Building sandbox image",
|
|
34
|
+
buildFailed: "Build failed",
|
|
35
|
+
testing: "Testing operations",
|
|
36
|
+
testsFailed: "Tests failed",
|
|
37
|
+
testsSkipped: "Completed (tests not run here)",
|
|
38
|
+
testsPassed: "Completed",
|
|
39
|
+
built: "Completed",
|
|
40
|
+
organization: "Approved by your organization",
|
|
41
|
+
approved: "Approved",
|
|
42
|
+
inReview: "Awaiting platform review",
|
|
43
|
+
rejected: "Changes requested",
|
|
44
|
+
waitingForTests: "Pending",
|
|
45
|
+
readyForOrganization: "Auto-approved when you deploy",
|
|
46
|
+
readyToSubmit: "Submit for platform review",
|
|
47
|
+
deprecated: "Deprecated",
|
|
48
|
+
store: "Live in the Node Store",
|
|
49
|
+
deployedToOrganization: "Installable in your organization's workspaces",
|
|
50
|
+
ready: "Ready to deploy",
|
|
51
|
+
waitingForApproval: "Pending"
|
|
52
|
+
}, k = {
|
|
53
|
+
structure: {
|
|
54
|
+
icon: /* @__PURE__ */ T(x, { size: 16 }),
|
|
55
|
+
key: "devportal.nodeLifecycle.check.structure",
|
|
56
|
+
label: "Package structure"
|
|
57
|
+
},
|
|
58
|
+
manifest: {
|
|
59
|
+
icon: /* @__PURE__ */ T(_, { size: 16 }),
|
|
60
|
+
key: "devportal.nodeLifecycle.check.manifest",
|
|
61
|
+
label: "Manifest & operations"
|
|
62
|
+
},
|
|
63
|
+
security: {
|
|
64
|
+
icon: /* @__PURE__ */ T(S, { size: 16 }),
|
|
65
|
+
key: "devportal.nodeLifecycle.check.security",
|
|
66
|
+
label: "Security scan"
|
|
67
|
+
},
|
|
68
|
+
build: {
|
|
69
|
+
icon: /* @__PURE__ */ T(he, { size: 16 }),
|
|
70
|
+
key: "devportal.nodeLifecycle.check.build",
|
|
71
|
+
label: "Sandbox image build"
|
|
72
|
+
},
|
|
73
|
+
tests: {
|
|
74
|
+
icon: /* @__PURE__ */ T(v, { size: 16 }),
|
|
75
|
+
key: "devportal.nodeLifecycle.check.tests",
|
|
76
|
+
label: "Automated operation tests"
|
|
77
|
+
}
|
|
78
|
+
}, ye = {
|
|
79
|
+
pass: {
|
|
80
|
+
label: "PASS",
|
|
81
|
+
className: "bg-status-success-bg-subtle text-status-success-text"
|
|
82
|
+
},
|
|
83
|
+
warn: {
|
|
84
|
+
label: "REVIEW",
|
|
85
|
+
className: "bg-status-warning-bg-subtle text-status-warning-text"
|
|
86
|
+
},
|
|
87
|
+
fail: {
|
|
88
|
+
label: "FAIL",
|
|
89
|
+
className: "bg-status-error-bg-subtle text-status-error-text"
|
|
90
|
+
},
|
|
91
|
+
running: {
|
|
92
|
+
label: "RUNNING",
|
|
93
|
+
className: "bg-status-info-bg-subtle text-status-info-text"
|
|
94
|
+
},
|
|
95
|
+
not_run: {
|
|
96
|
+
label: "NOT RUN",
|
|
97
|
+
className: "bg-bg-sunken text-text-secondary"
|
|
98
|
+
}
|
|
99
|
+
}, be = {
|
|
100
|
+
noPermission: ["devportal.nodeLifecycle.blocker.noPermission", "You do not have permission to publish versions of this node."],
|
|
101
|
+
notDraft: ["devportal.nodeLifecycle.blocker.notDraft", "This version has already been submitted or deployed. Create a new version to ship a change."],
|
|
102
|
+
visibilityMismatch: ["devportal.nodeLifecycle.blocker.visibilityMismatch", "This node's visibility does not allow that. Change it under Edit application."],
|
|
103
|
+
noPackage: ["devportal.nodeLifecycle.blocker.noPackage", "Upload the node package first."],
|
|
104
|
+
validationNotPassed: ["devportal.nodeLifecycle.blocker.validationNotPassed", "The package must pass validation first."],
|
|
105
|
+
buildNotReady: ["devportal.nodeLifecycle.blocker.buildNotReady", "Waiting for the sandbox image to build."],
|
|
106
|
+
testsNotPassed: ["devportal.nodeLifecycle.blocker.testsNotPassed", "The operation tests must finish without failures first."],
|
|
107
|
+
noWorkspace: ["devportal.nodeLifecycle.blocker.noWorkspace", "Open the developer portal from a workspace of your organization to publish privately."],
|
|
108
|
+
pendingVersion: ["devportal.nodeLifecycle.blocker.pendingVersion", "Another version of this node is already in review."]
|
|
109
|
+
};
|
|
110
|
+
function xe(e, t) {
|
|
111
|
+
return e(`devportal.nodeLifecycle.reason.${t.reason}`, O[t.reason] ?? t.reason);
|
|
112
|
+
}
|
|
113
|
+
var A = ({ step: e, index: t }) => {
|
|
114
|
+
let r = "flex h-11 w-11 shrink-0 items-center justify-center rounded-full border-2 text-sm font-semibold";
|
|
115
|
+
switch (e.status) {
|
|
116
|
+
case "complete": return /* @__PURE__ */ T("span", {
|
|
117
|
+
className: n(r, "border-status-success-text bg-status-success-bg-subtle text-status-success-text"),
|
|
118
|
+
children: /* @__PURE__ */ T(p, { size: 20 })
|
|
119
|
+
});
|
|
120
|
+
case "failed": return /* @__PURE__ */ T("span", {
|
|
121
|
+
className: n(r, "border-status-error-text bg-status-error-bg-subtle text-status-error-text"),
|
|
122
|
+
children: /* @__PURE__ */ T(w, { size: 20 })
|
|
123
|
+
});
|
|
124
|
+
case "in_progress": return /* @__PURE__ */ T("span", {
|
|
125
|
+
className: n(r, "border-action-primary-bg bg-action-primary-bg text-action-primary-text"),
|
|
126
|
+
children: /* @__PURE__ */ T(y, {
|
|
127
|
+
size: 18,
|
|
128
|
+
className: "animate-spin"
|
|
129
|
+
})
|
|
130
|
+
});
|
|
131
|
+
case "action": return /* @__PURE__ */ T("span", {
|
|
132
|
+
className: n(r, "border-action-primary-bg bg-action-primary-bg text-action-primary-text"),
|
|
133
|
+
children: t + 1
|
|
134
|
+
});
|
|
135
|
+
default: return /* @__PURE__ */ T("span", {
|
|
136
|
+
className: n(r, "border-border-seam text-text-secondary"),
|
|
137
|
+
children: t + 1
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
}, Se = ({ lifecycle: e, tr: t }) => /* @__PURE__ */ T("ol", {
|
|
141
|
+
className: "grid grid-cols-1 gap-4 sm:grid-cols-5",
|
|
142
|
+
"data-testid": "node-lifecycle-stepper",
|
|
143
|
+
children: e.steps.map((r, i) => {
|
|
144
|
+
let [a, o] = D[r.id], s = r.status === "complete" ? "text-status-success-text" : r.status === "failed" ? "text-status-error-text" : r.status === "in_progress" || r.status === "action" ? "text-status-info-text" : "text-text-secondary";
|
|
145
|
+
return /* @__PURE__ */ E("li", {
|
|
146
|
+
className: "flex items-center gap-3 sm:flex-col sm:text-center",
|
|
147
|
+
"data-step": r.id,
|
|
148
|
+
"data-status": r.status,
|
|
149
|
+
"aria-current": i === e.currentIndex ? "step" : void 0,
|
|
150
|
+
children: [/* @__PURE__ */ T(A, {
|
|
151
|
+
step: r,
|
|
152
|
+
index: i
|
|
153
|
+
}), /* @__PURE__ */ E("div", {
|
|
154
|
+
className: "flex flex-col",
|
|
155
|
+
children: [/* @__PURE__ */ E("span", {
|
|
156
|
+
className: "text-sm font-semibold text-text-primary",
|
|
157
|
+
children: [
|
|
158
|
+
i + 1,
|
|
159
|
+
". ",
|
|
160
|
+
t(a, o)
|
|
161
|
+
]
|
|
162
|
+
}), /* @__PURE__ */ T("span", {
|
|
163
|
+
className: n("text-xs", s),
|
|
164
|
+
children: xe(t, r)
|
|
165
|
+
})]
|
|
166
|
+
})]
|
|
167
|
+
}, r.id);
|
|
168
|
+
})
|
|
169
|
+
});
|
|
170
|
+
function j(e, t) {
|
|
171
|
+
if (t.id === "tests" && t.status === "pass" && t.detail) {
|
|
172
|
+
let [n, r] = t.detail.split("/");
|
|
173
|
+
return e("devportal.nodeLifecycle.testsPassing", "{{passed}} / {{total}} passing", {
|
|
174
|
+
passed: n ?? "0",
|
|
175
|
+
total: r ?? "0"
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
return t.detail === "notValidated" ? e("devportal.nodeLifecycle.notValidated", "Uploaded before validation existed") : t.detail === "blockedByValidation" ? e("devportal.nodeLifecycle.blockedByValidation", "Not built: the package failed validation") : t.detail;
|
|
179
|
+
}
|
|
180
|
+
var Ce = ({ lifecycle: e, tr: t }) => {
|
|
181
|
+
let [r, i] = f(!1), a = e.smoke, o = a.kind === "passed" || a.kind === "failed" || a.kind === "skipped" ? a.operations : [], s = a.kind === "passed" || a.kind === "failed" || a.kind === "skipped" ? a.finishedAt : null;
|
|
182
|
+
return /* @__PURE__ */ E("section", {
|
|
183
|
+
className: "flex flex-col rounded-card border border-border-seam bg-bg-surface",
|
|
184
|
+
"data-testid": "node-lifecycle-checks",
|
|
185
|
+
children: [
|
|
186
|
+
/* @__PURE__ */ T("h2", {
|
|
187
|
+
className: "border-b border-border-seam px-5 py-4 text-base font-semibold",
|
|
188
|
+
children: t("devportal.nodeLifecycle.checks", "Checks")
|
|
189
|
+
}),
|
|
190
|
+
/* @__PURE__ */ T("ul", {
|
|
191
|
+
className: "divide-y divide-border-seam",
|
|
192
|
+
children: e.checks.map((e) => {
|
|
193
|
+
let r = k[e.id], i = ye[e.status], a = j(t, e);
|
|
194
|
+
return /* @__PURE__ */ E("li", {
|
|
195
|
+
className: "px-5 py-3",
|
|
196
|
+
"data-check": e.id,
|
|
197
|
+
"data-status": e.status,
|
|
198
|
+
children: [/* @__PURE__ */ E("div", {
|
|
199
|
+
className: "flex items-center gap-3",
|
|
200
|
+
children: [
|
|
201
|
+
/* @__PURE__ */ T("span", {
|
|
202
|
+
className: "text-text-secondary",
|
|
203
|
+
children: r.icon
|
|
204
|
+
}),
|
|
205
|
+
/* @__PURE__ */ E("span", {
|
|
206
|
+
className: "flex-1 text-sm font-medium",
|
|
207
|
+
children: [t(r.key, r.label), a && /* @__PURE__ */ T("span", {
|
|
208
|
+
className: "ml-2 text-xs font-normal text-text-secondary",
|
|
209
|
+
children: a
|
|
210
|
+
})]
|
|
211
|
+
}),
|
|
212
|
+
/* @__PURE__ */ E("span", {
|
|
213
|
+
className: n("inline-flex items-center gap-1 rounded-md px-2 py-0.5 text-xs font-semibold", i.className),
|
|
214
|
+
children: [e.status === "running" && /* @__PURE__ */ T(y, {
|
|
215
|
+
size: 11,
|
|
216
|
+
className: "animate-spin"
|
|
217
|
+
}), t(`devportal.nodeLifecycle.badge.${e.status}`, i.label)]
|
|
218
|
+
})
|
|
219
|
+
]
|
|
220
|
+
}), e.issues.length > 0 && /* @__PURE__ */ T("ul", {
|
|
221
|
+
className: "mt-2 space-y-1 pl-7",
|
|
222
|
+
children: e.issues.map((e, t) => /* @__PURE__ */ E("li", {
|
|
223
|
+
className: "text-xs leading-snug",
|
|
224
|
+
children: [e.path && /* @__PURE__ */ T("code", {
|
|
225
|
+
className: "mr-1 rounded bg-bg-sunken px-1 py-0.5 font-mono text-text-primary",
|
|
226
|
+
children: e.path
|
|
227
|
+
}), /* @__PURE__ */ T("span", {
|
|
228
|
+
className: e.severity === "error" ? "text-status-error-text" : "text-status-warning-text",
|
|
229
|
+
children: e.message
|
|
230
|
+
})]
|
|
231
|
+
}, `${e.code}-${e.path}-${t}`))
|
|
232
|
+
})]
|
|
233
|
+
}, e.id);
|
|
234
|
+
})
|
|
235
|
+
}),
|
|
236
|
+
/* @__PURE__ */ E("div", {
|
|
237
|
+
className: "mt-auto border-t border-border-seam px-5 py-3",
|
|
238
|
+
children: [/* @__PURE__ */ E("div", {
|
|
239
|
+
className: "flex items-center justify-between gap-2 text-xs text-text-secondary",
|
|
240
|
+
children: [/* @__PURE__ */ T("span", { children: s ? t("devportal.nodeLifecycle.testsFinished", "Tests finished {{time}}", { time: new Date(s).toLocaleString() }) : t("devportal.nodeLifecycle.testsNotFinished", "No test run recorded yet") }), o.length > 0 && /* @__PURE__ */ E("button", {
|
|
241
|
+
type: "button",
|
|
242
|
+
className: "inline-flex items-center gap-1 font-medium text-status-info-text hover:underline",
|
|
243
|
+
onClick: () => i((e) => !e),
|
|
244
|
+
"aria-expanded": r,
|
|
245
|
+
children: [r ? t("devportal.nodeLifecycle.hideTestLogs", "Hide test logs") : t("devportal.nodeLifecycle.viewTestLogs", "View test logs"), T(r ? g : h, { size: 12 })]
|
|
246
|
+
})]
|
|
247
|
+
}), r && /* @__PURE__ */ T("ul", {
|
|
248
|
+
className: "mt-3 space-y-1 rounded-md bg-bg-sunken p-3 font-mono text-xs",
|
|
249
|
+
"data-testid": "node-lifecycle-test-logs",
|
|
250
|
+
children: o.map((e, t) => /* @__PURE__ */ E("li", {
|
|
251
|
+
className: "flex gap-2",
|
|
252
|
+
children: [
|
|
253
|
+
e.status === "PASS" ? /* @__PURE__ */ T(m, {
|
|
254
|
+
size: 12,
|
|
255
|
+
className: "mt-0.5 shrink-0 text-status-success-text"
|
|
256
|
+
}) : e.status === "SKIP" ? /* @__PURE__ */ T(b, {
|
|
257
|
+
size: 12,
|
|
258
|
+
className: "mt-0.5 shrink-0 text-text-secondary"
|
|
259
|
+
}) : /* @__PURE__ */ T(w, {
|
|
260
|
+
size: 12,
|
|
261
|
+
className: "mt-0.5 shrink-0 text-status-error-text"
|
|
262
|
+
}),
|
|
263
|
+
/* @__PURE__ */ T("span", {
|
|
264
|
+
className: "text-text-primary",
|
|
265
|
+
children: e.name
|
|
266
|
+
}),
|
|
267
|
+
/* @__PURE__ */ E("span", {
|
|
268
|
+
className: "text-text-secondary",
|
|
269
|
+
children: [
|
|
270
|
+
e.status,
|
|
271
|
+
" · ",
|
|
272
|
+
e.durationMs,
|
|
273
|
+
" ms"
|
|
274
|
+
]
|
|
275
|
+
}),
|
|
276
|
+
(e.error ?? e.detail) && /* @__PURE__ */ T("span", {
|
|
277
|
+
className: "break-all text-text-secondary",
|
|
278
|
+
children: e.error ?? e.detail
|
|
279
|
+
})
|
|
280
|
+
]
|
|
281
|
+
}, `${e.name}-${t}`))
|
|
282
|
+
})]
|
|
283
|
+
})
|
|
284
|
+
]
|
|
285
|
+
});
|
|
286
|
+
}, we = ({ manifest: e, tr: t }) => {
|
|
287
|
+
let [n, r] = f(!1), i = d(() => e ? JSON.stringify(e, null, 2) : "", [e]), a = i ? i.split("\n") : [];
|
|
288
|
+
return /* @__PURE__ */ E("section", {
|
|
289
|
+
className: "flex min-w-0 flex-col rounded-card border border-border-seam bg-bg-surface",
|
|
290
|
+
"data-testid": "node-lifecycle-manifest",
|
|
291
|
+
children: [/* @__PURE__ */ E("div", {
|
|
292
|
+
className: "flex items-center justify-between gap-2 border-b border-border-seam px-5 py-3",
|
|
293
|
+
children: [/* @__PURE__ */ E("h2", {
|
|
294
|
+
className: "text-base font-semibold",
|
|
295
|
+
children: [
|
|
296
|
+
t("devportal.nodeLifecycle.manifestPreview", "Manifest preview"),
|
|
297
|
+
" ",
|
|
298
|
+
/* @__PURE__ */ T("span", {
|
|
299
|
+
className: "font-normal text-text-secondary",
|
|
300
|
+
children: "(manifest.json)"
|
|
301
|
+
})
|
|
302
|
+
]
|
|
303
|
+
}), i && /* @__PURE__ */ E("button", {
|
|
304
|
+
type: "button",
|
|
305
|
+
onClick: async () => {
|
|
306
|
+
try {
|
|
307
|
+
await navigator.clipboard.writeText(i), r(!0), window.setTimeout(() => r(!1), 2e3);
|
|
308
|
+
} catch {
|
|
309
|
+
r(!1);
|
|
310
|
+
}
|
|
311
|
+
},
|
|
312
|
+
className: "inline-flex items-center gap-1.5 rounded-md border border-border-seam px-3 py-1.5 text-xs font-medium hover:bg-accent",
|
|
313
|
+
children: [T(n ? p : de, { size: 13 }), n ? t("devportal.copied", "Copied") : t("devportal.copy", "Copy")]
|
|
314
|
+
})]
|
|
315
|
+
}), a.length > 0 ? /* @__PURE__ */ T("pre", {
|
|
316
|
+
className: "max-h-[28rem] flex-1 overflow-auto px-0 py-3 font-mono text-xs leading-5",
|
|
317
|
+
children: a.map((e, t) => /* @__PURE__ */ E("div", {
|
|
318
|
+
className: "flex",
|
|
319
|
+
children: [/* @__PURE__ */ T("span", {
|
|
320
|
+
className: "w-10 shrink-0 select-none pr-3 text-right text-text-tertiary",
|
|
321
|
+
children: t + 1
|
|
322
|
+
}), /* @__PURE__ */ T("span", {
|
|
323
|
+
className: "whitespace-pre text-text-primary",
|
|
324
|
+
children: e
|
|
325
|
+
})]
|
|
326
|
+
}, t))
|
|
327
|
+
}) : /* @__PURE__ */ T("p", {
|
|
328
|
+
className: "px-5 py-6 text-sm text-text-secondary",
|
|
329
|
+
children: t("devportal.nodeLifecycle.noManifest", "This version has no manifest yet. Add one from the versions page.")
|
|
330
|
+
})]
|
|
331
|
+
});
|
|
332
|
+
}, M = () => {
|
|
333
|
+
let h = t(), { appId: g, versionId: _ } = ge(), { basePath: v, navigate: b, workspaceId: x, workspacesGatewayUrl: he, authToken: S, getWorkspaceToken: w } = e(), { allowed: D } = l(u.APP_VERSION_PUBLISH), { allowed: O } = l(u.APP_VERSION_UPDATE), { data: k, loading: ye, error: A, startPolling: j, stopPolling: M } = a({
|
|
334
|
+
variables: { id: g ?? "" },
|
|
335
|
+
skip: !g,
|
|
336
|
+
fetchPolicy: "cache-and-network"
|
|
337
|
+
}), N = k?.application, P = d(() => N?.versions?.edges?.map((e) => e.node) ?? [], [N?.versions]), F = P.find((e) => e.id === _) ?? null, I = N?.visibility ?? null, L = ie(I), R = d(() => F ? re(F, L) : null, [F, L]), z = R?.busy ?? !1;
|
|
338
|
+
oe(() => {
|
|
339
|
+
if (z) return j(ve), () => M();
|
|
340
|
+
}, [
|
|
341
|
+
z,
|
|
342
|
+
j,
|
|
343
|
+
M
|
|
344
|
+
]);
|
|
345
|
+
let Te = P.some((e) => e.id !== _ && e.status === "pending_review"), [Ee] = ee({
|
|
346
|
+
refetchQueries: ["GetApplication"],
|
|
347
|
+
awaitRefetchQueries: !0
|
|
348
|
+
}), [De, { loading: Oe }] = o({ refetchQueries: ["GetApplication"] }), [ke, { loading: Ae }] = s({ refetchQueries: ["GetApplication"] }), { upload: je, uploading: B, progress: Me, error: V } = te(he, S, x, w), H = se(null), [U, W] = f(null), [G, K] = f(null), [Ne, q] = f(!1), [J, Y] = f(!1), X = ae((e) => b?.(`${v}${e}`), [b, v]), Pe = async (e) => {
|
|
349
|
+
let t = e.target.files?.[0];
|
|
350
|
+
if (e.target.value = "", !(!t || !F)) {
|
|
351
|
+
if (W(null), K(null), !t.name.toLowerCase().endsWith(".zip")) {
|
|
352
|
+
W(h("devportal.nodeLifecycle.zipOnly", "Upload the node as a .zip package."));
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
Y(!0);
|
|
356
|
+
try {
|
|
357
|
+
let e = await je(t), n = await Ee({ variables: {
|
|
358
|
+
id: F.id,
|
|
359
|
+
input: {
|
|
360
|
+
packageUrl: e.downloadUrl,
|
|
361
|
+
packageSize: String(t.size)
|
|
362
|
+
}
|
|
363
|
+
} });
|
|
364
|
+
if (n.error || !n.data?.updateApplicationVersion) throw n.error ?? Error(h("devportal.nodeLifecycle.uploadFailed", "Failed to attach the package to this version"));
|
|
365
|
+
K(h("devportal.nodeLifecycle.uploaded", "Package uploaded. Validation and tests start automatically."));
|
|
366
|
+
} catch (e) {
|
|
367
|
+
W(e instanceof Error ? e.message : h("devportal.nodeLifecycle.uploadFailed", "Failed to attach the package to this version"));
|
|
368
|
+
} finally {
|
|
369
|
+
Y(!1);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}, Fe = L === "store" && N?.status !== "PUBLISHED", Z = F && R ? ne({
|
|
373
|
+
lifecycle: R,
|
|
374
|
+
version: F,
|
|
375
|
+
visibility: L,
|
|
376
|
+
appVisibility: I,
|
|
377
|
+
workspaceId: x,
|
|
378
|
+
otherVersionPending: Te,
|
|
379
|
+
canPublish: D
|
|
380
|
+
}) : "notDraft", Ie = async () => {
|
|
381
|
+
if (!(!F || Z || J)) {
|
|
382
|
+
if (W(null), K(null), Fe) {
|
|
383
|
+
X(`/apps/${g}/publish`);
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
try {
|
|
387
|
+
if (L === "private") {
|
|
388
|
+
if (!x) return;
|
|
389
|
+
let e = await ke({ variables: {
|
|
390
|
+
id: F.id,
|
|
391
|
+
workspaceId: x
|
|
392
|
+
} });
|
|
393
|
+
if (e.error || !e.data?.publishApplicationVersionToOrganization) throw e.error ?? Error(h("devportal.versionPublishToOrganizationFailed", "Failed to publish the version to your organization"));
|
|
394
|
+
K(h("devportal.nodeLifecycle.deployedPrivately", "Deployed to your organization. Workspace admins can now install it from the Node Store."));
|
|
395
|
+
} else {
|
|
396
|
+
let e = await De({ variables: { id: F.id } });
|
|
397
|
+
if (e.error || !e.data?.publishApplicationVersion) throw e.error ?? Error(h("devportal.versionPublishFailed", "Failed to submit version for review"));
|
|
398
|
+
K(h("devportal.nodeLifecycle.submitted", "Submitted for platform review. It deploys to the Node Store as soon as it is approved."));
|
|
399
|
+
}
|
|
400
|
+
} catch (e) {
|
|
401
|
+
W(e instanceof Error ? e.message : h("devportal.nodeLifecycle.deployFailed", "Deploy failed"));
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}, Le = async () => {
|
|
405
|
+
if (F) try {
|
|
406
|
+
await navigator.clipboard.writeText(F.id), q(!0), window.setTimeout(() => q(!1), 2e3);
|
|
407
|
+
} catch {
|
|
408
|
+
q(!1);
|
|
409
|
+
}
|
|
410
|
+
}, Q = `${v}/apps/${g}/versions`;
|
|
411
|
+
if (ye && !k) return /* @__PURE__ */ T(r, {});
|
|
412
|
+
if (A && !k) return /* @__PURE__ */ T(c, {
|
|
413
|
+
title: h("devportal.nodeLifecycle.title", "Publish a custom node"),
|
|
414
|
+
backLink: Q,
|
|
415
|
+
backLabel: h("devportal.backToVersions", "Back to versions"),
|
|
416
|
+
children: /* @__PURE__ */ T(i, {
|
|
417
|
+
title: h("devportal.nodeLifecycle.loadFailed", "Could not load this version"),
|
|
418
|
+
description: A.message
|
|
419
|
+
})
|
|
420
|
+
});
|
|
421
|
+
if (!N || !F || !R || N.appType !== "NODE") return /* @__PURE__ */ T(c, {
|
|
422
|
+
title: h("devportal.nodeLifecycle.title", "Publish a custom node"),
|
|
423
|
+
backLink: Q,
|
|
424
|
+
backLabel: h("devportal.backToVersions", "Back to versions"),
|
|
425
|
+
children: /* @__PURE__ */ T(i, {
|
|
426
|
+
title: h("devportal.nodeLifecycle.notFound", "Custom node version not found"),
|
|
427
|
+
description: h("devportal.nodeLifecycle.notFoundDescription", "This page shows the lifecycle of a version of a Node application. Pick a version from the versions page.")
|
|
428
|
+
})
|
|
429
|
+
});
|
|
430
|
+
let $ = F.status.toLowerCase(), Re = $ === "draft" || $ === "rejected", ze = Oe || Ae, Be = !!Z || ze || J, [Ve, He] = Z ? be[Z] : ["", ""], Ue = L === "private" ? h("devportal.nodeLifecycle.deployPrivate", "Deploy to my organization") : Fe ? h("devportal.nodeLifecycle.continueToStore", "Continue to store submission") : h("devportal.nodeLifecycle.submitToStore", "Submit for review");
|
|
431
|
+
return /* @__PURE__ */ E(c, {
|
|
432
|
+
title: /* @__PURE__ */ E("span", {
|
|
433
|
+
className: "flex flex-col gap-2",
|
|
434
|
+
children: [/* @__PURE__ */ T("span", {
|
|
435
|
+
className: "w-fit rounded-md bg-status-info-bg-subtle px-2 py-0.5 text-xs font-semibold uppercase tracking-wide text-status-info-text",
|
|
436
|
+
children: h("devportal.nodeLifecycle.badge", "Custom node")
|
|
437
|
+
}), /* @__PURE__ */ E("span", { children: [
|
|
438
|
+
h("devportal.nodeLifecycle.title", "Publish a custom node"),
|
|
439
|
+
" · ",
|
|
440
|
+
/* @__PURE__ */ E("span", {
|
|
441
|
+
className: "font-mono",
|
|
442
|
+
children: [
|
|
443
|
+
N.slug,
|
|
444
|
+
" v",
|
|
445
|
+
F.version
|
|
446
|
+
]
|
|
447
|
+
})
|
|
448
|
+
] })]
|
|
449
|
+
}),
|
|
450
|
+
backLink: Q,
|
|
451
|
+
backLabel: h("devportal.backToVersions", "Back to versions"),
|
|
452
|
+
purpose: h("devportal.nodeLifecycle.purpose", "Every custom node goes through the same five stages before workflows can use it. Validation, the sandbox build and the operation tests run automatically after you upload the package."),
|
|
453
|
+
fullWidth: !0,
|
|
454
|
+
children: [
|
|
455
|
+
/* @__PURE__ */ E("div", {
|
|
456
|
+
className: "flex flex-wrap items-center gap-2 text-sm text-text-secondary",
|
|
457
|
+
children: [
|
|
458
|
+
/* @__PURE__ */ T("span", { children: h("devportal.nodeLifecycle.versionId", "Version ID") }),
|
|
459
|
+
/* @__PURE__ */ T("code", {
|
|
460
|
+
className: "rounded-md border border-border-seam bg-bg-sunken px-2 py-0.5 font-mono text-text-primary",
|
|
461
|
+
"data-testid": "node-lifecycle-version-id",
|
|
462
|
+
children: F.id
|
|
463
|
+
}),
|
|
464
|
+
/* @__PURE__ */ T("button", {
|
|
465
|
+
type: "button",
|
|
466
|
+
onClick: Le,
|
|
467
|
+
"aria-label": h("devportal.nodeLifecycle.copyVersionId", "Copy version ID"),
|
|
468
|
+
className: "rounded-md p-1 hover:bg-accent",
|
|
469
|
+
children: T(Ne ? p : de, { size: 14 })
|
|
470
|
+
})
|
|
471
|
+
]
|
|
472
|
+
}),
|
|
473
|
+
U && /* @__PURE__ */ E("div", {
|
|
474
|
+
role: "alert",
|
|
475
|
+
className: "flex items-start gap-2 rounded-md bg-status-error-bg-subtle px-4 py-3 text-sm text-status-error-text",
|
|
476
|
+
children: [/* @__PURE__ */ T(ce, {
|
|
477
|
+
size: 16,
|
|
478
|
+
className: "mt-0.5 shrink-0"
|
|
479
|
+
}), U]
|
|
480
|
+
}),
|
|
481
|
+
G && /* @__PURE__ */ E("div", {
|
|
482
|
+
role: "status",
|
|
483
|
+
className: "flex items-start gap-2 rounded-md bg-status-success-bg-subtle px-4 py-3 text-sm text-status-success-text",
|
|
484
|
+
children: [/* @__PURE__ */ T(m, {
|
|
485
|
+
size: 16,
|
|
486
|
+
className: "mt-0.5 shrink-0"
|
|
487
|
+
}), G]
|
|
488
|
+
}),
|
|
489
|
+
/* @__PURE__ */ E("section", {
|
|
490
|
+
className: "rounded-card border border-border-seam bg-bg-surface p-5",
|
|
491
|
+
children: [/* @__PURE__ */ T(Se, {
|
|
492
|
+
lifecycle: R,
|
|
493
|
+
tr: h
|
|
494
|
+
}), $ === "rejected" && F.reviewNotes && /* @__PURE__ */ E("p", {
|
|
495
|
+
className: "mt-4 rounded-md bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text",
|
|
496
|
+
children: [
|
|
497
|
+
h("devportal.nodeLifecycle.reviewNotes", "Reviewer notes:"),
|
|
498
|
+
" ",
|
|
499
|
+
F.reviewNotes
|
|
500
|
+
]
|
|
501
|
+
})]
|
|
502
|
+
}),
|
|
503
|
+
/* @__PURE__ */ E("section", {
|
|
504
|
+
className: "flex flex-col gap-3 rounded-card border border-border-seam bg-bg-surface p-5 sm:flex-row sm:items-center sm:justify-between",
|
|
505
|
+
children: [/* @__PURE__ */ E("div", {
|
|
506
|
+
className: "flex items-center gap-3",
|
|
507
|
+
children: [/* @__PURE__ */ T(C, {
|
|
508
|
+
size: 18,
|
|
509
|
+
className: "text-text-secondary"
|
|
510
|
+
}), /* @__PURE__ */ E("div", {
|
|
511
|
+
className: "flex flex-col",
|
|
512
|
+
children: [
|
|
513
|
+
/* @__PURE__ */ T("span", {
|
|
514
|
+
className: "text-sm font-medium",
|
|
515
|
+
children: F.packageUrl ? h("devportal.nodeLifecycle.packageAttached", "Package attached") : h("devportal.nodeLifecycle.packageMissing", "No package yet")
|
|
516
|
+
}),
|
|
517
|
+
/* @__PURE__ */ T("span", {
|
|
518
|
+
className: "text-xs text-text-secondary",
|
|
519
|
+
children: F.packageUrl ? [F.packageSize && h("devportal.nodeLifecycle.packageSize", "{{size}} KB", { size: Math.max(1, Math.round(Number(F.packageSize) / 1024)) }), F.packageHash && `sha256 ${F.packageHash.slice(0, 12)}…`].filter(Boolean).join(" · ") : h("devportal.nodeLifecycle.packageHint", "A .zip with manifest.json and the node's server (fluidgrids-node new scaffolds one).")
|
|
520
|
+
}),
|
|
521
|
+
B && /* @__PURE__ */ T("span", {
|
|
522
|
+
className: "text-xs text-status-info-text",
|
|
523
|
+
children: h("devportal.nodeLifecycle.uploading", "Uploading… {{progress}}%", { progress: Math.round(Me) })
|
|
524
|
+
}),
|
|
525
|
+
V && /* @__PURE__ */ T("span", {
|
|
526
|
+
className: "text-xs text-status-error-text",
|
|
527
|
+
children: V
|
|
528
|
+
})
|
|
529
|
+
]
|
|
530
|
+
})]
|
|
531
|
+
}), Re && O && /* @__PURE__ */ E(_e, { children: [/* @__PURE__ */ T("input", {
|
|
532
|
+
ref: H,
|
|
533
|
+
type: "file",
|
|
534
|
+
accept: ".zip,application/zip",
|
|
535
|
+
className: "hidden",
|
|
536
|
+
"data-testid": "node-lifecycle-zip-input",
|
|
537
|
+
onChange: Pe
|
|
538
|
+
}), /* @__PURE__ */ E("button", {
|
|
539
|
+
type: "button",
|
|
540
|
+
disabled: B || J,
|
|
541
|
+
onClick: () => H.current?.click(),
|
|
542
|
+
className: "inline-flex items-center gap-2 rounded-md border border-border-seam px-4 py-2 text-sm font-medium hover:bg-accent disabled:opacity-50",
|
|
543
|
+
children: [B ? /* @__PURE__ */ T(y, {
|
|
544
|
+
size: 16,
|
|
545
|
+
className: "animate-spin"
|
|
546
|
+
}) : /* @__PURE__ */ T(C, { size: 16 }), F.packageUrl ? h("devportal.nodeLifecycle.replaceZip", "Replace ZIP") : h("devportal.nodeLifecycle.uploadZip", "Upload ZIP")]
|
|
547
|
+
})] })]
|
|
548
|
+
}),
|
|
549
|
+
/* @__PURE__ */ E("div", {
|
|
550
|
+
className: "grid grid-cols-1 gap-4 lg:grid-cols-2",
|
|
551
|
+
children: [/* @__PURE__ */ T(Ce, {
|
|
552
|
+
lifecycle: R,
|
|
553
|
+
tr: h
|
|
554
|
+
}), /* @__PURE__ */ T(we, {
|
|
555
|
+
manifest: F.manifest,
|
|
556
|
+
tr: h
|
|
557
|
+
})]
|
|
558
|
+
}),
|
|
559
|
+
/* @__PURE__ */ E("section", {
|
|
560
|
+
className: "flex flex-col gap-4 rounded-card border border-border-seam bg-bg-surface p-5 lg:flex-row lg:items-center lg:justify-between",
|
|
561
|
+
"data-testid": "node-lifecycle-deploy",
|
|
562
|
+
children: [/* @__PURE__ */ E("div", {
|
|
563
|
+
className: "flex flex-col gap-2",
|
|
564
|
+
children: [
|
|
565
|
+
/* @__PURE__ */ T("span", {
|
|
566
|
+
className: "text-sm font-semibold",
|
|
567
|
+
children: h("devportal.nodeLifecycle.visibility", "Visibility")
|
|
568
|
+
}),
|
|
569
|
+
/* @__PURE__ */ T("div", {
|
|
570
|
+
role: "radiogroup",
|
|
571
|
+
"aria-label": h("devportal.nodeLifecycle.visibility", "Visibility"),
|
|
572
|
+
className: "inline-flex w-fit overflow-hidden rounded-md border border-border-seam",
|
|
573
|
+
children: [[
|
|
574
|
+
"private",
|
|
575
|
+
/* @__PURE__ */ T(pe, { size: 14 }, "i"),
|
|
576
|
+
h("devportal.nodeLifecycle.private", "Workspace-private")
|
|
577
|
+
], [
|
|
578
|
+
"store",
|
|
579
|
+
/* @__PURE__ */ T(fe, { size: 14 }, "i"),
|
|
580
|
+
h("devportal.nodeLifecycle.store", "Submit to store")
|
|
581
|
+
]].map(([e, t, r]) => {
|
|
582
|
+
let i = L === e;
|
|
583
|
+
return /* @__PURE__ */ E("span", {
|
|
584
|
+
role: "radio",
|
|
585
|
+
"aria-checked": i,
|
|
586
|
+
"aria-disabled": !i,
|
|
587
|
+
"data-visibility": e,
|
|
588
|
+
className: n("inline-flex items-center gap-2 px-4 py-2 text-sm", i ? "bg-status-info-bg-subtle font-medium text-status-info-text" : "text-text-secondary"),
|
|
589
|
+
children: [t, r]
|
|
590
|
+
}, e);
|
|
591
|
+
})
|
|
592
|
+
}),
|
|
593
|
+
/* @__PURE__ */ E("p", {
|
|
594
|
+
className: "max-w-xl text-xs text-text-secondary",
|
|
595
|
+
children: [
|
|
596
|
+
L === "private" ? h("devportal.nodeLifecycle.privateHint", "Private nodes skip platform review: deploying approves the version for your organization and only its workspaces can install it.") : h("devportal.nodeLifecycle.storeHint", "Store nodes are reviewed by the platform team and deploy to the public Node Store once approved."),
|
|
597
|
+
" ",
|
|
598
|
+
/* @__PURE__ */ T("button", {
|
|
599
|
+
type: "button",
|
|
600
|
+
className: "font-medium text-status-info-text hover:underline",
|
|
601
|
+
onClick: () => X(`/apps/${g}/edit`),
|
|
602
|
+
children: h("devportal.nodeLifecycle.changeVisibility", "Change visibility")
|
|
603
|
+
})
|
|
604
|
+
]
|
|
605
|
+
})
|
|
606
|
+
]
|
|
607
|
+
}), /* @__PURE__ */ E("div", {
|
|
608
|
+
className: "flex flex-col items-stretch gap-2 lg:items-end",
|
|
609
|
+
children: [
|
|
610
|
+
/* @__PURE__ */ E("div", {
|
|
611
|
+
className: "flex flex-wrap gap-2",
|
|
612
|
+
children: [/* @__PURE__ */ E("button", {
|
|
613
|
+
type: "button",
|
|
614
|
+
onClick: () => X(`/apps/${g}/versions`),
|
|
615
|
+
className: "inline-flex items-center justify-center gap-2 rounded-md border border-border-seam px-4 py-2 text-sm font-medium hover:bg-accent",
|
|
616
|
+
children: [/* @__PURE__ */ T(le, { size: 16 }), h("devportal.nodeLifecycle.allVersions", "All versions")]
|
|
617
|
+
}), R.steps[4].status !== "complete" && /* @__PURE__ */ E("button", {
|
|
618
|
+
type: "button",
|
|
619
|
+
onClick: Ie,
|
|
620
|
+
disabled: Be,
|
|
621
|
+
"aria-disabled": Be,
|
|
622
|
+
"data-testid": "node-lifecycle-deploy-button",
|
|
623
|
+
className: "inline-flex items-center justify-center gap-2 rounded-md bg-action-primary-bg px-5 py-2 text-sm font-medium text-action-primary-text hover:bg-action-primary-bg/90 disabled:cursor-not-allowed disabled:opacity-50",
|
|
624
|
+
children: [ze ? /* @__PURE__ */ T(y, {
|
|
625
|
+
size: 16,
|
|
626
|
+
className: "animate-spin"
|
|
627
|
+
}) : T(L === "private" ? ue : me, { size: 16 }), Ue]
|
|
628
|
+
})]
|
|
629
|
+
}),
|
|
630
|
+
Z && R.steps[4].status !== "complete" && /* @__PURE__ */ T("p", {
|
|
631
|
+
className: "max-w-sm text-xs text-text-secondary lg:text-right",
|
|
632
|
+
"data-testid": "node-lifecycle-deploy-blocker",
|
|
633
|
+
"data-blocker": Z,
|
|
634
|
+
children: h(Ve, He)
|
|
635
|
+
}),
|
|
636
|
+
R.steps[4].status === "complete" && /* @__PURE__ */ E("p", {
|
|
637
|
+
className: "inline-flex items-center gap-1 text-sm font-medium text-status-success-text",
|
|
638
|
+
children: [/* @__PURE__ */ T(m, { size: 16 }), xe(h, R.steps[4])]
|
|
639
|
+
})
|
|
640
|
+
]
|
|
641
|
+
})]
|
|
642
|
+
})
|
|
643
|
+
]
|
|
644
|
+
});
|
|
645
|
+
};
|
|
646
|
+
//#endregion
|
|
647
|
+
export { M as NodeLifecyclePage };
|
|
648
|
+
|
|
649
|
+
//# sourceMappingURL=NodeLifecyclePage.js.map
|