@burdenoff/fluidgrids-fe-sdk 2026.1112.6 → 2026.1112.8
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/{AiStudioPage-BSLdKT0H.js → AiStudioPage-CtgPSPyc.js} +5 -5
- package/dist/ConfirmActionDialog-D9Pir3bc.js +30 -0
- package/dist/{DataSinkDashboardPage-kyzcjpzL.js → DataSinkDashboardPage-Dt3xTBb8.js} +1 -1
- package/dist/DataTablesPage-2xTLe_jk.js +2880 -0
- package/dist/{EntityTagPicker-dxfzv8aO.js → EntityTagPicker-CuZAMby_.js} +1 -1
- package/dist/{ExecutionDetailPage-B9eEep77.js → ExecutionDetailPage-CL-w9c3L.js} +13 -12
- package/dist/{ExecutionsListPage-DuuPSVEj.js → ExecutionsListPage-Bf6Cvsnz.js} +9 -8
- package/dist/{FailureTriagePanel-D4lJ4zqQ.js → FailureTriagePanel-BjatYyAa.js} +1 -1
- package/dist/{FluidGridsProvider-B1hgCbxG.js → FluidGridsProvider-TQ-aDPtn.js} +3 -3
- package/dist/{HistoryPage-C7NwkVNC.js → HistoryPage-s9pl5gyl.js} +2 -2
- package/dist/{InsightsPage-D9B_qW8e.js → InsightsPage-CtjJCky-.js} +4 -4
- package/dist/{MissingNodesInstallModal-BkkgeFeN.js → MissingNodesInstallModal-BCbhddk4.js} +1 -1
- package/dist/{NodesPage-BEeUbIts.js → NodesPage-BSNpOUMX.js} +2 -2
- package/dist/OpenTemplateAsCodeButton-BgvgDaVe.js +94 -0
- package/dist/RunActionsMenu-DmO14hEE.js +106 -0
- package/dist/RunnersPage-CvAPHdfU.js +673 -0
- package/dist/{SettingsPage-k21044-Z.js → SettingsPage-ywyjIAL8.js} +6 -6
- package/dist/{TagFilterSelect-CqhxcDjh.js → TagFilterSelect-DcusTt1p.js} +1 -1
- package/dist/{TaskQueuesPage-B86p51gH.js → TaskQueuesPage-C2dkenVF.js} +2 -2
- package/dist/{TemplateCard-DanOe65C.js → TemplateCard-XBc0qEA4.js} +214 -13
- package/dist/{TemplateConfigurationModal-CeMpPEhT.js → TemplateConfigurationModal-Dl_7RaCt.js} +20 -11
- package/dist/{TemplateDetailPanel-DnoA6mC3.js → TemplateDetailPanel-0Cc6jguU.js} +1 -1
- package/dist/{TemplatePreview-BFMsDQif.js → TemplatePreview-CRLUX5yI.js} +23 -14
- package/dist/{TemplatesPage-C7f2xq12.js → TemplatesPage-wClKZLO4.js} +4 -4
- package/dist/{VersionDiffDialog-pLpG_I1r.js → VersionDiffDialog-c27yet_-.js} +1 -1
- package/dist/{WorkflowBuilder-B8PtcT0Q.js → WorkflowBuilder-CK6c0eRp.js} +8 -8
- package/dist/{WorkflowBuilder-D9W8hQTO.js → WorkflowBuilder-qRGFtXJG.js} +3 -3
- package/dist/{WorkflowProposalCard-BjYAZH3q.js → WorkflowProposalCard-BvmJ5ea8.js} +1 -1
- package/dist/{WorkflowSearchRedirect-iPQBL6WO.js → WorkflowSearchRedirect-BGKduhfZ.js} +1 -1
- package/dist/{WorkflowShareDialog-DB-qJLB2.js → WorkflowShareDialog-BRwTF9QB.js} +1 -1
- package/dist/{WorkflowsList-rOxlI49U.js → WorkflowsList-Bocag4TX.js} +9 -8
- package/dist/{agentTools-DlPHMfhA.js → agentTools-BkQsycAp.js} +3 -3
- package/dist/{api-JpNuowX4.js → api-Dw8nfVRD.js} +1 -1
- package/dist/{api-Dvitj1aT.js → api-m8hX_l2k.js} +1 -1
- package/dist/{canvasNoteTools-CkAsMSvt.js → canvasNoteTools-U7j1z7GR.js} +2 -2
- package/dist/{code-editor-field-yJZEDJBi.js → code-editor-field-CWGZyNGM.js} +1 -1
- package/dist/executions.js +2 -2
- package/dist/{feature-flags-DM5myWaD.js → feature-flags-B_b8PJ6Z.js} +63 -3
- package/dist/flags.d.ts +1 -1
- package/dist/flags.js +1 -1
- package/dist/{flow-builder-DUkCKl-S.js → flow-builder-9jDNwkID.js} +509 -296
- package/dist/{graphql-operation-types-z2oXfQvM.js → graphql-operation-types-DZVhCBEi.js} +250 -1
- package/dist/history.js +1 -1
- package/dist/{index-BcdtKBM-.d.ts → index-B4g88tCa.d.ts} +15 -1
- package/dist/{index-u-kM0seP.d.ts → index-rj-TznII.d.ts} +30 -2
- package/dist/index.d.ts +3 -3
- package/dist/index.js +34 -34
- package/dist/{node-detail-view-ApMQwQRQ.js → node-detail-view-C1yupyvL.js} +9 -9
- package/dist/{node-editor-tab-body-DIcmar84.js → node-editor-tab-body-BtxSQPtX.js} +3 -3
- package/dist/{node-endpoint-configs-typvqw2c.js → node-endpoint-configs-BI7zc8eM.js} +1 -1
- package/dist/nodes.js +1 -1
- package/dist/observability.d.ts +1 -1
- package/dist/observability.js +2 -2
- package/dist/{popover-DOeSGQOG.js → popover-BaYffpTw.js} +5 -2
- package/dist/{quick-config-panel-Pm5nkZVr.js → quick-config-panel-BvlhLiQp.js} +3 -3
- package/dist/{schedule-panel-Dizqz9eA.js → schedule-panel-D5VdzW2c.js} +8 -8
- package/dist/settings.js +1 -1
- package/dist/{sidebar-node-editor-BNub2vUq.js → sidebar-node-editor-BU4rJwvm.js} +3 -3
- package/dist/templates.js +2 -2
- package/dist/{useAgentDefinitions-Uy6nhpKN.js → useAgentDefinitions-B4sw7bLw.js} +1 -1
- package/dist/{useDurableParity-Cb9nOdE8.js → useDurableParity-B3h8jqP0.js} +5 -103
- package/dist/{useEntityTags-D5C0tdLs.js → useEntityTags-BpDeLhzV.js} +1 -1
- package/dist/{useExecutions-DJXtbA15.js → useExecutions-BbkBSYpS.js} +2 -2
- package/dist/{useObservability-Dfgh4yjv.js → useObservability-BASo2sA3.js} +1 -1
- package/dist/{useRunHistory-BZQ3t68Q.js → useRunHistory-C3Pv_SJW.js} +2 -2
- package/dist/useWorkflowCodeExport-k5Emm4ZS.js +226 -0
- package/dist/{useWorkflows-CP-d3ygY.js → useWorkflows-CRUlQBd3.js} +2 -2
- package/dist/workflow-builder.js +4 -4
- package/dist/workflow-code-transfer-Cshsgf2H.js +375 -0
- package/dist/workflow-host.d.ts +1 -1
- package/dist/workflow-host.js +1 -1
- package/dist/workflow-pages.d.ts +1 -1
- package/dist/workflow-pages.js +17 -17
- package/dist/workflow-transfer-CQnQC-ke.js +104 -0
- package/dist/workflows-list.js +1 -1
- package/package.json +1 -1
- package/dist/DataTablesPage-Dm-dzVPD.js +0 -1698
- package/dist/QuotaExhaustedDialog-Bj7AG_0y.js +0 -55
- package/dist/RunnersPage-D9Bgod_d.js +0 -467
- package/dist/useWorkflowCodeExport-D0zapXXm.js +0 -643
|
@@ -0,0 +1,673 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { t as __exportAll } from "./rolldown-runtime-hDbaFkMy.js";
|
|
3
|
+
import { m as describeOperationError } from "./client-C9XSzSXr.js";
|
|
4
|
+
import { r as useTr } from "./TranslationBridge-Da-TPgQm.js";
|
|
5
|
+
import { i as SdkPermissionButton, s as useFluidGridsPermission, t as FLUIDGRIDS_PERMISSIONS } from "./constants-dcxg6zG6.js";
|
|
6
|
+
import { a as useRunners, i as useRunnerActions, r as runnerInstallCommand, t as RunnerStatusPill } from "./RunnerStatusPill-Ctg4TJcP.js";
|
|
7
|
+
import { t as FluidGridsDocsLink } from "./FluidGridsDocsLink-JxkBpOeb.js";
|
|
8
|
+
import { t as ConfirmActionDialog } from "./ConfirmActionDialog-D9Pir3bc.js";
|
|
9
|
+
import { n as useNavigationV2 } from "./useNavigationV2-C2WeqN7d.js";
|
|
10
|
+
import { n as TechnicalDetails, t as RunActionsMenu } from "./RunActionsMenu-DmO14hEE.js";
|
|
11
|
+
import { useCallback, useRef, useState } from "react";
|
|
12
|
+
import { Icon } from "@iconify/react";
|
|
13
|
+
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
14
|
+
import { toast } from "sonner";
|
|
15
|
+
import { Badge, Card, CardHeader, Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, Input, Label, Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@burdenoff/fe-libs/ui";
|
|
16
|
+
import { Button as Button$1 } from "@burdenoff/fe-libs/button";
|
|
17
|
+
|
|
18
|
+
// src/modules/runners/pages/RunnersPage.tsx
|
|
19
|
+
/**
|
|
20
|
+
* Runners Page — self-hosted runners.
|
|
21
|
+
*
|
|
22
|
+
* A runner is a small program a customer installs on their own VM or laptop.
|
|
23
|
+
* It connects out to FluidGrids, and any workflow node whose Settings →
|
|
24
|
+
* "Run on" names it executes on that machine, inside a local sandbox.
|
|
25
|
+
*
|
|
26
|
+
* Adding a runner issues a token that is shown ONCE, inside a ready-to-paste
|
|
27
|
+
* install command; the dialog then waits for the runner to come online.
|
|
28
|
+
*/
|
|
29
|
+
var RunnersPage_exports = /* @__PURE__ */ __exportAll({
|
|
30
|
+
RunnersPage: () => RunnersPage,
|
|
31
|
+
describePrivateRule: () => describePrivateRule
|
|
32
|
+
});
|
|
33
|
+
function formatSeen(iso) {
|
|
34
|
+
if (!iso) return "—";
|
|
35
|
+
const seconds = Math.max(0, Math.round((Date.now() - new Date(iso).getTime()) / 1e3));
|
|
36
|
+
if (seconds < 60) return `${seconds}s ago`;
|
|
37
|
+
if (seconds < 3600) return `${Math.round(seconds / 60)}m ago`;
|
|
38
|
+
if (seconds < 86400) return `${Math.round(seconds / 3600)}h ago`;
|
|
39
|
+
return new Date(iso).toLocaleDateString();
|
|
40
|
+
}
|
|
41
|
+
/** Rules shown inline before folding the rest behind "+N more". */
|
|
42
|
+
const PRIVATE_NETWORK_INLINE = 3;
|
|
43
|
+
/** "10.0.5.12:5432" / "db.corp (all ports)" for one rule. */
|
|
44
|
+
function describePrivateRule(rule, allPorts) {
|
|
45
|
+
return rule.ports.length > 0 ? `${rule.target}:${rule.ports.join(",")}` : `${rule.target} (${allPorts})`;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* What a runner's nodes may reach besides the public internet. Read-only: the
|
|
49
|
+
* list is set on the runner machine (`fluidgrids-runner network allow`), never
|
|
50
|
+
* here, so a FluidGrids account cannot open a path into the customer's network.
|
|
51
|
+
*/
|
|
52
|
+
function PrivateNetworkCell({ rules }) {
|
|
53
|
+
const tr = useTr();
|
|
54
|
+
const [expanded, setExpanded] = useState(false);
|
|
55
|
+
if (rules.length === 0) return /* @__PURE__ */ jsx("span", {
|
|
56
|
+
"data-testid": "runner-private-network-none",
|
|
57
|
+
children: tr("fluidgrids.runners.publicOnly", "Public internet only")
|
|
58
|
+
});
|
|
59
|
+
const allPorts = tr("fluidgrids.runners.allPorts", "all ports");
|
|
60
|
+
const everyNode = tr("fluidgrids.runners.everyNode", "every node");
|
|
61
|
+
const hidden = rules.length - PRIVATE_NETWORK_INLINE;
|
|
62
|
+
const shown = expanded || hidden <= 0 ? rules : rules.slice(0, PRIVATE_NETWORK_INLINE);
|
|
63
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
64
|
+
"data-testid": "runner-private-network",
|
|
65
|
+
children: [/* @__PURE__ */ jsx("ul", {
|
|
66
|
+
className: "space-y-0.5",
|
|
67
|
+
children: shown.map((rule, index) => /* @__PURE__ */ jsxs("li", { children: [/* @__PURE__ */ jsx("span", {
|
|
68
|
+
className: "font-mono text-xs text-text-primary",
|
|
69
|
+
children: describePrivateRule(rule, allPorts)
|
|
70
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
71
|
+
className: "ml-1 text-xs",
|
|
72
|
+
children: rule.nodes.length > 0 ? rule.nodes.join(", ") : everyNode
|
|
73
|
+
})] }, `${rule.target}-${index}`))
|
|
74
|
+
}), hidden > 0 && /* @__PURE__ */ jsx(Button$1, {
|
|
75
|
+
variant: "link",
|
|
76
|
+
size: "sm",
|
|
77
|
+
className: "h-auto p-0 text-xs",
|
|
78
|
+
"aria-expanded": expanded,
|
|
79
|
+
onClick: () => setExpanded((open) => !open),
|
|
80
|
+
"data-testid": "runner-private-network-toggle",
|
|
81
|
+
children: expanded ? tr("fluidgrids.runners.showFewer", "Show fewer") : tr("fluidgrids.runners.moreRules", "+{{count}} more", { count: hidden })
|
|
82
|
+
})]
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
/** Install command + copy button, with the "shown once" warning. */
|
|
86
|
+
function CopyableValue({ value, copied, testId, copyTestId, onCopied }) {
|
|
87
|
+
const tr = useTr();
|
|
88
|
+
const copy = useCallback(async () => {
|
|
89
|
+
try {
|
|
90
|
+
await navigator.clipboard.writeText(value);
|
|
91
|
+
onCopied?.();
|
|
92
|
+
toast.success(copied);
|
|
93
|
+
} catch {
|
|
94
|
+
toast.error(tr("fluidgrids.runners.copyFailed", "Could not copy — select the text and copy it manually"));
|
|
95
|
+
}
|
|
96
|
+
}, [
|
|
97
|
+
value,
|
|
98
|
+
copied,
|
|
99
|
+
onCopied,
|
|
100
|
+
tr
|
|
101
|
+
]);
|
|
102
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
103
|
+
className: "flex items-start gap-2",
|
|
104
|
+
children: [/* @__PURE__ */ jsx("pre", {
|
|
105
|
+
className: "flex-1 overflow-x-auto whitespace-pre-wrap break-all rounded-md border border-border bg-muted p-3 font-mono text-xs",
|
|
106
|
+
"data-testid": testId,
|
|
107
|
+
children: value
|
|
108
|
+
}), /* @__PURE__ */ jsxs(Button$1, {
|
|
109
|
+
variant: "outline",
|
|
110
|
+
size: "sm",
|
|
111
|
+
onClick: copy,
|
|
112
|
+
"data-testid": copyTestId,
|
|
113
|
+
children: [/* @__PURE__ */ jsx(Icon, {
|
|
114
|
+
icon: "lucide:copy",
|
|
115
|
+
className: "mr-1 h-4 w-4"
|
|
116
|
+
}), tr("fluidgrids.runners.copy", "Copy")]
|
|
117
|
+
})]
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Install command + token, kept apart: the command carries no token, and the
|
|
122
|
+
* installer asks for it with hidden input — so the token never lands in shell
|
|
123
|
+
* history or the machine's process list.
|
|
124
|
+
*/
|
|
125
|
+
function InstallCommand({ issued, onTokenCopied }) {
|
|
126
|
+
const tr = useTr();
|
|
127
|
+
const v2 = useNavigationV2();
|
|
128
|
+
const command = runnerInstallCommand(issued.bridgeUrl);
|
|
129
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
130
|
+
className: "space-y-3",
|
|
131
|
+
children: [
|
|
132
|
+
/* @__PURE__ */ jsxs("div", {
|
|
133
|
+
className: "space-y-2",
|
|
134
|
+
children: [/* @__PURE__ */ jsx("p", {
|
|
135
|
+
className: "text-sm text-text-secondary",
|
|
136
|
+
children: tr("fluidgrids.runners.installHint", "1. Run this on the machine that should run your nodes (Linux, or a Mac with Apple silicon). It installs the runner and its sandbox, and starts it in the background.")
|
|
137
|
+
}), /* @__PURE__ */ jsx(CopyableValue, {
|
|
138
|
+
value: command,
|
|
139
|
+
copied: tr("fluidgrids.runners.copied", "Install command copied"),
|
|
140
|
+
testId: "runner-install-command",
|
|
141
|
+
copyTestId: "runner-copy-command"
|
|
142
|
+
})]
|
|
143
|
+
}),
|
|
144
|
+
/* @__PURE__ */ jsxs("div", {
|
|
145
|
+
className: "space-y-2",
|
|
146
|
+
children: [/* @__PURE__ */ jsx("p", {
|
|
147
|
+
className: "text-sm text-text-secondary",
|
|
148
|
+
children: tr("fluidgrids.runners.tokenHint", "2. Paste this token when the installer asks for it. It is not part of the command, so it never ends up in your shell history.")
|
|
149
|
+
}), /* @__PURE__ */ jsx(CopyableValue, {
|
|
150
|
+
value: issued.token,
|
|
151
|
+
copied: tr("fluidgrids.runners.tokenCopied", "Token copied"),
|
|
152
|
+
testId: "runner-token",
|
|
153
|
+
copyTestId: "runner-copy-token",
|
|
154
|
+
onCopied: onTokenCopied
|
|
155
|
+
})]
|
|
156
|
+
}),
|
|
157
|
+
/* @__PURE__ */ jsx("p", {
|
|
158
|
+
className: "text-xs text-status-warning-text",
|
|
159
|
+
children: tr("fluidgrids.runners.tokenOnce", "The token is shown only once. Rotate it from the runner list if it is lost.")
|
|
160
|
+
}),
|
|
161
|
+
v2 ? /* @__PURE__ */ jsx(TechnicalDetails, {
|
|
162
|
+
"data-testid": "runner-token-file-hint",
|
|
163
|
+
children: /* @__PURE__ */ jsx("p", {
|
|
164
|
+
className: "text-xs text-text-secondary",
|
|
165
|
+
children: tr("fluidgrids.runners.tokenAutomation", "Installing without a terminal (cloud-init, scripts)? Save the token to a file only you can read and add --token-file <path> to the command.")
|
|
166
|
+
})
|
|
167
|
+
}) : /* @__PURE__ */ jsx("p", {
|
|
168
|
+
className: "text-xs text-text-secondary",
|
|
169
|
+
children: tr("fluidgrids.runners.tokenAutomation", "Installing without a terminal (cloud-init, scripts)? Save the token to a file only you can read and add --token-file <path> to the command.")
|
|
170
|
+
})
|
|
171
|
+
]
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Add-runner dialog: name → command → waits for the runner to connect.
|
|
176
|
+
* The body is mounted only while open, so every opening starts with an empty
|
|
177
|
+
* name, no issued key and no pending "close anyway" question.
|
|
178
|
+
*/
|
|
179
|
+
function AddRunnerDialog({ open, ...rest }) {
|
|
180
|
+
return open ? /* @__PURE__ */ jsx(AddRunnerBody, { ...rest }) : null;
|
|
181
|
+
}
|
|
182
|
+
function AddRunnerBody({ onOpenChange, runners, onCreated }) {
|
|
183
|
+
const tr = useTr();
|
|
184
|
+
const v2 = useNavigationV2();
|
|
185
|
+
const { createRunner, busy } = useRunnerActions();
|
|
186
|
+
const [name, setName] = useState("");
|
|
187
|
+
const [issued, setIssued] = useState(null);
|
|
188
|
+
const tokenCopied = useRef(false);
|
|
189
|
+
const [confirmingClose, setConfirmingClose] = useState(false);
|
|
190
|
+
const live = issued ? runners.find((r) => r.id === issued.runner.id) : void 0;
|
|
191
|
+
const requestOpenChange = useCallback((next) => {
|
|
192
|
+
if (!next && v2 && issued && !tokenCopied.current && live?.status !== "ONLINE") {
|
|
193
|
+
setConfirmingClose(true);
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
onOpenChange(next);
|
|
197
|
+
}, [
|
|
198
|
+
issued,
|
|
199
|
+
live?.status,
|
|
200
|
+
onOpenChange,
|
|
201
|
+
v2
|
|
202
|
+
]);
|
|
203
|
+
const submit = useCallback(async () => {
|
|
204
|
+
try {
|
|
205
|
+
setIssued(await createRunner(name.trim()));
|
|
206
|
+
onCreated();
|
|
207
|
+
} catch (err) {
|
|
208
|
+
toast.error(describeOperationError(err, tr("fluidgrids.runners.createFailed", "Could not add the runner")));
|
|
209
|
+
}
|
|
210
|
+
}, [
|
|
211
|
+
createRunner,
|
|
212
|
+
name,
|
|
213
|
+
onCreated,
|
|
214
|
+
tr
|
|
215
|
+
]);
|
|
216
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Dialog, {
|
|
217
|
+
open: true,
|
|
218
|
+
onOpenChange: requestOpenChange,
|
|
219
|
+
children: /* @__PURE__ */ jsxs(DialogContent, {
|
|
220
|
+
className: "sm:max-w-2xl",
|
|
221
|
+
"data-testid": "add-runner-dialog",
|
|
222
|
+
children: [
|
|
223
|
+
/* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, { children: tr("fluidgrids.runners.addTitle", "Add a runner") }) }),
|
|
224
|
+
!issued ? /* @__PURE__ */ jsxs("div", {
|
|
225
|
+
className: "space-y-2",
|
|
226
|
+
children: [/* @__PURE__ */ jsx(Label, {
|
|
227
|
+
htmlFor: "runner-name",
|
|
228
|
+
children: tr("fluidgrids.runners.name", "Name")
|
|
229
|
+
}), /* @__PURE__ */ jsx(Input, {
|
|
230
|
+
id: "runner-name",
|
|
231
|
+
value: name,
|
|
232
|
+
maxLength: 100,
|
|
233
|
+
placeholder: tr("fluidgrids.runners.namePlaceholder", "e.g. build-server or my-laptop"),
|
|
234
|
+
onChange: (e) => setName(e.target.value),
|
|
235
|
+
onKeyDown: (e) => {
|
|
236
|
+
if (e.key === "Enter" && name.trim()) submit();
|
|
237
|
+
},
|
|
238
|
+
"data-testid": "runner-name-input"
|
|
239
|
+
})]
|
|
240
|
+
}) : /* @__PURE__ */ jsxs("div", {
|
|
241
|
+
className: "space-y-4",
|
|
242
|
+
children: [/* @__PURE__ */ jsx(InstallCommand, {
|
|
243
|
+
issued,
|
|
244
|
+
onTokenCopied: () => tokenCopied.current = true
|
|
245
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
246
|
+
className: "flex items-center gap-2 text-sm",
|
|
247
|
+
"data-testid": "runner-connect-status",
|
|
248
|
+
children: live?.status === "ONLINE" ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Icon, {
|
|
249
|
+
icon: "lucide:check-circle-2",
|
|
250
|
+
className: "h-4 w-4 text-status-success-text"
|
|
251
|
+
}), tr("fluidgrids.runners.connected", "Connected. You can now pick this runner in a node's Settings → Run on.")] }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Icon, {
|
|
252
|
+
icon: "lucide:loader-2",
|
|
253
|
+
className: "h-4 w-4 animate-spin text-text-secondary"
|
|
254
|
+
}), tr("fluidgrids.runners.waiting", "Waiting for the runner to connect…")] })
|
|
255
|
+
})]
|
|
256
|
+
}),
|
|
257
|
+
/* @__PURE__ */ jsx(DialogFooter, { children: !issued ? /* @__PURE__ */ jsx(Button$1, {
|
|
258
|
+
onClick: submit,
|
|
259
|
+
disabled: busy || !name.trim(),
|
|
260
|
+
"data-testid": "runner-create-submit",
|
|
261
|
+
children: tr("fluidgrids.runners.create", "Create runner")
|
|
262
|
+
}) : /* @__PURE__ */ jsx(Button$1, {
|
|
263
|
+
variant: "outline",
|
|
264
|
+
onClick: () => requestOpenChange(false),
|
|
265
|
+
"data-testid": "runner-dialog-done",
|
|
266
|
+
children: tr("fluidgrids.runners.done", "Done")
|
|
267
|
+
}) })
|
|
268
|
+
]
|
|
269
|
+
})
|
|
270
|
+
}), v2 && /* @__PURE__ */ jsx(ConfirmActionDialog, {
|
|
271
|
+
open: confirmingClose,
|
|
272
|
+
onOpenChange: setConfirmingClose,
|
|
273
|
+
title: tr("fluidgrids.runners.closeUncopiedTitle", "Close without copying the key?"),
|
|
274
|
+
description: tr("fluidgrids.runners.closeUncopiedBody", "The connection key is shown only once. If you close this now, you will need to get a new one."),
|
|
275
|
+
confirmLabel: tr("fluidgrids.runners.closeAnyway", "Close anyway"),
|
|
276
|
+
cancelLabel: tr("fluidgrids.runners.goBack", "Go back"),
|
|
277
|
+
onConfirm: () => {
|
|
278
|
+
setConfirmingClose(false);
|
|
279
|
+
onOpenChange(false);
|
|
280
|
+
},
|
|
281
|
+
"data-testid": "confirm-close-uncopied"
|
|
282
|
+
})] });
|
|
283
|
+
}
|
|
284
|
+
/** One runner's row in Navigation v2: name, status, last seen and a "⋯" menu. */
|
|
285
|
+
function RunnerRowV2({ runner, acting, onRotate, onRemove }) {
|
|
286
|
+
const tr = useTr();
|
|
287
|
+
const canRotate = useFluidGridsPermission(FLUIDGRIDS_PERMISSIONS.SANDBOX_UPDATE).allowed;
|
|
288
|
+
const canRemove = useFluidGridsPermission(FLUIDGRIDS_PERMISSIONS.SANDBOX_DELETE).allowed;
|
|
289
|
+
const items = [];
|
|
290
|
+
if (canRotate) items.push({
|
|
291
|
+
id: "rotate",
|
|
292
|
+
label: tr("fluidgrids.runners.rotate", "Get a new connection key"),
|
|
293
|
+
icon: "mdi:key-outline",
|
|
294
|
+
onSelect: () => onRotate(runner),
|
|
295
|
+
disabled: acting
|
|
296
|
+
});
|
|
297
|
+
if (canRemove) items.push({
|
|
298
|
+
id: "remove",
|
|
299
|
+
label: tr("fluidgrids.runners.remove", "Remove"),
|
|
300
|
+
icon: "mdi:trash-can-outline",
|
|
301
|
+
onSelect: () => onRemove(runner),
|
|
302
|
+
disabled: acting,
|
|
303
|
+
destructive: true
|
|
304
|
+
});
|
|
305
|
+
return /* @__PURE__ */ jsxs(TableRow, {
|
|
306
|
+
"data-testid": "runner-row",
|
|
307
|
+
children: [
|
|
308
|
+
/* @__PURE__ */ jsxs(TableCell, { children: [/* @__PURE__ */ jsx("div", {
|
|
309
|
+
className: "font-medium text-text-primary",
|
|
310
|
+
children: runner.name
|
|
311
|
+
}), /* @__PURE__ */ jsx(TechnicalDetails, {
|
|
312
|
+
className: "mt-1",
|
|
313
|
+
children: /* @__PURE__ */ jsxs("dl", {
|
|
314
|
+
className: "grid gap-1 text-xs text-text-secondary sm:grid-cols-[auto_1fr]",
|
|
315
|
+
children: [
|
|
316
|
+
/* @__PURE__ */ jsx("dt", { children: tr("fluidgrids.runners.keyStartsWith", "Key starts with") }),
|
|
317
|
+
/* @__PURE__ */ jsxs("dd", {
|
|
318
|
+
className: "font-mono",
|
|
319
|
+
children: [runner.tokenPrefix, "…"]
|
|
320
|
+
}),
|
|
321
|
+
/* @__PURE__ */ jsx("dt", { children: tr("fluidgrids.runners.machine", "Machine") }),
|
|
322
|
+
/* @__PURE__ */ jsx("dd", { children: runner.hostname ? `${runner.hostname} · ${runner.os ?? "?"}/${runner.arch ?? "?"}` : "—" }),
|
|
323
|
+
/* @__PURE__ */ jsx("dt", { children: tr("fluidgrids.runners.sandbox", "Sandbox") }),
|
|
324
|
+
/* @__PURE__ */ jsxs("dd", { children: [runner.driver ? /* @__PURE__ */ jsx(Badge, {
|
|
325
|
+
variant: "outline",
|
|
326
|
+
children: runner.driver
|
|
327
|
+
}) : "—", runner.version && /* @__PURE__ */ jsxs("span", {
|
|
328
|
+
className: "ml-2",
|
|
329
|
+
children: ["v", runner.version]
|
|
330
|
+
})] }),
|
|
331
|
+
/* @__PURE__ */ jsx("dt", { children: tr("fluidgrids.runners.privateNetwork", "Private network") }),
|
|
332
|
+
/* @__PURE__ */ jsx("dd", { children: /* @__PURE__ */ jsx(PrivateNetworkCell, { rules: runner.privateNetwork ?? [] }) })
|
|
333
|
+
]
|
|
334
|
+
})
|
|
335
|
+
})] }),
|
|
336
|
+
/* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsx(RunnerStatusPill, { status: runner.status }) }),
|
|
337
|
+
/* @__PURE__ */ jsx(TableCell, {
|
|
338
|
+
className: "text-sm text-text-secondary",
|
|
339
|
+
children: formatSeen(runner.lastSeenAt)
|
|
340
|
+
}),
|
|
341
|
+
/* @__PURE__ */ jsx(TableCell, {
|
|
342
|
+
className: "text-right",
|
|
343
|
+
children: /* @__PURE__ */ jsx(RunActionsMenu, {
|
|
344
|
+
items,
|
|
345
|
+
label: tr("fluidgrids.runners.moreActions", "Runner actions"),
|
|
346
|
+
"data-testid": "runner-actions-menu"
|
|
347
|
+
})
|
|
348
|
+
})
|
|
349
|
+
]
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
function RunnersPage() {
|
|
353
|
+
const tr = useTr();
|
|
354
|
+
const v2 = useNavigationV2();
|
|
355
|
+
const [rotating, setRotating] = useState(null);
|
|
356
|
+
const rotatedCopied = useRef(false);
|
|
357
|
+
const [confirmingRotatedClose, setConfirmingRotatedClose] = useState(false);
|
|
358
|
+
const { runners, loading, error, refetch } = useRunners({ pollMs: 5e3 });
|
|
359
|
+
const { rotateToken, deleteRunner } = useRunnerActions();
|
|
360
|
+
const [actingId, setActingId] = useState(null);
|
|
361
|
+
const [adding, setAdding] = useState(false);
|
|
362
|
+
const [rotated, setRotated] = useState(null);
|
|
363
|
+
const [removing, setRemoving] = useState(null);
|
|
364
|
+
const handleRotate = useCallback(async (runner) => {
|
|
365
|
+
setActingId(runner.id);
|
|
366
|
+
try {
|
|
367
|
+
rotatedCopied.current = false;
|
|
368
|
+
setRotated(await rotateToken(runner.id));
|
|
369
|
+
refetch();
|
|
370
|
+
} catch (err) {
|
|
371
|
+
toast.error(describeOperationError(err, tr("fluidgrids.runners.rotateFailed", "Could not rotate the token")));
|
|
372
|
+
} finally {
|
|
373
|
+
setActingId(null);
|
|
374
|
+
}
|
|
375
|
+
}, [
|
|
376
|
+
refetch,
|
|
377
|
+
rotateToken,
|
|
378
|
+
tr
|
|
379
|
+
]);
|
|
380
|
+
const closeRotated = useCallback(() => {
|
|
381
|
+
if (v2 && rotated && !rotatedCopied.current) {
|
|
382
|
+
setConfirmingRotatedClose(true);
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
setRotated(null);
|
|
386
|
+
}, [rotated, v2]);
|
|
387
|
+
const handleRemove = useCallback(async () => {
|
|
388
|
+
if (!removing) return;
|
|
389
|
+
setActingId(removing.id);
|
|
390
|
+
try {
|
|
391
|
+
await deleteRunner(removing.id);
|
|
392
|
+
toast.success(tr("fluidgrids.runners.removed", "Runner removed"));
|
|
393
|
+
setRemoving(null);
|
|
394
|
+
refetch();
|
|
395
|
+
} catch (err) {
|
|
396
|
+
toast.error(describeOperationError(err, tr("fluidgrids.runners.removeFailed", "Could not remove the runner")));
|
|
397
|
+
} finally {
|
|
398
|
+
setActingId(null);
|
|
399
|
+
}
|
|
400
|
+
}, [
|
|
401
|
+
deleteRunner,
|
|
402
|
+
refetch,
|
|
403
|
+
removing,
|
|
404
|
+
tr
|
|
405
|
+
]);
|
|
406
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
407
|
+
className: "space-y-6 p-6",
|
|
408
|
+
"data-testid": "runners-page",
|
|
409
|
+
children: [
|
|
410
|
+
/* @__PURE__ */ jsxs("div", {
|
|
411
|
+
className: v2 ? "flex flex-col items-start gap-4 sm:flex-row sm:justify-between" : "flex items-start justify-between gap-4",
|
|
412
|
+
"data-tour": "fluidgrids-runners-header",
|
|
413
|
+
children: [/* @__PURE__ */ jsxs("div", { children: [
|
|
414
|
+
/* @__PURE__ */ jsx("h1", {
|
|
415
|
+
className: "text-2xl font-semibold text-text-primary",
|
|
416
|
+
children: tr("fluidgrids.runners.title", "Runners")
|
|
417
|
+
}),
|
|
418
|
+
/* @__PURE__ */ jsx("p", {
|
|
419
|
+
className: "mt-1 max-w-2xl text-sm text-text-secondary",
|
|
420
|
+
children: tr("fluidgrids.runners.subtitle", "Run workflow nodes on your own machines. A node set to Run on a runner executes there, inside a local sandbox; the rest of the workflow keeps running in FluidGrids.")
|
|
421
|
+
}),
|
|
422
|
+
/* @__PURE__ */ jsxs("p", {
|
|
423
|
+
className: "mt-1 max-w-2xl text-sm text-text-secondary",
|
|
424
|
+
"data-testid": "runners-private-network-hint",
|
|
425
|
+
children: [
|
|
426
|
+
tr("fluidgrids.runners.privateNetworkHint", "Nodes reach the public internet only. To let them reach something inside your network, open it on the runner machine:"),
|
|
427
|
+
" ",
|
|
428
|
+
/* @__PURE__ */ jsx("code", {
|
|
429
|
+
className: "rounded bg-muted px-1 font-mono text-xs text-text-primary",
|
|
430
|
+
children: "fluidgrids-runner network allow 10.0.5.12 --port 5432"
|
|
431
|
+
})
|
|
432
|
+
]
|
|
433
|
+
}),
|
|
434
|
+
/* @__PURE__ */ jsx(FluidGridsDocsLink, {
|
|
435
|
+
topic: "runners",
|
|
436
|
+
className: "mt-1"
|
|
437
|
+
})
|
|
438
|
+
] }), /* @__PURE__ */ jsx(SdkPermissionButton, {
|
|
439
|
+
permission: FLUIDGRIDS_PERMISSIONS.SANDBOX_CREATE,
|
|
440
|
+
deniedTooltip: tr("fluidgrids.runners.addDeniedTooltip", "You don't have permission to add runners"),
|
|
441
|
+
children: /* @__PURE__ */ jsxs(Button$1, {
|
|
442
|
+
onClick: () => setAdding(true),
|
|
443
|
+
"data-testid": "runner-add",
|
|
444
|
+
"data-tour": "fluidgrids-runners-add",
|
|
445
|
+
children: [/* @__PURE__ */ jsx(Icon, {
|
|
446
|
+
icon: "lucide:plus",
|
|
447
|
+
className: "mr-1 h-4 w-4"
|
|
448
|
+
}), tr("fluidgrids.runners.add", "Add runner")]
|
|
449
|
+
})
|
|
450
|
+
})]
|
|
451
|
+
}),
|
|
452
|
+
error && /* @__PURE__ */ jsx("div", {
|
|
453
|
+
role: "alert",
|
|
454
|
+
className: "rounded-md border border-status-error-border bg-status-error-bg-subtle p-3 text-sm text-status-error-text",
|
|
455
|
+
children: v2 ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("p", { children: tr("fluidgrids.runners.loadFailed", "We couldn't load your runners. Try again in a moment.") }), /* @__PURE__ */ jsx(TechnicalDetails, {
|
|
456
|
+
className: "mt-2",
|
|
457
|
+
children: /* @__PURE__ */ jsx("code", {
|
|
458
|
+
className: "break-words text-xs",
|
|
459
|
+
children: error.message
|
|
460
|
+
})
|
|
461
|
+
})] }) : error.message
|
|
462
|
+
}),
|
|
463
|
+
/* @__PURE__ */ jsx(Card, {
|
|
464
|
+
"data-tour": "fluidgrids-runners-table",
|
|
465
|
+
children: /* @__PURE__ */ jsx(CardHeader, {
|
|
466
|
+
className: "p-0",
|
|
467
|
+
children: /* @__PURE__ */ jsxs(Table, { children: [/* @__PURE__ */ jsx(TableHeader, { children: /* @__PURE__ */ jsxs(TableRow, { children: [
|
|
468
|
+
/* @__PURE__ */ jsx(TableHead, { children: tr("fluidgrids.runners.name", "Name") }),
|
|
469
|
+
/* @__PURE__ */ jsx(TableHead, { children: tr("fluidgrids.runners.status", "Status") }),
|
|
470
|
+
!v2 && /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
471
|
+
/* @__PURE__ */ jsx(TableHead, { children: tr("fluidgrids.runners.machine", "Machine") }),
|
|
472
|
+
/* @__PURE__ */ jsx(TableHead, { children: tr("fluidgrids.runners.sandbox", "Sandbox") }),
|
|
473
|
+
/* @__PURE__ */ jsx(TableHead, { children: tr("fluidgrids.runners.privateNetwork", "Private network") })
|
|
474
|
+
] }),
|
|
475
|
+
/* @__PURE__ */ jsx(TableHead, { children: tr("fluidgrids.runners.lastSeen", "Last seen") }),
|
|
476
|
+
/* @__PURE__ */ jsx(TableHead, {
|
|
477
|
+
className: "text-right",
|
|
478
|
+
children: tr("fluidgrids.runners.actions", "Actions")
|
|
479
|
+
})
|
|
480
|
+
] }) }), /* @__PURE__ */ jsxs(TableBody, { children: [
|
|
481
|
+
v2 && runners.map((runner) => /* @__PURE__ */ jsx(RunnerRowV2, {
|
|
482
|
+
runner,
|
|
483
|
+
acting: actingId === runner.id,
|
|
484
|
+
onRotate: setRotating,
|
|
485
|
+
onRemove: setRemoving
|
|
486
|
+
}, runner.id)),
|
|
487
|
+
!v2 && runners.map((runner) => /* @__PURE__ */ jsxs(TableRow, {
|
|
488
|
+
"data-testid": "runner-row",
|
|
489
|
+
children: [
|
|
490
|
+
/* @__PURE__ */ jsxs(TableCell, { children: [/* @__PURE__ */ jsx("div", {
|
|
491
|
+
className: "font-medium text-text-primary",
|
|
492
|
+
children: runner.name
|
|
493
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
494
|
+
className: "font-mono text-xs text-text-secondary",
|
|
495
|
+
children: [runner.tokenPrefix, "…"]
|
|
496
|
+
})] }),
|
|
497
|
+
/* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsx(RunnerStatusPill, { status: runner.status }) }),
|
|
498
|
+
/* @__PURE__ */ jsx(TableCell, {
|
|
499
|
+
className: "text-sm text-text-secondary",
|
|
500
|
+
children: runner.hostname ? `${runner.hostname} · ${runner.os ?? "?"}/${runner.arch ?? "?"}` : "—"
|
|
501
|
+
}),
|
|
502
|
+
/* @__PURE__ */ jsxs(TableCell, {
|
|
503
|
+
className: "text-sm text-text-secondary",
|
|
504
|
+
children: [runner.driver ? /* @__PURE__ */ jsx(Badge, {
|
|
505
|
+
variant: "outline",
|
|
506
|
+
children: runner.driver
|
|
507
|
+
}) : "—", runner.version && /* @__PURE__ */ jsxs("span", {
|
|
508
|
+
className: "ml-2 text-xs",
|
|
509
|
+
children: ["v", runner.version]
|
|
510
|
+
})]
|
|
511
|
+
}),
|
|
512
|
+
/* @__PURE__ */ jsx(TableCell, {
|
|
513
|
+
className: "text-sm text-text-secondary",
|
|
514
|
+
children: /* @__PURE__ */ jsx(PrivateNetworkCell, { rules: runner.privateNetwork ?? [] })
|
|
515
|
+
}),
|
|
516
|
+
/* @__PURE__ */ jsx(TableCell, {
|
|
517
|
+
className: "text-sm text-text-secondary",
|
|
518
|
+
children: formatSeen(runner.lastSeenAt)
|
|
519
|
+
}),
|
|
520
|
+
/* @__PURE__ */ jsxs(TableCell, {
|
|
521
|
+
className: "text-right",
|
|
522
|
+
children: [/* @__PURE__ */ jsx(SdkPermissionButton, {
|
|
523
|
+
permission: FLUIDGRIDS_PERMISSIONS.SANDBOX_UPDATE,
|
|
524
|
+
deniedTooltip: tr("fluidgrids.runners.rotateDeniedTooltip", "You don't have permission to rotate runner tokens"),
|
|
525
|
+
children: /* @__PURE__ */ jsx(Button$1, {
|
|
526
|
+
"data-agent": "confirm",
|
|
527
|
+
variant: "ghost",
|
|
528
|
+
size: "sm",
|
|
529
|
+
title: tr("fluidgrids.runners.rotate", "Rotate token"),
|
|
530
|
+
"aria-label": tr("fluidgrids.runners.rotate", "Rotate token"),
|
|
531
|
+
onClick: () => handleRotate(runner),
|
|
532
|
+
disabled: actingId === runner.id,
|
|
533
|
+
"data-testid": "runner-rotate",
|
|
534
|
+
children: /* @__PURE__ */ jsx(Icon, {
|
|
535
|
+
icon: "lucide:key-round",
|
|
536
|
+
className: "h-4 w-4"
|
|
537
|
+
})
|
|
538
|
+
})
|
|
539
|
+
}), /* @__PURE__ */ jsx(SdkPermissionButton, {
|
|
540
|
+
permission: FLUIDGRIDS_PERMISSIONS.SANDBOX_DELETE,
|
|
541
|
+
deniedTooltip: tr("fluidgrids.runners.removeDeniedTooltip", "You don't have permission to remove runners"),
|
|
542
|
+
children: /* @__PURE__ */ jsx(Button$1, {
|
|
543
|
+
variant: "ghost",
|
|
544
|
+
size: "sm",
|
|
545
|
+
title: tr("fluidgrids.runners.remove", "Remove"),
|
|
546
|
+
"aria-label": tr("fluidgrids.runners.remove", "Remove"),
|
|
547
|
+
onClick: () => setRemoving(runner),
|
|
548
|
+
disabled: actingId === runner.id,
|
|
549
|
+
"data-testid": "runner-remove",
|
|
550
|
+
children: /* @__PURE__ */ jsx(Icon, {
|
|
551
|
+
icon: "lucide:trash-2",
|
|
552
|
+
className: "h-4 w-4 text-destructive"
|
|
553
|
+
})
|
|
554
|
+
})
|
|
555
|
+
})]
|
|
556
|
+
})
|
|
557
|
+
]
|
|
558
|
+
}, runner.id)),
|
|
559
|
+
v2 && loading && runners.length === 0 && /* @__PURE__ */ jsx(TableRow, { children: /* @__PURE__ */ jsx(TableCell, {
|
|
560
|
+
colSpan: 4,
|
|
561
|
+
className: "py-10 text-center text-sm text-text-secondary",
|
|
562
|
+
"data-testid": "runners-loading",
|
|
563
|
+
children: tr("fluidgrids.runners.loading", "Loading runners…")
|
|
564
|
+
}) }),
|
|
565
|
+
!loading && runners.length === 0 && /* @__PURE__ */ jsx(TableRow, { children: /* @__PURE__ */ jsxs(TableCell, {
|
|
566
|
+
colSpan: v2 ? 4 : 7,
|
|
567
|
+
className: "py-10 text-center text-sm text-text-secondary",
|
|
568
|
+
children: [/* @__PURE__ */ jsx("p", { children: tr("fluidgrids.runners.empty", v2 ? "No runners yet. Add one to run steps on your own machine." : "No runners yet. Add one to run nodes on your own machine.") }), v2 && /* @__PURE__ */ jsx("div", {
|
|
569
|
+
className: "mt-3",
|
|
570
|
+
children: /* @__PURE__ */ jsx(SdkPermissionButton, {
|
|
571
|
+
permission: FLUIDGRIDS_PERMISSIONS.SANDBOX_CREATE,
|
|
572
|
+
deniedTooltip: tr("fluidgrids.runners.addDeniedTooltip", "You don't have permission to add runners"),
|
|
573
|
+
children: /* @__PURE__ */ jsxs(Button$1, {
|
|
574
|
+
onClick: () => setAdding(true),
|
|
575
|
+
"data-testid": "runner-empty-add",
|
|
576
|
+
children: [/* @__PURE__ */ jsx(Icon, {
|
|
577
|
+
icon: "lucide:plus",
|
|
578
|
+
className: "mr-1 h-4 w-4"
|
|
579
|
+
}), tr("fluidgrids.runners.add", "Add runner")]
|
|
580
|
+
})
|
|
581
|
+
})
|
|
582
|
+
})]
|
|
583
|
+
}) })
|
|
584
|
+
] })] })
|
|
585
|
+
})
|
|
586
|
+
}),
|
|
587
|
+
/* @__PURE__ */ jsx(AddRunnerDialog, {
|
|
588
|
+
open: adding,
|
|
589
|
+
onOpenChange: setAdding,
|
|
590
|
+
runners,
|
|
591
|
+
onCreated: () => void refetch()
|
|
592
|
+
}),
|
|
593
|
+
/* @__PURE__ */ jsx(Dialog, {
|
|
594
|
+
open: rotated !== null,
|
|
595
|
+
onOpenChange: (open) => !open && closeRotated(),
|
|
596
|
+
children: /* @__PURE__ */ jsxs(DialogContent, {
|
|
597
|
+
className: "sm:max-w-2xl",
|
|
598
|
+
"data-testid": "rotated-dialog",
|
|
599
|
+
children: [
|
|
600
|
+
/* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, { children: tr("fluidgrids.runners.rotatedTitle", v2 ? "Your new connection key" : "New token issued") }) }),
|
|
601
|
+
/* @__PURE__ */ jsx("p", {
|
|
602
|
+
className: "text-sm text-text-secondary",
|
|
603
|
+
children: tr("fluidgrids.runners.rotatedHint", v2 ? "The old key no longer works and the runner was disconnected. Run the command below on that machine again and paste the new key when it asks." : "The old token no longer works and the runner was disconnected. Re-run the command below on that machine and paste the new token when it asks.")
|
|
604
|
+
}),
|
|
605
|
+
rotated && /* @__PURE__ */ jsx(InstallCommand, {
|
|
606
|
+
issued: rotated,
|
|
607
|
+
onTokenCopied: () => rotatedCopied.current = true
|
|
608
|
+
}),
|
|
609
|
+
/* @__PURE__ */ jsx(DialogFooter, { children: /* @__PURE__ */ jsx(Button$1, {
|
|
610
|
+
variant: "outline",
|
|
611
|
+
onClick: () => closeRotated(),
|
|
612
|
+
children: tr("fluidgrids.runners.done", "Done")
|
|
613
|
+
}) })
|
|
614
|
+
]
|
|
615
|
+
})
|
|
616
|
+
}),
|
|
617
|
+
v2 && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(ConfirmActionDialog, {
|
|
618
|
+
open: rotating !== null,
|
|
619
|
+
onOpenChange: (open) => {
|
|
620
|
+
if (!open) setRotating(null);
|
|
621
|
+
},
|
|
622
|
+
title: tr("fluidgrids.runners.rotateConfirmTitle", "Get a new connection key for {{name}}?", { name: rotating?.name ?? "" }),
|
|
623
|
+
description: tr("fluidgrids.runners.rotateConfirmBody", "{{name}} is disconnected right away and its old key stops working. You will need to run the install command again on that machine with the new key.", { name: rotating?.name ?? "" }),
|
|
624
|
+
confirmLabel: tr("fluidgrids.runners.rotateConfirmAction", "Get a new key"),
|
|
625
|
+
cancelLabel: tr("fluidgrids.runners.rotateConfirmKeep", "Keep the current key"),
|
|
626
|
+
destructive: true,
|
|
627
|
+
busy: actingId !== null,
|
|
628
|
+
onConfirm: () => {
|
|
629
|
+
const runner = rotating;
|
|
630
|
+
setRotating(null);
|
|
631
|
+
if (runner) handleRotate(runner);
|
|
632
|
+
},
|
|
633
|
+
"data-testid": "confirm-rotate"
|
|
634
|
+
}), /* @__PURE__ */ jsx(ConfirmActionDialog, {
|
|
635
|
+
open: confirmingRotatedClose,
|
|
636
|
+
onOpenChange: setConfirmingRotatedClose,
|
|
637
|
+
title: tr("fluidgrids.runners.closeUncopiedTitle", "Close without copying the key?"),
|
|
638
|
+
description: tr("fluidgrids.runners.closeUncopiedBody", "The connection key is shown only once. If you close this now, you will need to get a new one."),
|
|
639
|
+
confirmLabel: tr("fluidgrids.runners.closeAnyway", "Close anyway"),
|
|
640
|
+
cancelLabel: tr("fluidgrids.runners.goBack", "Go back"),
|
|
641
|
+
onConfirm: () => {
|
|
642
|
+
setConfirmingRotatedClose(false);
|
|
643
|
+
setRotated(null);
|
|
644
|
+
},
|
|
645
|
+
"data-testid": "confirm-close-rotated"
|
|
646
|
+
})] }),
|
|
647
|
+
/* @__PURE__ */ jsx(Dialog, {
|
|
648
|
+
open: removing !== null,
|
|
649
|
+
onOpenChange: (open) => !open && setRemoving(null),
|
|
650
|
+
children: /* @__PURE__ */ jsxs(DialogContent, { children: [
|
|
651
|
+
/* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, { children: v2 && removing ? tr("fluidgrids.runners.removeTitle", "Remove {{name}}?", { name: removing.name }) : tr("fluidgrids.runners.removeTitle", "Remove this runner?") }) }),
|
|
652
|
+
/* @__PURE__ */ jsx("p", {
|
|
653
|
+
className: "text-sm text-text-secondary",
|
|
654
|
+
children: tr("fluidgrids.runners.removeHint", "It is disconnected and its token stops working. Nodes set to run on it will fail until you pick another runner or FluidGrids Cloud.")
|
|
655
|
+
}),
|
|
656
|
+
/* @__PURE__ */ jsxs(DialogFooter, { children: [/* @__PURE__ */ jsx(Button$1, {
|
|
657
|
+
variant: "outline",
|
|
658
|
+
onClick: () => setRemoving(null),
|
|
659
|
+
children: tr("fluidgrids.runners.cancel", "Cancel")
|
|
660
|
+
}), /* @__PURE__ */ jsx(Button$1, {
|
|
661
|
+
variant: "destructive",
|
|
662
|
+
onClick: handleRemove,
|
|
663
|
+
disabled: actingId !== null,
|
|
664
|
+
"data-testid": "runner-remove-confirm",
|
|
665
|
+
children: tr("fluidgrids.runners.remove", "Remove")
|
|
666
|
+
})] })
|
|
667
|
+
] })
|
|
668
|
+
})
|
|
669
|
+
]
|
|
670
|
+
});
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
export { RunnersPage_exports as n, RunnersPage as t };
|