@burdenoff/fluidgrids-fe-sdk 2026.1111.16 → 2026.1111.17
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/README.md +41 -0
- package/dist/AiStudioPage-kJHSsIcj.js +774 -0
- package/dist/ApprovalInboxPage-dbBDSJ-f.js +558 -0
- package/dist/DataSinkDashboardPage-1h2QsMzH.js +270 -0
- package/dist/DataTablesPage-BZy2z0LB.js +1690 -0
- package/dist/EntityTagPicker-BqRNsLCQ.js +135 -0
- package/dist/{ExecutionDetailPage-D-0_POAf.js → ExecutionDetailPage-BdcZmLT4.js} +799 -4420
- package/dist/ExecutionDetailPage-DvQ667OE.d.ts +10 -0
- package/dist/ExecutionsListPage-BCUJoAIE.js +2742 -0
- package/dist/{FailureTriagePanel-BHiduL7A.js → FailureTriagePanel-B9hDQymi.js} +4 -97
- package/dist/{FluidGridsProvider-DmvFADFa.js → FluidGridsProvider-dvZSNtSW.js} +10 -350
- package/dist/HistoryPage-BLoRpJ1R.d.ts +6 -0
- package/dist/{HistoryPage-BbUgxx1I.js → HistoryPage-U0tqupBN.js} +6 -4
- package/dist/HumanRequestCard-D-ooVPDn.js +439 -0
- package/dist/{InsightsPage-s6f5bU-8.js → InsightsPage-CALo16eB.js} +17 -328
- package/dist/ManagedAiPolicyAuthority-BxwJ3ptd.js +40 -0
- package/dist/{ManagedAiPolicyAuthority-CGux_DaV.d.ts → ManagedAiPolicyAuthority-DM3t3wNr.d.ts} +1 -5
- package/dist/ManagedAiPolicyAuthorityContext-CNkxIOZ1.js +10 -0
- package/dist/{MissingNodesInstallModal-B-9gHy2K.js → MissingNodesInstallModal-CMybsI8h.js} +3 -2
- package/dist/{NodesPage-ClvhUfbh.js → NodesPage-Bf5PhfBK.js} +7 -3
- package/dist/NodesPage-DEbnz9iU.d.ts +6 -0
- package/dist/{PublishCustomNodeAction-D2F7oN0S.js → PublishCustomNodeAction-5XXnSA3H.js} +3 -45
- package/dist/QuotaExhaustedDialog-7IFSaLyi.js +54 -0
- package/dist/RunnerStatusPill-Ctg4TJcP.js +187 -0
- package/dist/RunnersPage-CLCOCclc.js +467 -0
- package/dist/{ManagedAiPolicyAuthority-DsSaz-vg.js → SettingsPage-CgkRlCM5.js} +19 -50
- package/dist/SettingsPage-DMHQFj5-.d.ts +9 -0
- package/dist/TagFilterSelect-DCBOH6Ou.js +41 -0
- package/dist/TaskQueuesPage-9VgSnLdL.js +951 -0
- package/dist/TemplateCard-DsC0KNH1.js +1416 -0
- package/dist/{TemplateConfigurationModal-D_Mvgxqa.js → TemplateConfigurationModal-BhGWIzpm.js} +3 -2
- package/dist/{TemplateDetailPanel-DfFfUcOe.js → TemplateDetailPanel-D4cUVr-m.js} +3 -3
- package/dist/TemplatePreview-GthzCOSo.js +231 -0
- package/dist/TemplatesPage-BG3H-6v6.d.ts +10 -0
- package/dist/{TemplatesPage-Cku13bav.js → TemplatesPage-CsDNT54N.js} +11 -228
- package/dist/VariablesPage-67WR_lVE.js +949 -0
- package/dist/{VersionDiffDialog-Dq2xlPFI.js → VersionDiffDialog-DSN0mU0f.js} +2 -1
- package/dist/WorkflowBuilder-DEi_9YOb.js +555 -0
- package/dist/{WorkflowSearchRedirect-CaoOOpEl.js → WorkflowBuilder-iPqXgbYr.js} +19 -585
- package/dist/{WorkflowProposalCard-8Vr56kQa.js → WorkflowProposalCard-qrEeNyYG.js} +4 -405
- package/dist/WorkflowSearchRedirect-DwDNZ_q5.js +36 -0
- package/dist/{WorkflowShareDialog-6RRDe-_v.js → WorkflowShareDialog-B_gn968c.js} +6 -52
- package/dist/{WorkflowsList-B2j1Pehb.js → WorkflowsList-CA20dVIl.js} +11 -6
- package/dist/WorkflowsList-CcNDQge5.d.ts +6 -0
- package/dist/agent-form-Bfvm32j1.js +83 -0
- package/dist/{agentTools-DJ5o2ekg.js → agentTools-CkRJB7r5.js} +3 -2
- package/dist/{ai-usage-D5p7ZeRR.js → ai-usage-glCwHyQz.js} +1 -1
- package/dist/api-BrCHB5oA.js +224 -0
- package/dist/api-C8e0iV-Q.js +55 -0
- package/dist/button-DG7y_FVJ.js +48 -0
- package/dist/{canvasNoteTools-D3zUdEeg.js → canvasNoteTools-CQIc7Oxg.js} +2 -2
- package/dist/client-C9XSzSXr.js +1147 -0
- package/dist/{codec-client-DstqyzTN.js → codec-client-CJ95Rmqo.js} +1 -1
- package/dist/constants-B2lhWNoN.js +202 -0
- package/dist/constants-XdvUxeWK.d.ts +162 -0
- package/dist/dialog-Cjb4lB4D.js +105 -0
- package/dist/executions.d.ts +1 -1
- package/dist/executions.js +2 -1
- package/dist/feature-flags-DM5myWaD.js +296 -0
- package/dist/flags.d.ts +3 -0
- package/dist/flags.js +4 -0
- package/dist/{flow-builder-DEzT8TQu.js → flow-builder-y2Y1iG4Y.js} +70 -1731
- package/dist/{node-endpoint-configs-DHFGA5MQ.js → graphql-operation-types-kX-MMjgW.js} +1 -1194
- package/dist/{graphql-types-XcDLtFwU.js → graphql-types-CDKVWH2R.js} +2 -202
- package/dist/history.d.ts +1 -1
- package/dist/history.js +1 -1
- package/dist/index-72XFgvbn.d.ts +132 -0
- package/dist/index-BcdtKBM-.d.ts +56 -0
- package/dist/{index-B3BWqafN.d.ts → index-DjiFgEQl.d.ts} +5 -131
- package/dist/{index-DRf25-D3.d.ts → index-W2o__Nm6.d.ts} +32 -214
- package/dist/index.d.ts +13 -9
- package/dist/index.js +50 -5300
- package/dist/{node-detail-view-LNqeIqN-.js → node-detail-view-B91kXzIy.js} +11 -8
- package/dist/node-endpoint-configs-B5bjNMDW.js +37 -0
- package/dist/node-registry-refresh-Dy0uRg9f.js +84 -0
- package/dist/nodes.d.ts +1 -1
- package/dist/nodes.js +1 -1
- package/dist/observability.d.ts +1 -1
- package/dist/observability.js +2 -1
- package/dist/{quick-config-panel-D3ogsaFL.js → quick-config-panel-DggPl1vY.js} +2 -2
- package/dist/rolldown-runtime-hDbaFkMy.js +18 -0
- package/dist/run-display-BycKYSU0.js +46 -0
- package/dist/run-list-links-ByYC0OlV.js +98 -0
- package/dist/settings.d.ts +2 -1
- package/dist/settings.js +2 -1
- package/dist/shared-CMfn30xT.js +196 -0
- package/dist/templates.d.ts +1 -1
- package/dist/templates.js +2 -1
- package/dist/theme-provider-B3mIuz2d.js +11 -0
- package/dist/{useAgentDefinitions-NFtLytDR.js → useAgentDefinitions-Dpz0HDTq.js} +2 -1
- package/dist/useDurableParity-CzUQMFJ3.js +415 -0
- package/dist/useEntityTags-DhnsZcTl.js +236 -0
- package/dist/{useExecutions-DAzeWHS6.js → useExecutions-9aLuOt1c.js} +4 -3
- package/dist/{useObservability-COCZ0hUS.js → useObservability-CfEw3ZFD.js} +2 -2
- package/dist/{useRunHistory-CsYUbouO.js → useRunHistory-B1xJDwl1.js} +4 -3
- package/dist/{useWorkflows-w4Dx2fF2.js → useWorkflows-BlVVu8NM.js} +3 -2
- package/dist/utils-uaL5UVxb.js +65 -0
- package/dist/workflow-builder.d.ts +1 -1
- package/dist/workflow-builder.js +4 -2
- package/dist/workflow-host.d.ts +6 -0
- package/dist/workflow-host.js +9 -0
- package/dist/workflow-pages.d.ts +55 -0
- package/dist/workflow-pages.js +113 -0
- package/dist/workflows-list.d.ts +1 -1
- package/dist/workflows-list.js +1 -1
- package/package.json +13 -1
- package/dist/ExecutionDetailPage-MvsnOnE1.d.ts +0 -4
- package/dist/HistoryPage-BqUizaFv.d.ts +0 -3
- package/dist/NodesPage-C97-9K2Y.d.ts +0 -3
- package/dist/TemplatesPage-D0qnXzHh.d.ts +0 -4
- package/dist/WorkflowsList-0d5GSKdh.d.ts +0 -3
- package/dist/agent-form-BvMWhQ42.js +0 -496
|
@@ -0,0 +1,949 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { t as __exportAll } from "./rolldown-runtime-hDbaFkMy.js";
|
|
3
|
+
import { r as useTr } from "./TranslationBridge-Da-TPgQm.js";
|
|
4
|
+
import { i as SdkPermissionButton, t as FLUIDGRIDS_PERMISSIONS } from "./constants-B2lhWNoN.js";
|
|
5
|
+
import { _ as throwIfResultError, n as getFluidGridsClient } from "./client-C9XSzSXr.js";
|
|
6
|
+
import { useCallback, useEffect, useState } from "react";
|
|
7
|
+
import { useNavigate } from "react-router";
|
|
8
|
+
import { Icon } from "@iconify/react";
|
|
9
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
10
|
+
import { toast } from "sonner";
|
|
11
|
+
import { gql } from "@apollo/client";
|
|
12
|
+
import { Badge, Card, CardHeader, Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, Input, Label, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Switch, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger } from "@burdenoff/fe-libs/ui";
|
|
13
|
+
import { Button as Button$1 } from "@burdenoff/fe-libs/button";
|
|
14
|
+
|
|
15
|
+
// src/modules/variables/hooks/useVariables.ts
|
|
16
|
+
/**
|
|
17
|
+
* Custom hooks for workflow Variables + external secrets provider config
|
|
18
|
+
* (BOFF-7517). Queries/mutates wspace-workflow-svc via the federated
|
|
19
|
+
* GraphQL gateway — mirrors the connections module's hook pattern
|
|
20
|
+
* (`modules/connections/hooks/useConnections.ts`).
|
|
21
|
+
*/
|
|
22
|
+
const VARIABLE_FIELDS = gql`
|
|
23
|
+
fragment WorkflowVariableFields on WorkflowVariable {
|
|
24
|
+
id
|
|
25
|
+
scope
|
|
26
|
+
workspaceId
|
|
27
|
+
projectId
|
|
28
|
+
key
|
|
29
|
+
description
|
|
30
|
+
isSecret
|
|
31
|
+
externalProvider
|
|
32
|
+
externalRef
|
|
33
|
+
value
|
|
34
|
+
createdAt
|
|
35
|
+
updatedAt
|
|
36
|
+
createdBy
|
|
37
|
+
updatedBy
|
|
38
|
+
}
|
|
39
|
+
`;
|
|
40
|
+
const GET_WORKFLOW_VARIABLES = gql`
|
|
41
|
+
${VARIABLE_FIELDS}
|
|
42
|
+
query GetWorkflowVariables($scope: VariableScope, $projectId: ID) {
|
|
43
|
+
workflowVariables(scope: $scope, projectId: $projectId) {
|
|
44
|
+
variables {
|
|
45
|
+
...WorkflowVariableFields
|
|
46
|
+
}
|
|
47
|
+
total
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
`;
|
|
51
|
+
const CREATE_WORKFLOW_VARIABLE = gql`
|
|
52
|
+
${VARIABLE_FIELDS}
|
|
53
|
+
mutation CreateWorkflowVariable($input: CreateWorkflowVariableInput!) {
|
|
54
|
+
createWorkflowVariable(input: $input) {
|
|
55
|
+
success
|
|
56
|
+
message
|
|
57
|
+
variable {
|
|
58
|
+
...WorkflowVariableFields
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
`;
|
|
63
|
+
const UPDATE_WORKFLOW_VARIABLE = gql`
|
|
64
|
+
${VARIABLE_FIELDS}
|
|
65
|
+
mutation UpdateWorkflowVariable(
|
|
66
|
+
$id: ID!
|
|
67
|
+
$input: UpdateWorkflowVariableInput!
|
|
68
|
+
) {
|
|
69
|
+
updateWorkflowVariable(id: $id, input: $input) {
|
|
70
|
+
success
|
|
71
|
+
message
|
|
72
|
+
variable {
|
|
73
|
+
...WorkflowVariableFields
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
`;
|
|
78
|
+
const DELETE_WORKFLOW_VARIABLE = gql`
|
|
79
|
+
mutation DeleteWorkflowVariable($id: ID!) {
|
|
80
|
+
deleteWorkflowVariable(id: $id) {
|
|
81
|
+
success
|
|
82
|
+
message
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
`;
|
|
86
|
+
const REVEAL_WORKFLOW_VARIABLE_VALUE = gql`
|
|
87
|
+
mutation RevealWorkflowVariableValue($id: ID!) {
|
|
88
|
+
revealWorkflowVariableValue(id: $id) {
|
|
89
|
+
success
|
|
90
|
+
message
|
|
91
|
+
value
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
`;
|
|
95
|
+
const GET_SECRETS_PROVIDER_CONFIGS = gql`
|
|
96
|
+
query GetSecretsProviderConfigs {
|
|
97
|
+
secretsProviderConfigs {
|
|
98
|
+
id
|
|
99
|
+
workspaceId
|
|
100
|
+
provider
|
|
101
|
+
awsSecretsManagerPrefix
|
|
102
|
+
awsRegion
|
|
103
|
+
vaultAddress
|
|
104
|
+
vaultMountPath
|
|
105
|
+
azureKeyVaultUri
|
|
106
|
+
gcpProjectId
|
|
107
|
+
isEnabled
|
|
108
|
+
lastTestedAt
|
|
109
|
+
lastTestStatus
|
|
110
|
+
lastTestMessage
|
|
111
|
+
createdAt
|
|
112
|
+
updatedAt
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
`;
|
|
116
|
+
const SAVE_SECRETS_PROVIDER_CONFIG = gql`
|
|
117
|
+
mutation SaveSecretsProviderConfig($input: SaveSecretsProviderConfigInput!) {
|
|
118
|
+
saveSecretsProviderConfig(input: $input) {
|
|
119
|
+
success
|
|
120
|
+
message
|
|
121
|
+
config {
|
|
122
|
+
id
|
|
123
|
+
provider
|
|
124
|
+
awsSecretsManagerPrefix
|
|
125
|
+
awsRegion
|
|
126
|
+
isEnabled
|
|
127
|
+
lastTestedAt
|
|
128
|
+
lastTestStatus
|
|
129
|
+
lastTestMessage
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
`;
|
|
134
|
+
const TEST_SECRETS_PROVIDER_CONNECTION = gql`
|
|
135
|
+
mutation TestSecretsProviderConnection($provider: SecretProviderType!) {
|
|
136
|
+
testSecretsProviderConnection(provider: $provider) {
|
|
137
|
+
success
|
|
138
|
+
message
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
`;
|
|
142
|
+
function useVariables(filter) {
|
|
143
|
+
const [variables, setVariables] = useState([]);
|
|
144
|
+
const [total, setTotal] = useState(0);
|
|
145
|
+
const [loading, setLoading] = useState(true);
|
|
146
|
+
const [error, setError] = useState(null);
|
|
147
|
+
const scope = filter?.scope;
|
|
148
|
+
const projectId = filter?.projectId;
|
|
149
|
+
const fetchData = useCallback(async () => {
|
|
150
|
+
setLoading(true);
|
|
151
|
+
setError(null);
|
|
152
|
+
try {
|
|
153
|
+
const result = await getFluidGridsClient().query({
|
|
154
|
+
query: GET_WORKFLOW_VARIABLES,
|
|
155
|
+
variables: {
|
|
156
|
+
scope,
|
|
157
|
+
projectId
|
|
158
|
+
},
|
|
159
|
+
fetchPolicy: "network-only"
|
|
160
|
+
});
|
|
161
|
+
setVariables(result.data?.workflowVariables?.variables ?? []);
|
|
162
|
+
setTotal(result.data?.workflowVariables?.total ?? 0);
|
|
163
|
+
} catch (err) {
|
|
164
|
+
setError(err);
|
|
165
|
+
} finally {
|
|
166
|
+
setLoading(false);
|
|
167
|
+
}
|
|
168
|
+
}, [scope, projectId]);
|
|
169
|
+
useEffect(() => {
|
|
170
|
+
fetchData();
|
|
171
|
+
}, [fetchData]);
|
|
172
|
+
return {
|
|
173
|
+
variables,
|
|
174
|
+
total,
|
|
175
|
+
loading,
|
|
176
|
+
error,
|
|
177
|
+
refetch: fetchData
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
function useCreateVariable() {
|
|
181
|
+
const [loading, setLoading] = useState(false);
|
|
182
|
+
const [error, setError] = useState(null);
|
|
183
|
+
return {
|
|
184
|
+
createVariable: useCallback(async (input) => {
|
|
185
|
+
setLoading(true);
|
|
186
|
+
setError(null);
|
|
187
|
+
try {
|
|
188
|
+
const client = getFluidGridsClient();
|
|
189
|
+
const response = throwIfResultError(await client.mutate({
|
|
190
|
+
mutation: CREATE_WORKFLOW_VARIABLE,
|
|
191
|
+
variables: { input }
|
|
192
|
+
})).data?.createWorkflowVariable;
|
|
193
|
+
if (!response?.success) throw new Error(response?.message ?? "Failed to create variable");
|
|
194
|
+
return response.variable;
|
|
195
|
+
} catch (err) {
|
|
196
|
+
setError(err);
|
|
197
|
+
throw err;
|
|
198
|
+
} finally {
|
|
199
|
+
setLoading(false);
|
|
200
|
+
}
|
|
201
|
+
}, []),
|
|
202
|
+
loading,
|
|
203
|
+
error
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
function useUpdateVariable() {
|
|
207
|
+
const [loading, setLoading] = useState(false);
|
|
208
|
+
const [error, setError] = useState(null);
|
|
209
|
+
return {
|
|
210
|
+
updateVariable: useCallback(async (id, input) => {
|
|
211
|
+
setLoading(true);
|
|
212
|
+
setError(null);
|
|
213
|
+
try {
|
|
214
|
+
const client = getFluidGridsClient();
|
|
215
|
+
const response = throwIfResultError(await client.mutate({
|
|
216
|
+
mutation: UPDATE_WORKFLOW_VARIABLE,
|
|
217
|
+
variables: {
|
|
218
|
+
id,
|
|
219
|
+
input
|
|
220
|
+
}
|
|
221
|
+
})).data?.updateWorkflowVariable;
|
|
222
|
+
if (!response?.success) throw new Error(response?.message ?? "Failed to update variable");
|
|
223
|
+
return response.variable;
|
|
224
|
+
} catch (err) {
|
|
225
|
+
setError(err);
|
|
226
|
+
throw err;
|
|
227
|
+
} finally {
|
|
228
|
+
setLoading(false);
|
|
229
|
+
}
|
|
230
|
+
}, []),
|
|
231
|
+
loading,
|
|
232
|
+
error
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
function useDeleteVariable() {
|
|
236
|
+
const [loading, setLoading] = useState(false);
|
|
237
|
+
const [error, setError] = useState(null);
|
|
238
|
+
return {
|
|
239
|
+
deleteVariable: useCallback(async (id) => {
|
|
240
|
+
setLoading(true);
|
|
241
|
+
setError(null);
|
|
242
|
+
try {
|
|
243
|
+
const client = getFluidGridsClient();
|
|
244
|
+
const response = throwIfResultError(await client.mutate({
|
|
245
|
+
mutation: DELETE_WORKFLOW_VARIABLE,
|
|
246
|
+
variables: { id }
|
|
247
|
+
})).data?.deleteWorkflowVariable;
|
|
248
|
+
if (!response?.success) throw new Error(response?.message ?? "Failed to delete variable");
|
|
249
|
+
return true;
|
|
250
|
+
} catch (err) {
|
|
251
|
+
setError(err);
|
|
252
|
+
throw err;
|
|
253
|
+
} finally {
|
|
254
|
+
setLoading(false);
|
|
255
|
+
}
|
|
256
|
+
}, []),
|
|
257
|
+
loading,
|
|
258
|
+
error
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
function useRevealVariableValue() {
|
|
262
|
+
const [loading, setLoading] = useState(false);
|
|
263
|
+
const [error, setError] = useState(null);
|
|
264
|
+
return {
|
|
265
|
+
revealValue: useCallback(async (id) => {
|
|
266
|
+
setLoading(true);
|
|
267
|
+
setError(null);
|
|
268
|
+
try {
|
|
269
|
+
const client = getFluidGridsClient();
|
|
270
|
+
const response = throwIfResultError(await client.mutate({
|
|
271
|
+
mutation: REVEAL_WORKFLOW_VARIABLE_VALUE,
|
|
272
|
+
variables: { id }
|
|
273
|
+
})).data?.revealWorkflowVariableValue;
|
|
274
|
+
if (!response?.success) throw new Error(response?.message ?? "Failed to reveal value");
|
|
275
|
+
return response.value ?? "";
|
|
276
|
+
} catch (err) {
|
|
277
|
+
setError(err);
|
|
278
|
+
throw err;
|
|
279
|
+
} finally {
|
|
280
|
+
setLoading(false);
|
|
281
|
+
}
|
|
282
|
+
}, []),
|
|
283
|
+
loading,
|
|
284
|
+
error
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
function useSecretsProviderConfigs() {
|
|
288
|
+
const [configs, setConfigs] = useState([]);
|
|
289
|
+
const [loading, setLoading] = useState(true);
|
|
290
|
+
const [error, setError] = useState(null);
|
|
291
|
+
const fetchData = useCallback(async () => {
|
|
292
|
+
setLoading(true);
|
|
293
|
+
setError(null);
|
|
294
|
+
try {
|
|
295
|
+
const result = await getFluidGridsClient().query({
|
|
296
|
+
query: GET_SECRETS_PROVIDER_CONFIGS,
|
|
297
|
+
fetchPolicy: "network-only"
|
|
298
|
+
});
|
|
299
|
+
setConfigs(result.data?.secretsProviderConfigs ?? []);
|
|
300
|
+
} catch (err) {
|
|
301
|
+
setError(err);
|
|
302
|
+
} finally {
|
|
303
|
+
setLoading(false);
|
|
304
|
+
}
|
|
305
|
+
}, []);
|
|
306
|
+
useEffect(() => {
|
|
307
|
+
fetchData();
|
|
308
|
+
}, [fetchData]);
|
|
309
|
+
return {
|
|
310
|
+
configs,
|
|
311
|
+
loading,
|
|
312
|
+
error,
|
|
313
|
+
refetch: fetchData
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
function useSaveSecretsProviderConfig() {
|
|
317
|
+
const [loading, setLoading] = useState(false);
|
|
318
|
+
const [error, setError] = useState(null);
|
|
319
|
+
return {
|
|
320
|
+
saveConfig: useCallback(async (input) => {
|
|
321
|
+
setLoading(true);
|
|
322
|
+
setError(null);
|
|
323
|
+
try {
|
|
324
|
+
const client = getFluidGridsClient();
|
|
325
|
+
const response = throwIfResultError(await client.mutate({
|
|
326
|
+
mutation: SAVE_SECRETS_PROVIDER_CONFIG,
|
|
327
|
+
variables: { input }
|
|
328
|
+
})).data?.saveSecretsProviderConfig;
|
|
329
|
+
if (!response?.success) throw new Error(response?.message ?? "Failed to save provider configuration");
|
|
330
|
+
return response.config;
|
|
331
|
+
} catch (err) {
|
|
332
|
+
setError(err);
|
|
333
|
+
throw err;
|
|
334
|
+
} finally {
|
|
335
|
+
setLoading(false);
|
|
336
|
+
}
|
|
337
|
+
}, []),
|
|
338
|
+
loading,
|
|
339
|
+
error
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
function useTestSecretsProviderConnection() {
|
|
343
|
+
const [loading, setLoading] = useState(false);
|
|
344
|
+
const [error, setError] = useState(null);
|
|
345
|
+
return {
|
|
346
|
+
testConnection: useCallback(async (provider) => {
|
|
347
|
+
setLoading(true);
|
|
348
|
+
setError(null);
|
|
349
|
+
try {
|
|
350
|
+
const client = getFluidGridsClient();
|
|
351
|
+
return throwIfResultError(await client.mutate({
|
|
352
|
+
mutation: TEST_SECRETS_PROVIDER_CONNECTION,
|
|
353
|
+
variables: { provider }
|
|
354
|
+
})).data?.testSecretsProviderConnection ?? {
|
|
355
|
+
success: false,
|
|
356
|
+
message: "Unknown error"
|
|
357
|
+
};
|
|
358
|
+
} catch (err) {
|
|
359
|
+
setError(err);
|
|
360
|
+
throw err;
|
|
361
|
+
} finally {
|
|
362
|
+
setLoading(false);
|
|
363
|
+
}
|
|
364
|
+
}, []),
|
|
365
|
+
loading,
|
|
366
|
+
error
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// src/modules/variables/pages/VariablesPage.tsx
|
|
371
|
+
/**
|
|
372
|
+
* Variables Page (BOFF-7517)
|
|
373
|
+
*
|
|
374
|
+
* Workspace/project-scoped `$vars` key-value store management: list/create/
|
|
375
|
+
* edit/delete variables, mask secret values (dots + explicit "Reveal"
|
|
376
|
+
* action), and configure/test the external secrets provider (AWS Secrets
|
|
377
|
+
* Manager first).
|
|
378
|
+
*/
|
|
379
|
+
var VariablesPage_exports = /* @__PURE__ */ __exportAll({ VariablesPage: () => VariablesPage });
|
|
380
|
+
function VariableValueCell({ variable }) {
|
|
381
|
+
const tr = useTr();
|
|
382
|
+
const { revealValue, loading } = useRevealVariableValue();
|
|
383
|
+
const [revealed, setRevealed] = useState(null);
|
|
384
|
+
const isMasked = variable.isSecret || variable.externalProvider !== "NONE";
|
|
385
|
+
const handleReveal = useCallback(async () => {
|
|
386
|
+
try {
|
|
387
|
+
const value = await revealValue(variable.id);
|
|
388
|
+
setRevealed(value);
|
|
389
|
+
setTimeout(() => setRevealed(null), 15e3);
|
|
390
|
+
} catch (err) {
|
|
391
|
+
toast.error(err instanceof Error ? err.message : tr("fluidgrids.variables.revealFailed", "Failed to reveal value"));
|
|
392
|
+
}
|
|
393
|
+
}, [
|
|
394
|
+
revealValue,
|
|
395
|
+
variable.id,
|
|
396
|
+
tr
|
|
397
|
+
]);
|
|
398
|
+
if (variable.externalProvider !== "NONE" && revealed === null) return /* @__PURE__ */ jsxs("div", {
|
|
399
|
+
className: "flex items-center gap-2",
|
|
400
|
+
children: [
|
|
401
|
+
/* @__PURE__ */ jsx(Badge, {
|
|
402
|
+
variant: "outline",
|
|
403
|
+
className: "font-mono text-xs",
|
|
404
|
+
children: variable.externalProvider
|
|
405
|
+
}),
|
|
406
|
+
variable.externalRef && /* @__PURE__ */ jsx("span", {
|
|
407
|
+
className: "text-xs text-text-secondary truncate max-w-[160px]",
|
|
408
|
+
title: variable.externalRef,
|
|
409
|
+
children: variable.externalRef
|
|
410
|
+
}),
|
|
411
|
+
/* @__PURE__ */ jsx("button", {
|
|
412
|
+
onClick: handleReveal,
|
|
413
|
+
disabled: loading,
|
|
414
|
+
className: "text-xs text-text-secondary hover:text-text-primary underline",
|
|
415
|
+
children: tr("fluidgrids.variables.reveal", "Reveal")
|
|
416
|
+
})
|
|
417
|
+
]
|
|
418
|
+
});
|
|
419
|
+
if (!isMasked) return /* @__PURE__ */ jsx("code", {
|
|
420
|
+
className: "text-sm text-text-primary",
|
|
421
|
+
children: variable.value ?? ""
|
|
422
|
+
});
|
|
423
|
+
if (revealed !== null) return /* @__PURE__ */ jsxs("div", {
|
|
424
|
+
className: "flex items-center gap-2",
|
|
425
|
+
children: [/* @__PURE__ */ jsx("code", {
|
|
426
|
+
className: "text-sm text-text-primary break-all",
|
|
427
|
+
children: revealed
|
|
428
|
+
}), /* @__PURE__ */ jsx("button", {
|
|
429
|
+
onClick: () => setRevealed(null),
|
|
430
|
+
className: "text-xs text-text-secondary hover:text-text-primary underline shrink-0",
|
|
431
|
+
children: tr("fluidgrids.variables.hide", "Hide")
|
|
432
|
+
})]
|
|
433
|
+
});
|
|
434
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
435
|
+
className: "flex items-center gap-2",
|
|
436
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
437
|
+
className: "tracking-widest text-text-secondary select-none",
|
|
438
|
+
children: "••••••••"
|
|
439
|
+
}), /* @__PURE__ */ jsx("button", {
|
|
440
|
+
onClick: handleReveal,
|
|
441
|
+
disabled: loading,
|
|
442
|
+
className: "text-xs text-text-secondary hover:text-text-primary underline",
|
|
443
|
+
children: loading ? tr("fluidgrids.variables.revealing", "Revealing…") : tr("fluidgrids.variables.reveal", "Reveal")
|
|
444
|
+
})]
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
function VariableFormDialog({ open, onOpenChange, variable, onSaved }) {
|
|
448
|
+
const tr = useTr();
|
|
449
|
+
const { createVariable, loading: creating } = useCreateVariable();
|
|
450
|
+
const { updateVariable, loading: updating } = useUpdateVariable();
|
|
451
|
+
const isEdit = !!variable;
|
|
452
|
+
const [key, setKey] = useState(variable?.key ?? "");
|
|
453
|
+
const [description, setDescription] = useState(variable?.description ?? "");
|
|
454
|
+
const [isSecret, setIsSecret] = useState(variable?.isSecret ?? false);
|
|
455
|
+
const [value, setValue] = useState("");
|
|
456
|
+
const [scope, setScope] = useState(variable?.scope ?? "WORKSPACE");
|
|
457
|
+
const resetForm = useCallback(() => {
|
|
458
|
+
setKey(variable?.key ?? "");
|
|
459
|
+
setDescription(variable?.description ?? "");
|
|
460
|
+
setIsSecret(variable?.isSecret ?? false);
|
|
461
|
+
setValue("");
|
|
462
|
+
setScope(variable?.scope ?? "WORKSPACE");
|
|
463
|
+
}, [variable]);
|
|
464
|
+
const handleSubmit = useCallback(async () => {
|
|
465
|
+
try {
|
|
466
|
+
if (isEdit && variable) {
|
|
467
|
+
await updateVariable(variable.id, {
|
|
468
|
+
description: description || void 0,
|
|
469
|
+
isSecret,
|
|
470
|
+
...value ? { value } : {}
|
|
471
|
+
});
|
|
472
|
+
toast.success(tr("fluidgrids.variables.updated", "Variable updated"));
|
|
473
|
+
} else {
|
|
474
|
+
if (!key.trim()) {
|
|
475
|
+
toast.error(tr("fluidgrids.variables.keyRequired", "Key is required"));
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
478
|
+
await createVariable({
|
|
479
|
+
key: key.trim(),
|
|
480
|
+
description: description || void 0,
|
|
481
|
+
isSecret,
|
|
482
|
+
value,
|
|
483
|
+
scope
|
|
484
|
+
});
|
|
485
|
+
toast.success(tr("fluidgrids.variables.created", "Variable created"));
|
|
486
|
+
}
|
|
487
|
+
onSaved();
|
|
488
|
+
onOpenChange(false);
|
|
489
|
+
} catch (err) {
|
|
490
|
+
toast.error(err instanceof Error ? err.message : tr("fluidgrids.variables.saveFailed", "Failed to save variable"));
|
|
491
|
+
}
|
|
492
|
+
}, [
|
|
493
|
+
isEdit,
|
|
494
|
+
variable,
|
|
495
|
+
key,
|
|
496
|
+
description,
|
|
497
|
+
isSecret,
|
|
498
|
+
value,
|
|
499
|
+
scope,
|
|
500
|
+
createVariable,
|
|
501
|
+
updateVariable,
|
|
502
|
+
onSaved,
|
|
503
|
+
onOpenChange,
|
|
504
|
+
tr
|
|
505
|
+
]);
|
|
506
|
+
return /* @__PURE__ */ jsx(Dialog, {
|
|
507
|
+
open,
|
|
508
|
+
onOpenChange: (next) => {
|
|
509
|
+
if (next) resetForm();
|
|
510
|
+
onOpenChange(next);
|
|
511
|
+
},
|
|
512
|
+
children: /* @__PURE__ */ jsxs(DialogContent, {
|
|
513
|
+
className: "max-w-md",
|
|
514
|
+
children: [
|
|
515
|
+
/* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, { children: isEdit ? tr("fluidgrids.variables.editTitle", "Edit variable") : tr("fluidgrids.variables.createTitle", "New variable") }) }),
|
|
516
|
+
/* @__PURE__ */ jsxs("div", {
|
|
517
|
+
className: "space-y-4 py-2",
|
|
518
|
+
children: [
|
|
519
|
+
/* @__PURE__ */ jsxs("div", {
|
|
520
|
+
className: "space-y-1.5",
|
|
521
|
+
children: [
|
|
522
|
+
/* @__PURE__ */ jsx(Label, {
|
|
523
|
+
htmlFor: "variable-key",
|
|
524
|
+
children: tr("fluidgrids.variables.keyLabel", "Key")
|
|
525
|
+
}),
|
|
526
|
+
/* @__PURE__ */ jsx(Input, {
|
|
527
|
+
id: "variable-key",
|
|
528
|
+
value: key,
|
|
529
|
+
onChange: (e) => setKey(e.target.value),
|
|
530
|
+
disabled: isEdit,
|
|
531
|
+
placeholder: "API_URL"
|
|
532
|
+
}),
|
|
533
|
+
/* @__PURE__ */ jsx("p", {
|
|
534
|
+
className: "text-xs text-text-secondary",
|
|
535
|
+
children: tr("fluidgrids.variables.keyHint", "Use it in expressions as {{ $vars.KEY }} or ${vars.KEY}")
|
|
536
|
+
})
|
|
537
|
+
]
|
|
538
|
+
}),
|
|
539
|
+
!isEdit && /* @__PURE__ */ jsxs("div", {
|
|
540
|
+
className: "space-y-1.5",
|
|
541
|
+
children: [/* @__PURE__ */ jsx(Label, {
|
|
542
|
+
htmlFor: "variable-scope",
|
|
543
|
+
children: tr("fluidgrids.variables.scopeLabel", "Scope")
|
|
544
|
+
}), /* @__PURE__ */ jsxs(Select, {
|
|
545
|
+
value: scope,
|
|
546
|
+
onValueChange: (v) => setScope(v),
|
|
547
|
+
children: [/* @__PURE__ */ jsx(SelectTrigger, {
|
|
548
|
+
id: "variable-scope",
|
|
549
|
+
children: /* @__PURE__ */ jsx(SelectValue, {})
|
|
550
|
+
}), /* @__PURE__ */ jsxs(SelectContent, { children: [/* @__PURE__ */ jsx(SelectItem, {
|
|
551
|
+
value: "WORKSPACE",
|
|
552
|
+
children: tr("fluidgrids.variables.scopeWorkspace", "Workspace")
|
|
553
|
+
}), /* @__PURE__ */ jsx(SelectItem, {
|
|
554
|
+
value: "PROJECT",
|
|
555
|
+
children: tr("fluidgrids.variables.scopeProject", "Project")
|
|
556
|
+
})] })]
|
|
557
|
+
})]
|
|
558
|
+
}),
|
|
559
|
+
/* @__PURE__ */ jsxs("div", {
|
|
560
|
+
className: "space-y-1.5",
|
|
561
|
+
children: [/* @__PURE__ */ jsx(Label, {
|
|
562
|
+
htmlFor: "variable-description",
|
|
563
|
+
children: tr("fluidgrids.variables.descriptionLabel", "Description")
|
|
564
|
+
}), /* @__PURE__ */ jsx(Input, {
|
|
565
|
+
id: "variable-description",
|
|
566
|
+
value: description,
|
|
567
|
+
onChange: (e) => setDescription(e.target.value),
|
|
568
|
+
placeholder: tr("fluidgrids.variables.descriptionPlaceholder", "Optional")
|
|
569
|
+
})]
|
|
570
|
+
}),
|
|
571
|
+
/* @__PURE__ */ jsxs("div", {
|
|
572
|
+
className: "flex items-center justify-between py-1",
|
|
573
|
+
children: [/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx(Label, {
|
|
574
|
+
htmlFor: "variable-secret",
|
|
575
|
+
children: tr("fluidgrids.variables.secretLabel", "Secret value")
|
|
576
|
+
}), /* @__PURE__ */ jsx("p", {
|
|
577
|
+
className: "text-xs text-text-secondary",
|
|
578
|
+
children: tr("fluidgrids.variables.secretHint", "Masked in the UI and never printed to run logs")
|
|
579
|
+
})] }), /* @__PURE__ */ jsx(Switch, {
|
|
580
|
+
id: "variable-secret",
|
|
581
|
+
checked: isSecret,
|
|
582
|
+
onCheckedChange: setIsSecret
|
|
583
|
+
})]
|
|
584
|
+
}),
|
|
585
|
+
/* @__PURE__ */ jsxs("div", {
|
|
586
|
+
className: "space-y-1.5",
|
|
587
|
+
children: [/* @__PURE__ */ jsx(Label, {
|
|
588
|
+
htmlFor: "variable-value",
|
|
589
|
+
children: tr("fluidgrids.variables.valueLabel", "Value")
|
|
590
|
+
}), /* @__PURE__ */ jsx(Input, {
|
|
591
|
+
id: "variable-value",
|
|
592
|
+
type: isSecret ? "password" : "text",
|
|
593
|
+
value,
|
|
594
|
+
onChange: (e) => setValue(e.target.value),
|
|
595
|
+
placeholder: isEdit ? tr("fluidgrids.variables.valueLeaveBlank", "Leave blank to keep the current value") : ""
|
|
596
|
+
})]
|
|
597
|
+
})
|
|
598
|
+
]
|
|
599
|
+
}),
|
|
600
|
+
/* @__PURE__ */ jsxs(DialogFooter, { children: [/* @__PURE__ */ jsx(Button$1, {
|
|
601
|
+
variant: "outline",
|
|
602
|
+
onClick: () => onOpenChange(false),
|
|
603
|
+
children: tr("fluidgrids.variables.cancel", "Cancel")
|
|
604
|
+
}), /* @__PURE__ */ jsx(Button$1, {
|
|
605
|
+
"data-agent": "confirm",
|
|
606
|
+
onClick: handleSubmit,
|
|
607
|
+
disabled: creating || updating,
|
|
608
|
+
children: creating || updating ? tr("fluidgrids.variables.saving", "Saving…") : tr("fluidgrids.variables.save", "Save")
|
|
609
|
+
})] })
|
|
610
|
+
]
|
|
611
|
+
})
|
|
612
|
+
});
|
|
613
|
+
}
|
|
614
|
+
function VariablesTab() {
|
|
615
|
+
const tr = useTr();
|
|
616
|
+
const { variables, loading, refetch } = useVariables();
|
|
617
|
+
const { deleteVariable } = useDeleteVariable();
|
|
618
|
+
const [dialogOpen, setDialogOpen] = useState(false);
|
|
619
|
+
const [editing, setEditing] = useState(null);
|
|
620
|
+
const handleCreate = useCallback(() => {
|
|
621
|
+
setEditing(null);
|
|
622
|
+
setDialogOpen(true);
|
|
623
|
+
}, []);
|
|
624
|
+
const handleEdit = useCallback((variable) => {
|
|
625
|
+
setEditing(variable);
|
|
626
|
+
setDialogOpen(true);
|
|
627
|
+
}, []);
|
|
628
|
+
const handleDelete = useCallback(async (variable) => {
|
|
629
|
+
if (!window.confirm(tr("fluidgrids.variables.confirmDelete", `Delete variable "${variable.key}"?`))) return;
|
|
630
|
+
try {
|
|
631
|
+
await deleteVariable(variable.id);
|
|
632
|
+
toast.success(tr("fluidgrids.variables.deleted", "Variable deleted"));
|
|
633
|
+
refetch();
|
|
634
|
+
} catch (err) {
|
|
635
|
+
toast.error(err instanceof Error ? err.message : tr("fluidgrids.variables.deleteFailed", "Failed to delete variable"));
|
|
636
|
+
}
|
|
637
|
+
}, [
|
|
638
|
+
deleteVariable,
|
|
639
|
+
refetch,
|
|
640
|
+
tr
|
|
641
|
+
]);
|
|
642
|
+
return /* @__PURE__ */ jsxs("div", { children: [
|
|
643
|
+
/* @__PURE__ */ jsxs("div", {
|
|
644
|
+
className: "flex items-center justify-between mb-4",
|
|
645
|
+
children: [/* @__PURE__ */ jsx("p", {
|
|
646
|
+
className: "text-sm text-text-secondary",
|
|
647
|
+
children: tr("fluidgrids.variables.tabDescription", "Reference these in any node parameter as {{ $vars.KEY }} (new expressions) or ${vars.KEY} (legacy).")
|
|
648
|
+
}), /* @__PURE__ */ jsx(SdkPermissionButton, {
|
|
649
|
+
permission: FLUIDGRIDS_PERMISSIONS.VARIABLE_CREATE,
|
|
650
|
+
deniedTooltip: tr("fluidgrids.variables.createDeniedTooltip", "You don't have permission to create variables"),
|
|
651
|
+
children: /* @__PURE__ */ jsxs(Button$1, {
|
|
652
|
+
onClick: handleCreate,
|
|
653
|
+
size: "sm",
|
|
654
|
+
"data-tour": "fluidgrids-variables-create",
|
|
655
|
+
children: [/* @__PURE__ */ jsx(Icon, {
|
|
656
|
+
icon: "mdi:plus",
|
|
657
|
+
className: "mr-1.5",
|
|
658
|
+
width: 16
|
|
659
|
+
}), tr("fluidgrids.variables.newVariable", "New Variable")]
|
|
660
|
+
})
|
|
661
|
+
})]
|
|
662
|
+
}),
|
|
663
|
+
/* @__PURE__ */ jsx(Card, {
|
|
664
|
+
className: "border border-border-secondary bg-background-secondary",
|
|
665
|
+
"data-tour": "fluidgrids-variables-table",
|
|
666
|
+
children: /* @__PURE__ */ jsxs(Table, { children: [/* @__PURE__ */ jsx(TableHeader, { children: /* @__PURE__ */ jsxs(TableRow, { children: [
|
|
667
|
+
/* @__PURE__ */ jsx(TableHead, { children: tr("fluidgrids.variables.colKey", "Key") }),
|
|
668
|
+
/* @__PURE__ */ jsx(TableHead, { children: tr("fluidgrids.variables.colScope", "Scope") }),
|
|
669
|
+
/* @__PURE__ */ jsx(TableHead, { children: tr("fluidgrids.variables.colValue", "Value") }),
|
|
670
|
+
/* @__PURE__ */ jsx(TableHead, {
|
|
671
|
+
className: "text-right",
|
|
672
|
+
children: tr("fluidgrids.variables.colActions", "Actions")
|
|
673
|
+
})
|
|
674
|
+
] }) }), /* @__PURE__ */ jsxs(TableBody, { children: [
|
|
675
|
+
loading && /* @__PURE__ */ jsx(TableRow, { children: /* @__PURE__ */ jsx(TableCell, {
|
|
676
|
+
colSpan: 4,
|
|
677
|
+
className: "text-center text-text-secondary py-8",
|
|
678
|
+
children: tr("fluidgrids.variables.loading", "Loading…")
|
|
679
|
+
}) }),
|
|
680
|
+
!loading && variables.length === 0 && /* @__PURE__ */ jsx(TableRow, { children: /* @__PURE__ */ jsx(TableCell, {
|
|
681
|
+
colSpan: 4,
|
|
682
|
+
className: "text-center text-text-secondary py-8",
|
|
683
|
+
children: tr("fluidgrids.variables.empty", "No variables yet")
|
|
684
|
+
}) }),
|
|
685
|
+
variables.map((variable) => /* @__PURE__ */ jsxs(TableRow, { children: [
|
|
686
|
+
/* @__PURE__ */ jsxs(TableCell, { children: [/* @__PURE__ */ jsxs("div", {
|
|
687
|
+
className: "flex items-center gap-2",
|
|
688
|
+
children: [/* @__PURE__ */ jsx("code", {
|
|
689
|
+
className: "text-sm font-medium text-text-primary",
|
|
690
|
+
children: variable.key
|
|
691
|
+
}), variable.isSecret && /* @__PURE__ */ jsx(Badge, {
|
|
692
|
+
variant: "outline",
|
|
693
|
+
className: "text-[10px]",
|
|
694
|
+
children: tr("fluidgrids.variables.secretBadge", "SECRET")
|
|
695
|
+
})]
|
|
696
|
+
}), variable.description && /* @__PURE__ */ jsx("p", {
|
|
697
|
+
className: "text-xs text-text-secondary mt-0.5",
|
|
698
|
+
children: variable.description
|
|
699
|
+
})] }),
|
|
700
|
+
/* @__PURE__ */ jsx(TableCell, {
|
|
701
|
+
className: "text-text-secondary text-sm",
|
|
702
|
+
children: variable.scope
|
|
703
|
+
}),
|
|
704
|
+
/* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsx(VariableValueCell, { variable }) }),
|
|
705
|
+
/* @__PURE__ */ jsx(TableCell, {
|
|
706
|
+
className: "text-right",
|
|
707
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
708
|
+
className: "flex items-center justify-end gap-1",
|
|
709
|
+
children: [/* @__PURE__ */ jsx(SdkPermissionButton, {
|
|
710
|
+
permission: FLUIDGRIDS_PERMISSIONS.VARIABLE_UPDATE,
|
|
711
|
+
deniedTooltip: tr("fluidgrids.variables.editDeniedTooltip", "You don't have permission to edit variables"),
|
|
712
|
+
children: /* @__PURE__ */ jsx("button", {
|
|
713
|
+
onClick: () => handleEdit(variable),
|
|
714
|
+
className: "p-1.5 rounded hover:bg-background-tertiary text-text-secondary hover:text-text-primary",
|
|
715
|
+
title: tr("fluidgrids.variables.edit", "Edit"),
|
|
716
|
+
children: /* @__PURE__ */ jsx(Icon, {
|
|
717
|
+
icon: "mdi:pencil-outline",
|
|
718
|
+
width: 16
|
|
719
|
+
})
|
|
720
|
+
})
|
|
721
|
+
}), /* @__PURE__ */ jsx(SdkPermissionButton, {
|
|
722
|
+
permission: FLUIDGRIDS_PERMISSIONS.VARIABLE_DELETE,
|
|
723
|
+
deniedTooltip: tr("fluidgrids.variables.deleteDeniedTooltip", "You don't have permission to delete variables"),
|
|
724
|
+
children: /* @__PURE__ */ jsx("button", {
|
|
725
|
+
onClick: () => handleDelete(variable),
|
|
726
|
+
className: "p-1.5 rounded hover:bg-background-tertiary text-text-secondary hover:text-status-error-text",
|
|
727
|
+
title: tr("fluidgrids.variables.delete", "Delete"),
|
|
728
|
+
children: /* @__PURE__ */ jsx(Icon, {
|
|
729
|
+
icon: "mdi:trash-can-outline",
|
|
730
|
+
width: 16
|
|
731
|
+
})
|
|
732
|
+
})
|
|
733
|
+
})]
|
|
734
|
+
})
|
|
735
|
+
})
|
|
736
|
+
] }, variable.id))
|
|
737
|
+
] })] })
|
|
738
|
+
}),
|
|
739
|
+
/* @__PURE__ */ jsx(VariableFormDialog, {
|
|
740
|
+
open: dialogOpen,
|
|
741
|
+
onOpenChange: setDialogOpen,
|
|
742
|
+
variable: editing,
|
|
743
|
+
onSaved: refetch
|
|
744
|
+
})
|
|
745
|
+
] });
|
|
746
|
+
}
|
|
747
|
+
function ExternalProvidersTab() {
|
|
748
|
+
const tr = useTr();
|
|
749
|
+
const { configs, loading, refetch } = useSecretsProviderConfigs();
|
|
750
|
+
const { saveConfig, loading: saving } = useSaveSecretsProviderConfig();
|
|
751
|
+
const { testConnection, loading: testing } = useTestSecretsProviderConnection();
|
|
752
|
+
const awsConfig = configs.find((c) => c.provider === "AWS_SECRETS_MANAGER");
|
|
753
|
+
const [prefix, setPrefix] = useState("");
|
|
754
|
+
const [region, setRegion] = useState("ap-south-1");
|
|
755
|
+
const [enabled, setEnabled] = useState(false);
|
|
756
|
+
const [lastTest, setLastTest] = useState(null);
|
|
757
|
+
const [hydratedConfigId, setHydratedConfigId] = useState(null);
|
|
758
|
+
useEffect(() => {
|
|
759
|
+
if (!awsConfig || awsConfig.id === hydratedConfigId) return;
|
|
760
|
+
setPrefix(awsConfig.awsSecretsManagerPrefix ?? "");
|
|
761
|
+
setRegion(awsConfig.awsRegion ?? "ap-south-1");
|
|
762
|
+
setEnabled(awsConfig.isEnabled);
|
|
763
|
+
setLastTest(awsConfig.lastTestStatus ? {
|
|
764
|
+
success: awsConfig.lastTestStatus === "SUCCESS",
|
|
765
|
+
message: awsConfig.lastTestMessage ?? ""
|
|
766
|
+
} : null);
|
|
767
|
+
setHydratedConfigId(awsConfig.id);
|
|
768
|
+
}, [awsConfig, hydratedConfigId]);
|
|
769
|
+
const handleSave = useCallback(async () => {
|
|
770
|
+
try {
|
|
771
|
+
await saveConfig({
|
|
772
|
+
provider: "AWS_SECRETS_MANAGER",
|
|
773
|
+
awsSecretsManagerPrefix: prefix || void 0,
|
|
774
|
+
awsRegion: region || void 0,
|
|
775
|
+
isEnabled: enabled
|
|
776
|
+
});
|
|
777
|
+
toast.success(tr("fluidgrids.variables.providerSaved", "Provider configuration saved"));
|
|
778
|
+
refetch();
|
|
779
|
+
} catch (err) {
|
|
780
|
+
toast.error(err instanceof Error ? err.message : tr("fluidgrids.variables.providerSaveFailed", "Failed to save"));
|
|
781
|
+
}
|
|
782
|
+
}, [
|
|
783
|
+
saveConfig,
|
|
784
|
+
prefix,
|
|
785
|
+
region,
|
|
786
|
+
enabled,
|
|
787
|
+
refetch,
|
|
788
|
+
tr
|
|
789
|
+
]);
|
|
790
|
+
const handleTest = useCallback(async () => {
|
|
791
|
+
try {
|
|
792
|
+
const result = await testConnection("AWS_SECRETS_MANAGER");
|
|
793
|
+
setLastTest(result);
|
|
794
|
+
if (result.success) toast.success(result.message);
|
|
795
|
+
else toast.error(result.message);
|
|
796
|
+
} catch (err) {
|
|
797
|
+
toast.error(err instanceof Error ? err.message : tr("fluidgrids.variables.testFailed", "Connection test failed"));
|
|
798
|
+
}
|
|
799
|
+
}, [testConnection, tr]);
|
|
800
|
+
if (loading) return /* @__PURE__ */ jsx("p", {
|
|
801
|
+
className: "text-text-secondary text-sm",
|
|
802
|
+
children: tr("fluidgrids.variables.loading", "Loading…")
|
|
803
|
+
});
|
|
804
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
805
|
+
className: "space-y-4 max-w-xl",
|
|
806
|
+
children: [/* @__PURE__ */ jsx(Card, {
|
|
807
|
+
className: "border border-border-secondary bg-background-secondary",
|
|
808
|
+
children: /* @__PURE__ */ jsxs(CardHeader, {
|
|
809
|
+
className: "pb-3 space-y-4",
|
|
810
|
+
children: [
|
|
811
|
+
/* @__PURE__ */ jsxs("div", {
|
|
812
|
+
className: "flex items-center gap-2",
|
|
813
|
+
children: [/* @__PURE__ */ jsx(Icon, {
|
|
814
|
+
icon: "mdi:aws",
|
|
815
|
+
width: 20,
|
|
816
|
+
className: "text-text-secondary"
|
|
817
|
+
}), /* @__PURE__ */ jsx("h3", {
|
|
818
|
+
className: "text-sm font-semibold text-text-primary",
|
|
819
|
+
children: tr("fluidgrids.variables.awsProviderTitle", "AWS Secrets Manager")
|
|
820
|
+
})]
|
|
821
|
+
}),
|
|
822
|
+
/* @__PURE__ */ jsx("p", {
|
|
823
|
+
className: "text-xs text-text-secondary",
|
|
824
|
+
children: tr("fluidgrids.variables.awsProviderDescription", "A variable can reference a secret stored in AWS Secrets Manager instead of storing its own value. Only secrets under the prefix below are reachable.")
|
|
825
|
+
}),
|
|
826
|
+
/* @__PURE__ */ jsxs("div", {
|
|
827
|
+
className: "space-y-1.5",
|
|
828
|
+
children: [/* @__PURE__ */ jsx(Label, {
|
|
829
|
+
htmlFor: "aws-prefix",
|
|
830
|
+
children: tr("fluidgrids.variables.awsPrefixLabel", "Secrets Manager prefix")
|
|
831
|
+
}), /* @__PURE__ */ jsx(Input, {
|
|
832
|
+
id: "aws-prefix",
|
|
833
|
+
value: prefix,
|
|
834
|
+
onChange: (e) => setPrefix(e.target.value),
|
|
835
|
+
placeholder: "boff/prod/wspace/workflow/vars/"
|
|
836
|
+
})]
|
|
837
|
+
}),
|
|
838
|
+
/* @__PURE__ */ jsxs("div", {
|
|
839
|
+
className: "space-y-1.5",
|
|
840
|
+
children: [/* @__PURE__ */ jsx(Label, {
|
|
841
|
+
htmlFor: "aws-region",
|
|
842
|
+
children: tr("fluidgrids.variables.awsRegionLabel", "Region")
|
|
843
|
+
}), /* @__PURE__ */ jsx(Input, {
|
|
844
|
+
id: "aws-region",
|
|
845
|
+
value: region,
|
|
846
|
+
onChange: (e) => setRegion(e.target.value)
|
|
847
|
+
})]
|
|
848
|
+
}),
|
|
849
|
+
/* @__PURE__ */ jsxs("div", {
|
|
850
|
+
className: "flex items-center justify-between",
|
|
851
|
+
children: [/* @__PURE__ */ jsx(Label, {
|
|
852
|
+
htmlFor: "aws-enabled",
|
|
853
|
+
children: tr("fluidgrids.variables.awsEnabledLabel", "Enabled")
|
|
854
|
+
}), /* @__PURE__ */ jsx(Switch, {
|
|
855
|
+
id: "aws-enabled",
|
|
856
|
+
checked: enabled,
|
|
857
|
+
onCheckedChange: setEnabled
|
|
858
|
+
})]
|
|
859
|
+
}),
|
|
860
|
+
lastTest && /* @__PURE__ */ jsx("div", {
|
|
861
|
+
className: `text-xs rounded-md px-3 py-2 border ${lastTest.success ? "border-status-success-border bg-status-success-bg-subtle text-status-success-text" : "border-status-error-border bg-status-error-bg-subtle text-status-error-text"}`,
|
|
862
|
+
children: lastTest.message
|
|
863
|
+
}),
|
|
864
|
+
/* @__PURE__ */ jsxs("div", {
|
|
865
|
+
className: "flex items-center gap-2 pt-1",
|
|
866
|
+
children: [/* @__PURE__ */ jsx(Button$1, {
|
|
867
|
+
"data-agent": "confirm",
|
|
868
|
+
onClick: handleSave,
|
|
869
|
+
disabled: saving,
|
|
870
|
+
size: "sm",
|
|
871
|
+
children: saving ? tr("fluidgrids.variables.saving", "Saving…") : tr("fluidgrids.variables.save", "Save")
|
|
872
|
+
}), /* @__PURE__ */ jsx(Button$1, {
|
|
873
|
+
onClick: handleTest,
|
|
874
|
+
disabled: testing,
|
|
875
|
+
variant: "outline",
|
|
876
|
+
size: "sm",
|
|
877
|
+
children: testing ? tr("fluidgrids.variables.testing", "Testing…") : tr("fluidgrids.variables.testConnection", "Test connection")
|
|
878
|
+
})]
|
|
879
|
+
})
|
|
880
|
+
]
|
|
881
|
+
})
|
|
882
|
+
}), /* @__PURE__ */ jsx("p", {
|
|
883
|
+
className: "text-xs text-text-secondary",
|
|
884
|
+
children: tr("fluidgrids.variables.otherProvidersNote", "HashiCorp Vault, Azure Key Vault, and GCP Secret Manager are not available yet.")
|
|
885
|
+
})]
|
|
886
|
+
});
|
|
887
|
+
}
|
|
888
|
+
function VariablesPage() {
|
|
889
|
+
const tr = useTr();
|
|
890
|
+
const navigate = useNavigate();
|
|
891
|
+
const [activeTab, setActiveTab] = useState("variables");
|
|
892
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
893
|
+
className: "p-4 sm:p-6 bg-background-primary min-h-screen",
|
|
894
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
895
|
+
className: "flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4 mb-6",
|
|
896
|
+
"data-tour": "fluidgrids-variables-header",
|
|
897
|
+
children: [/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("h1", {
|
|
898
|
+
className: "text-2xl sm:text-3xl font-bold text-text-primary",
|
|
899
|
+
children: tr("fluidgrids.variables.pageTitle", "Variables")
|
|
900
|
+
}), /* @__PURE__ */ jsx("p", {
|
|
901
|
+
className: "text-text-secondary mt-1",
|
|
902
|
+
children: tr("fluidgrids.variables.pageSubtitle", "Reusable values workflows can reference as $vars")
|
|
903
|
+
})] }), /* @__PURE__ */ jsxs(Button$1, {
|
|
904
|
+
variant: "outline",
|
|
905
|
+
onClick: () => navigate("../list"),
|
|
906
|
+
children: [/* @__PURE__ */ jsx(Icon, {
|
|
907
|
+
icon: "mdi:arrow-left",
|
|
908
|
+
className: "mr-2",
|
|
909
|
+
width: 16
|
|
910
|
+
}), tr("fluidgrids.variables.backToWorkflows", "Back to Workflows")]
|
|
911
|
+
})]
|
|
912
|
+
}), /* @__PURE__ */ jsxs(Tabs, {
|
|
913
|
+
value: activeTab,
|
|
914
|
+
onValueChange: setActiveTab,
|
|
915
|
+
className: "w-full",
|
|
916
|
+
children: [
|
|
917
|
+
/* @__PURE__ */ jsxs(TabsList, {
|
|
918
|
+
className: "bg-background-secondary border border-border-secondary mb-6",
|
|
919
|
+
"data-tour": "fluidgrids-variables-tabs",
|
|
920
|
+
children: [/* @__PURE__ */ jsxs(TabsTrigger, {
|
|
921
|
+
value: "variables",
|
|
922
|
+
className: "gap-1.5",
|
|
923
|
+
children: [/* @__PURE__ */ jsx(Icon, {
|
|
924
|
+
icon: "mdi:variable",
|
|
925
|
+
width: 16
|
|
926
|
+
}), tr("fluidgrids.variables.variablesTab", "Variables")]
|
|
927
|
+
}), /* @__PURE__ */ jsxs(TabsTrigger, {
|
|
928
|
+
value: "providers",
|
|
929
|
+
className: "gap-1.5",
|
|
930
|
+
children: [/* @__PURE__ */ jsx(Icon, {
|
|
931
|
+
icon: "mdi:key-chain-variant",
|
|
932
|
+
width: 16
|
|
933
|
+
}), tr("fluidgrids.variables.providersTab", "External Providers")]
|
|
934
|
+
})]
|
|
935
|
+
}),
|
|
936
|
+
/* @__PURE__ */ jsx(TabsContent, {
|
|
937
|
+
value: "variables",
|
|
938
|
+
children: /* @__PURE__ */ jsx(VariablesTab, {})
|
|
939
|
+
}),
|
|
940
|
+
/* @__PURE__ */ jsx(TabsContent, {
|
|
941
|
+
value: "providers",
|
|
942
|
+
children: /* @__PURE__ */ jsx(ExternalProvidersTab, {})
|
|
943
|
+
})
|
|
944
|
+
]
|
|
945
|
+
})]
|
|
946
|
+
});
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
export { useRevealVariableValue as a, useTestSecretsProviderConnection as c, useDeleteVariable as i, useUpdateVariable as l, VariablesPage_exports as n, useSaveSecretsProviderConfig as o, useCreateVariable as r, useSecretsProviderConfigs as s, VariablesPage as t, useVariables as u };
|