@burdenoff/fluidgrids-fe-sdk 2026.1104.3 → 2026.1105.2
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 +38 -0
- package/dist/ExecutionDetailPage-HQB2SWBP.js +28 -0
- package/dist/ExecutionsListPage-RSLL634L.js +22 -0
- package/dist/WorkflowBuilder-E3PNZX74.js +32 -0
- package/dist/WorkflowsList-473FRRP2.js +21 -0
- package/dist/{agentTools-SZZN6TP3.js → agentTools-5N3ZEZDW.js} +8 -7
- package/dist/{chunk-NIY6R42C.js → chunk-2KUZBEWW.js} +7 -5
- package/dist/{chunk-NTWG3CJX.js → chunk-3IXU7WUC.js} +32 -21
- package/dist/{chunk-AAIZ6S6E.js → chunk-3QCRKKTI.js} +70 -88
- package/dist/{chunk-WTV6SQYK.js → chunk-3XUWPDKJ.js} +616 -25
- package/dist/{chunk-XCSCD3IU.js → chunk-5CFCFA6O.js} +8 -7
- package/dist/{chunk-DFIX6YWP.js → chunk-62CCBMDC.js} +40 -21
- package/dist/{chunk-KHXRYQYP.js → chunk-64JN2TVX.js} +4 -3
- package/dist/{chunk-NYBL5WHP.js → chunk-6IS7EXIY.js} +3 -3
- package/dist/{chunk-YYVRBROH.js → chunk-6ZK4MRVA.js} +1 -1
- package/dist/{chunk-4YCMMBSK.js → chunk-AJVU5YW6.js} +3 -3
- package/dist/{chunk-NGXJHYV5.js → chunk-AMXJLVZN.js} +2 -2
- package/dist/{chunk-PXIFUMLA.js → chunk-AU7LACOY.js} +16 -11
- package/dist/{chunk-GEY7RXRZ.js → chunk-CH3YUGWR.js} +4 -4
- package/dist/{chunk-XNU2PLJ2.js → chunk-CNKTQ5MG.js} +189 -9
- package/dist/{chunk-BIB7IH26.js → chunk-EYQ7GJRW.js} +5 -5
- package/dist/{chunk-X6PIU7FE.js → chunk-GKFMK7FF.js} +4 -3
- package/dist/{chunk-NJRCAE6K.js → chunk-HK76ZUAK.js} +5 -5
- package/dist/{chunk-F7LQL43U.js → chunk-IL343FKX.js} +2 -2
- package/dist/{chunk-5D4XS3WJ.js → chunk-J3YQCEP3.js} +18 -4
- package/dist/{chunk-4EUEKSEQ.js → chunk-L2N6DDOI.js} +2 -2
- package/dist/chunk-NZAYYUQ4.js +172 -0
- package/dist/{chunk-ON7LK6QH.js → chunk-O7CJJNW6.js} +278 -197
- package/dist/{chunk-ZDCJPQ5M.js → chunk-OXXXUAWM.js} +2 -2
- package/dist/{chunk-D4WA2M2N.js → chunk-QFC6E3WD.js} +4 -3
- package/dist/{chunk-AFX3EKFN.js → chunk-QFGZXWTM.js} +16 -4
- package/dist/{chunk-IK7IGG6T.js → chunk-QPLFALVV.js} +9 -8
- package/dist/{chunk-MF7JLSJX.js → chunk-SALZ3LQB.js} +11 -2
- package/dist/{chunk-SS7Y66P5.js → chunk-TCIBTMJI.js} +70 -4
- package/dist/{chunk-OMB3WMDQ.js → chunk-TNFBRXU7.js} +11 -10
- package/dist/chunk-UEG2WC3G.js +502 -0
- package/dist/chunk-US5QSLPV.js +316 -0
- package/dist/{chunk-5UHAB75U.js → chunk-W5WML3OO.js} +1 -1
- package/dist/chunk-WZ3EJVS6.js +93 -0
- package/dist/{chunk-Q72EOY4T.js → chunk-X25NCWG2.js} +9 -3
- package/dist/{chunk-VDJFTZ2H.js → chunk-XFH6SLDK.js} +4 -93
- package/dist/{chunk-TBHAZK52.js → chunk-Y6M7K4UG.js} +1 -1
- package/dist/{chunk-AVHBWJRY.js → chunk-Z3ABLERJ.js} +3 -1
- package/dist/client-YVZMLEQX.js +3 -0
- package/dist/config-66FUPSG5.js +1 -0
- package/dist/executions.js +18 -15
- package/dist/global-client-N5EIFW6T.js +3 -0
- package/dist/history.js +9 -8
- package/dist/index.d.ts +172 -133
- package/dist/index.js +95 -74
- package/dist/{node-detail-view-GAGSLHAO.js → node-detail-view-WIWW5N6N.js} +36 -11
- package/dist/nodes.js +5 -3
- package/dist/observability.js +10 -8
- package/dist/{quick-config-panel-44RBX6YR.js → quick-config-panel-O64TXXK3.js} +10 -8
- package/dist/settings.js +11 -9
- package/dist/templates.js +15 -14
- package/dist/{workflow-builder-BMGVSwpy.d.ts → workflow-builder-7vv9dCdp.d.ts} +413 -2
- package/dist/workflow-builder.d.ts +2 -1
- package/dist/workflow-builder.js +17 -16
- package/dist/workflows-list.js +11 -10
- package/package.json +1 -1
- package/dist/ExecutionDetailPage-ND2VMU45.js +0 -25
- package/dist/ExecutionsListPage-EZ65FXER.js +0 -20
- package/dist/WorkflowBuilder-4I44FWII.js +0 -31
- package/dist/WorkflowsList-YFD2RKKQ.js +0 -20
- package/dist/chunk-6AMNEX2Y.js +0 -214
- package/dist/client-EYQDMR4O.js +0 -1
- package/dist/config-3DBXLCK3.js +0 -1
- package/dist/global-client-O2HCG5CJ.js +0 -1
package/README.md
CHANGED
|
@@ -237,6 +237,44 @@ The SDK uses Tailwind CSS for styling. Make sure you have Tailwind configured in
|
|
|
237
237
|
import '@burdenoff/fluidgrids-fe-sdk/styles.css';
|
|
238
238
|
```
|
|
239
239
|
|
|
240
|
+
## Embedding: theme, token refresh and events (BOFF-9961)
|
|
241
|
+
|
|
242
|
+
`FluidGridsProvider`, `FluidGridsRoot` and `WorkflowBuilder` take three
|
|
243
|
+
embedding props (also settable with `setFluidGridsConfig`):
|
|
244
|
+
|
|
245
|
+
```tsx
|
|
246
|
+
<FluidGridsProvider
|
|
247
|
+
workspaceId={workspaceId}
|
|
248
|
+
apiGatewayUrl={workspaceGraphqlUrl}
|
|
249
|
+
authToken={token}
|
|
250
|
+
theme={{ mode: 'light', colors: { primary: '#2563eb' }, radius: { base: '10px' } }}
|
|
251
|
+
auth={{ onTokenExpired: () => session.refresh() }}
|
|
252
|
+
onEvent={(name, payload) => {
|
|
253
|
+
if (name === 'run:completed') console.log(payload.runId, payload.status);
|
|
254
|
+
}}
|
|
255
|
+
>
|
|
256
|
+
{children}
|
|
257
|
+
</FluidGridsProvider>
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
- **`theme`** — `"light"`, `"dark"` or `{ mode?, colors?, radius?, font? }`.
|
|
261
|
+
Each token maps to fe-libs semantic CSS variables (`FLUIDGRIDS_THEME_TOKEN_MAP`);
|
|
262
|
+
values are validated (`themeToCssVariables`) and applied document-wide as
|
|
263
|
+
inline properties on `<html>`, restored on unmount (`applyFluidGridsTheme`,
|
|
264
|
+
`useFluidGridsTheme`). The public embed viewer also reads `accent`, `radius`
|
|
265
|
+
and `font` query parameters next to `theme`.
|
|
266
|
+
- **`auth.onTokenExpired`** — called once per expired-session failure (401,
|
|
267
|
+
`UNAUTHENTICATED`, expired/revoked credential); concurrent failures share one
|
|
268
|
+
call; the request is retried once with the new token; on rejection the SDK
|
|
269
|
+
emits `auth:failed` and surfaces the original error. Host-injected Apollo
|
|
270
|
+
clients add `createFluidGridsTokenRefreshLink()` before their auth link.
|
|
271
|
+
- **`onEvent`** — typed `FluidGridsEventMap`: `workflow:saved`,
|
|
272
|
+
`workflow:activated`, `run:started`, `run:completed`, `node:selected`,
|
|
273
|
+
`error`, `auth:failed`. Contract version `FLUIDGRIDS_EVENTS_VERSION` (semver:
|
|
274
|
+
additive = minor, payload break = major).
|
|
275
|
+
|
|
276
|
+
Full guide: [docs.fluidgrids.ai/developers/embedding](https://docs.fluidgrids.ai/developers/embedding).
|
|
277
|
+
|
|
240
278
|
## Branding
|
|
241
279
|
|
|
242
280
|
Every workflow canvas the SDK renders — `WorkflowBuilder`, `WorkflowBuilderCore`,
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export { ExecutionDetailPage } from './chunk-3XUWPDKJ.js';
|
|
2
|
+
import './chunk-QFC6E3WD.js';
|
|
3
|
+
import './chunk-CNKTQ5MG.js';
|
|
4
|
+
import './chunk-J3YQCEP3.js';
|
|
5
|
+
import './chunk-TCIBTMJI.js';
|
|
6
|
+
import './chunk-NZAYYUQ4.js';
|
|
7
|
+
import './chunk-AMXJLVZN.js';
|
|
8
|
+
import './chunk-WZ3EJVS6.js';
|
|
9
|
+
import './chunk-5ERAJC2I.js';
|
|
10
|
+
import './chunk-EYQ7GJRW.js';
|
|
11
|
+
import './chunk-JDLQ6QIB.js';
|
|
12
|
+
import './chunk-IL343FKX.js';
|
|
13
|
+
import './chunk-Y53CVZVV.js';
|
|
14
|
+
import './chunk-FNZZ5JJL.js';
|
|
15
|
+
import './chunk-QFGZXWTM.js';
|
|
16
|
+
import './chunk-PJAWNFJV.js';
|
|
17
|
+
import './chunk-H4ERTSMX.js';
|
|
18
|
+
import './chunk-3QCRKKTI.js';
|
|
19
|
+
import './chunk-5375NUIO.js';
|
|
20
|
+
import './chunk-JL7CASN5.js';
|
|
21
|
+
import './chunk-OCJTTHTS.js';
|
|
22
|
+
import './chunk-AU7LACOY.js';
|
|
23
|
+
import './chunk-G77IGC3Y.js';
|
|
24
|
+
import './chunk-Z3ABLERJ.js';
|
|
25
|
+
import './chunk-UULVIT25.js';
|
|
26
|
+
import './chunk-3IXU7WUC.js';
|
|
27
|
+
import './chunk-US5QSLPV.js';
|
|
28
|
+
import './chunk-UEG2WC3G.js';
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export { ExecutionsListPage } from './chunk-HK76ZUAK.js';
|
|
2
|
+
import './chunk-CNKTQ5MG.js';
|
|
3
|
+
import './chunk-J3YQCEP3.js';
|
|
4
|
+
import './chunk-WZ3EJVS6.js';
|
|
5
|
+
import './chunk-5ERAJC2I.js';
|
|
6
|
+
import './chunk-IL343FKX.js';
|
|
7
|
+
import './chunk-FNZZ5JJL.js';
|
|
8
|
+
import './chunk-QFGZXWTM.js';
|
|
9
|
+
import './chunk-PJAWNFJV.js';
|
|
10
|
+
import './chunk-H4ERTSMX.js';
|
|
11
|
+
import './chunk-4VJ3MDOV.js';
|
|
12
|
+
import './chunk-3QCRKKTI.js';
|
|
13
|
+
import './chunk-5375NUIO.js';
|
|
14
|
+
import './chunk-JL7CASN5.js';
|
|
15
|
+
import './chunk-OCJTTHTS.js';
|
|
16
|
+
import './chunk-AU7LACOY.js';
|
|
17
|
+
import './chunk-G77IGC3Y.js';
|
|
18
|
+
import './chunk-Z3ABLERJ.js';
|
|
19
|
+
import './chunk-UULVIT25.js';
|
|
20
|
+
import './chunk-3IXU7WUC.js';
|
|
21
|
+
import './chunk-US5QSLPV.js';
|
|
22
|
+
import './chunk-UEG2WC3G.js';
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export { WorkflowBuilder } from './chunk-TNFBRXU7.js';
|
|
2
|
+
import './chunk-Y6M7K4UG.js';
|
|
3
|
+
import './chunk-PIKYQE7P.js';
|
|
4
|
+
import './chunk-62CCBMDC.js';
|
|
5
|
+
import './chunk-GEMNVFPK.js';
|
|
6
|
+
import './chunk-B6CCE2RW.js';
|
|
7
|
+
import './chunk-IEVSFCFS.js';
|
|
8
|
+
import './chunk-YXMFRQYV.js';
|
|
9
|
+
import './chunk-BQXVT32O.js';
|
|
10
|
+
import './chunk-6ZK4MRVA.js';
|
|
11
|
+
import './chunk-W5WML3OO.js';
|
|
12
|
+
import './chunk-GKFMK7FF.js';
|
|
13
|
+
import './chunk-EYQ7GJRW.js';
|
|
14
|
+
import './chunk-JDLQ6QIB.js';
|
|
15
|
+
import './chunk-IL343FKX.js';
|
|
16
|
+
import './chunk-Y53CVZVV.js';
|
|
17
|
+
import './chunk-64JN2TVX.js';
|
|
18
|
+
import './chunk-QFGZXWTM.js';
|
|
19
|
+
import './chunk-GLYINMOR.js';
|
|
20
|
+
import './chunk-H4ERTSMX.js';
|
|
21
|
+
import './chunk-4VJ3MDOV.js';
|
|
22
|
+
import './chunk-3QCRKKTI.js';
|
|
23
|
+
import './chunk-5375NUIO.js';
|
|
24
|
+
import './chunk-JL7CASN5.js';
|
|
25
|
+
import './chunk-OCJTTHTS.js';
|
|
26
|
+
import './chunk-AU7LACOY.js';
|
|
27
|
+
import './chunk-G77IGC3Y.js';
|
|
28
|
+
import './chunk-Z3ABLERJ.js';
|
|
29
|
+
import './chunk-UULVIT25.js';
|
|
30
|
+
import './chunk-3IXU7WUC.js';
|
|
31
|
+
import './chunk-US5QSLPV.js';
|
|
32
|
+
import './chunk-UEG2WC3G.js';
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export { WorkflowsList } from './chunk-5CFCFA6O.js';
|
|
2
|
+
import './chunk-Y6M7K4UG.js';
|
|
3
|
+
import './chunk-J3YQCEP3.js';
|
|
4
|
+
import './chunk-5ERAJC2I.js';
|
|
5
|
+
import './chunk-GKFMK7FF.js';
|
|
6
|
+
import './chunk-FNZZ5JJL.js';
|
|
7
|
+
import './chunk-QFGZXWTM.js';
|
|
8
|
+
import './chunk-PJAWNFJV.js';
|
|
9
|
+
import './chunk-H4ERTSMX.js';
|
|
10
|
+
import './chunk-4VJ3MDOV.js';
|
|
11
|
+
import './chunk-3QCRKKTI.js';
|
|
12
|
+
import './chunk-5375NUIO.js';
|
|
13
|
+
import './chunk-JL7CASN5.js';
|
|
14
|
+
import './chunk-OCJTTHTS.js';
|
|
15
|
+
import './chunk-AU7LACOY.js';
|
|
16
|
+
import './chunk-G77IGC3Y.js';
|
|
17
|
+
import './chunk-Z3ABLERJ.js';
|
|
18
|
+
import './chunk-UULVIT25.js';
|
|
19
|
+
import './chunk-3IXU7WUC.js';
|
|
20
|
+
import './chunk-US5QSLPV.js';
|
|
21
|
+
import './chunk-UEG2WC3G.js';
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import { nodeTitle, selectedOperationOf, paramsFromOperation, fixedParameterState } from './chunk-
|
|
2
|
-
import { computeAttachPosition } from './chunk-
|
|
3
|
-
import { NODE_CONFIGS, createConfiguredNode, resolveOutputHandles, resolveInputHandles, isNodeConfigsInitialized, useFlowStore, useSaveStatusStore, autosaveAllowedFor, isFlowComplete, isNodeTypeHiddenFromPalette } from './chunk-
|
|
1
|
+
import { nodeTitle, selectedOperationOf, paramsFromOperation, fixedParameterState } from './chunk-AJVU5YW6.js';
|
|
2
|
+
import { computeAttachPosition } from './chunk-W5WML3OO.js';
|
|
3
|
+
import { NODE_CONFIGS, createConfiguredNode, resolveOutputHandles, resolveInputHandles, isNodeConfigsInitialized, useFlowStore, useSaveStatusStore, autosaveAllowedFor, isFlowComplete, isNodeTypeHiddenFromPalette } from './chunk-3QCRKKTI.js';
|
|
4
4
|
import './chunk-5375NUIO.js';
|
|
5
5
|
import './chunk-JL7CASN5.js';
|
|
6
6
|
import './chunk-OCJTTHTS.js';
|
|
7
|
-
import './chunk-
|
|
8
|
-
import './chunk-6AMNEX2Y.js';
|
|
7
|
+
import './chunk-AU7LACOY.js';
|
|
9
8
|
import './chunk-G77IGC3Y.js';
|
|
10
|
-
import './chunk-
|
|
9
|
+
import './chunk-Z3ABLERJ.js';
|
|
11
10
|
import './chunk-UULVIT25.js';
|
|
12
|
-
import './chunk-
|
|
11
|
+
import './chunk-3IXU7WUC.js';
|
|
12
|
+
import './chunk-US5QSLPV.js';
|
|
13
|
+
import './chunk-UEG2WC3G.js';
|
|
13
14
|
import { defineAgentTool, AgentToolError } from '@burdenoff/fe-libs/shared/agent-tools';
|
|
14
15
|
import { z } from 'zod';
|
|
15
16
|
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { CodeEditorField, normalizeCodeLanguage } from './chunk-AASHQI77.js';
|
|
2
|
-
import { asRecord, ConditionTreeBuilder, SwitchRulesEditor, casesFromRules, isStringOptionList, optionText, coerceNumber, paramsFromOperation, resolveLoadOptionsSpec, optionListValues, parseMappingValue, optionListText } from './chunk-
|
|
2
|
+
import { asRecord, ConditionTreeBuilder, SwitchRulesEditor, casesFromRules, isStringOptionList, optionText, coerceNumber, paramsFromOperation, resolveLoadOptionsSpec, optionListValues, parseMappingValue, optionListText } from './chunk-AJVU5YW6.js';
|
|
3
3
|
import { Popover, PopoverTrigger, PopoverContent } from './chunk-GTEBQQ7J.js';
|
|
4
|
-
import {
|
|
4
|
+
import { AgentDefinitionSelectField } from './chunk-XFH6SLDK.js';
|
|
5
|
+
import { isAgentNodeType } from './chunk-WZ3EJVS6.js';
|
|
5
6
|
import { readAssertRulesSetting, rowsFromRules, normaliseAssertRules, ruleFromRow, describeAssertRuleProblem, operatorSpec, ASSERT_OPERATORS, emptyAssertRuleRow } from './chunk-JDLQ6QIB.js';
|
|
6
|
-
import { useFlowStore, isParamVisible, ConnectionSelector, structuredParameterType, useRunGuard, FluidGridsContext, ExpressionEditor, formatParameterValue, parseParameterValue, useFluidGridsAnalytics,
|
|
7
|
+
import { useFlowStore, isParamVisible, ConnectionSelector, structuredParameterType, useRunGuard, FluidGridsContext, ExpressionEditor, formatParameterValue, parseParameterValue, useFluidGridsAnalytics, openRunQuotaUpgradePrompt } from './chunk-3QCRKKTI.js';
|
|
7
8
|
import { useBuilderReadOnly } from './chunk-OCJTTHTS.js';
|
|
8
|
-
import { useRunFromNodeEligibilityQuery, PreviewScheduleDocument, WebhookTestListenerDocument, StopWebhookTestListenerDocument, ListenForWebhookTestEventDocument } from './chunk-
|
|
9
|
+
import { useRunFromNodeEligibilityQuery, PreviewScheduleDocument, WebhookTestListenerDocument, StopWebhookTestListenerDocument, ListenForWebhookTestEventDocument } from './chunk-Z3ABLERJ.js';
|
|
9
10
|
import { useTr } from './chunk-UULVIT25.js';
|
|
10
|
-
import { getFluidGridsClientSafe, getFluidGridsClient } from './chunk-
|
|
11
|
+
import { getFluidGridsClientSafe, getFluidGridsClient } from './chunk-3IXU7WUC.js';
|
|
12
|
+
import { throwIfResultError, describeOperationError } from './chunk-US5QSLPV.js';
|
|
11
13
|
import { useId, useState, useMemo, useRef, useEffect, useContext, useCallback } from 'react';
|
|
12
14
|
import { Icon } from '@iconify/react';
|
|
13
15
|
import { cn } from '@burdenoff/fe-libs/utils';
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createLiveTokenReader, createFluidGridsTokenRefreshLink } from './chunk-US5QSLPV.js';
|
|
1
2
|
import { createHttpLink, split, ApolloClient, InMemoryCache } from '@apollo/client/core';
|
|
2
3
|
import { setContext } from '@apollo/client/link/context';
|
|
3
4
|
import { getMainDefinition } from '@apollo/client/utilities';
|
|
@@ -8,33 +9,43 @@ var clientInstance = null;
|
|
|
8
9
|
function createFluidGridsClient(config) {
|
|
9
10
|
const graphqlUrl = getGraphQLUrl(config.apiGatewayUrl);
|
|
10
11
|
const wsUrl = graphqlUrl.replace(/^http/, "ws");
|
|
12
|
+
const readTokens = createLiveTokenReader({
|
|
13
|
+
authToken: config.authToken,
|
|
14
|
+
workspaceToken: config.workspaceToken
|
|
15
|
+
});
|
|
11
16
|
const httpLink = createHttpLink({
|
|
12
17
|
uri: graphqlUrl
|
|
13
18
|
});
|
|
14
|
-
const authLink = setContext((_, { headers }) =>
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
...config.tenantId && { "x-tenant-id": config.tenantId },
|
|
23
|
-
...config.productId && { "x-product-id": config.productId }
|
|
24
|
-
}
|
|
25
|
-
}));
|
|
26
|
-
const wsLink = new GraphQLWsLink(
|
|
27
|
-
createClient({
|
|
28
|
-
url: wsUrl,
|
|
29
|
-
connectionParams: () => ({
|
|
30
|
-
authorization: config.authToken ? `Bearer ${config.authToken}` : "",
|
|
31
|
-
...config.workspaceToken && {
|
|
32
|
-
"x-workspace-authorization": `Bearer ${config.workspaceToken}`
|
|
19
|
+
const authLink = setContext((_, { headers }) => {
|
|
20
|
+
const { authToken, workspaceToken } = readTokens();
|
|
21
|
+
return {
|
|
22
|
+
headers: {
|
|
23
|
+
...headers,
|
|
24
|
+
...authToken && { authorization: `Bearer ${authToken}` },
|
|
25
|
+
...workspaceToken && {
|
|
26
|
+
"x-workspace-authorization": `Bearer ${workspaceToken}`
|
|
33
27
|
},
|
|
34
28
|
"x-workspace-id": config.workspaceId,
|
|
35
29
|
...config.tenantId && { "x-tenant-id": config.tenantId },
|
|
36
30
|
...config.productId && { "x-product-id": config.productId }
|
|
37
|
-
}
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
});
|
|
34
|
+
const wsLink = new GraphQLWsLink(
|
|
35
|
+
createClient({
|
|
36
|
+
url: wsUrl,
|
|
37
|
+
connectionParams: () => {
|
|
38
|
+
const { authToken, workspaceToken } = readTokens();
|
|
39
|
+
return {
|
|
40
|
+
authorization: authToken ? `Bearer ${authToken}` : "",
|
|
41
|
+
...workspaceToken && {
|
|
42
|
+
"x-workspace-authorization": `Bearer ${workspaceToken}`
|
|
43
|
+
},
|
|
44
|
+
"x-workspace-id": config.workspaceId,
|
|
45
|
+
...config.tenantId && { "x-tenant-id": config.tenantId },
|
|
46
|
+
...config.productId && { "x-product-id": config.productId }
|
|
47
|
+
};
|
|
48
|
+
}
|
|
38
49
|
})
|
|
39
50
|
);
|
|
40
51
|
const splitLink = split(
|
|
@@ -43,7 +54,7 @@ function createFluidGridsClient(config) {
|
|
|
43
54
|
return definition.kind === "OperationDefinition" && definition.operation === "subscription";
|
|
44
55
|
},
|
|
45
56
|
wsLink,
|
|
46
|
-
authLink.concat(httpLink)
|
|
57
|
+
createFluidGridsTokenRefreshLink().concat(authLink).concat(httpLink)
|
|
47
58
|
);
|
|
48
59
|
return new ApolloClient({
|
|
49
60
|
link: splitLink,
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { SdkPermissionGate, FLUIDGRIDS_PERMISSIONS } from './chunk-5375NUIO.js';
|
|
2
2
|
import { useBuilderReadOnly, editorSeverity } from './chunk-OCJTTHTS.js';
|
|
3
|
-
import { getGlobalStoreClient, createGlobalStoreClient, setGlobalStoreClient, resetGlobalStoreClient } from './chunk-
|
|
4
|
-
import { getFluidGridsConfig, validateTrustedOrigin, resetFluidGridsExecutionState, setFluidGridsConfig, resetFluidGridsConfig } from './chunk-6AMNEX2Y.js';
|
|
3
|
+
import { getGlobalStoreClient, createGlobalStoreClient, setGlobalStoreClient, resetGlobalStoreClient } from './chunk-AU7LACOY.js';
|
|
5
4
|
import { GetMyNodeInstallationsDocument } from './chunk-G77IGC3Y.js';
|
|
6
|
-
import { fetchAllNodeEndpointConfigs, NodeManifestDocument, UpdateWorkflowDefinitionDocument, CreateWorkflowDefinitionDocument, CreateWorkflowVersionDocument, ExecuteStepDocument, TriggerWorkflowDocument, RunFromNodeDocument, ExecutionDetailDocument, WorkflowDefinitionDocument, WorkflowRunDocument } from './chunk-
|
|
5
|
+
import { fetchAllNodeEndpointConfigs, NodeManifestDocument, UpdateWorkflowDefinitionDocument, CreateWorkflowDefinitionDocument, CreateWorkflowVersionDocument, ExecuteStepDocument, TriggerWorkflowDocument, RunFromNodeDocument, ExecutionDetailDocument, WorkflowDefinitionDocument, WorkflowRunDocument } from './chunk-Z3ABLERJ.js';
|
|
7
6
|
import { useTr, ENGLISH_FALLBACK_TRANSLATOR, FluidGridsTranslationProvider } from './chunk-UULVIT25.js';
|
|
8
|
-
import { waitForFluidGridsClient, getFluidGridsClient, getFluidGridsClientSafe, createFluidGridsClient, setFluidGridsClient, resetFluidGridsClient } from './chunk-
|
|
7
|
+
import { waitForFluidGridsClient, getFluidGridsClient, getFluidGridsClientSafe, createFluidGridsClient, setFluidGridsClient, resetFluidGridsClient } from './chunk-3IXU7WUC.js';
|
|
8
|
+
import { throwIfResultError, emitFluidGridsEvent, emitOperationErrorEvent, describeOperationError, emitRunCompletedOnce } from './chunk-US5QSLPV.js';
|
|
9
|
+
import { getFluidGridsConfig, validateTrustedOrigin, resetFluidGridsExecutionState, resetFluidGridsConfig, setFluidGridsConfig } from './chunk-UEG2WC3G.js';
|
|
9
10
|
import * as React from 'react';
|
|
10
11
|
import { memo, forwardRef, useState, useImperativeHandle, useRef, useEffect, useMemo, createContext, useCallback, useSyncExternalStore, useContext } from 'react';
|
|
11
12
|
import { useOptionalFeatureFlags } from '@burdenoff/fe-libs/shared/feature-flags';
|
|
12
|
-
import { CombinedGraphQLErrors, ServerError } from '@apollo/client/errors';
|
|
13
13
|
import { dispatchUpgradePrompt } from '@burdenoff/fe-libs/shared/components';
|
|
14
14
|
import { nanoid } from 'nanoid/non-secure';
|
|
15
15
|
import { addEdge, applyEdgeChanges, applyNodeChanges, useReactFlow, NodeResizer, getConnectedEdges, useStore, Handle, Position, useUpdateNodeInternals, useNodeId } from '@xyflow/react';
|
|
@@ -275,81 +275,6 @@ function usePaletteGates() {
|
|
|
275
275
|
const context = useOptionalFeatureFlags();
|
|
276
276
|
return useMemo(() => resolvePaletteGates(context), [context]);
|
|
277
277
|
}
|
|
278
|
-
function describeGraphQLError(error) {
|
|
279
|
-
const code = typeof error.extensions?.code === "string" ? error.extensions.code : void 0;
|
|
280
|
-
switch (code) {
|
|
281
|
-
case "QUOTA_EXHAUSTED": {
|
|
282
|
-
const quota = /Quota exhausted for (\S+)/.exec(error.message)?.[1];
|
|
283
|
-
const allowance = quota ? `"${quota}" quota` : "usage quota";
|
|
284
|
-
return `Quota exhausted \u2014 your workspace has used up its ${allowance}. Upgrade your plan or wait for the quota to reset.`;
|
|
285
|
-
}
|
|
286
|
-
case "QUOTA_NOT_PROVISIONED":
|
|
287
|
-
return "This workspace's plan does not include this usage allowance yet. Contact your workspace admin or support to have it provisioned.";
|
|
288
|
-
case "UNAUTHENTICATED":
|
|
289
|
-
return "Your session has expired. Please sign in again.";
|
|
290
|
-
case "FORBIDDEN":
|
|
291
|
-
return error.message || "You don't have permission to perform this action.";
|
|
292
|
-
default:
|
|
293
|
-
return error.message || "Unknown error";
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
function firstGraphQLErrorInBody(bodyText) {
|
|
297
|
-
try {
|
|
298
|
-
const parsed = JSON.parse(bodyText);
|
|
299
|
-
if (typeof parsed !== "object" || parsed === null) return null;
|
|
300
|
-
const errors = parsed.errors;
|
|
301
|
-
if (!Array.isArray(errors) || errors.length === 0) return null;
|
|
302
|
-
const first = errors[0];
|
|
303
|
-
if (typeof first !== "object" || first === null) return null;
|
|
304
|
-
const message = first.message;
|
|
305
|
-
if (typeof message !== "string") return null;
|
|
306
|
-
return first;
|
|
307
|
-
} catch {
|
|
308
|
-
return null;
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
function describeOperationError(error, fallback = "Unknown error") {
|
|
312
|
-
if (CombinedGraphQLErrors.is(error)) {
|
|
313
|
-
const first = error.errors[0];
|
|
314
|
-
return first ? describeGraphQLError(first) : error.message || fallback;
|
|
315
|
-
}
|
|
316
|
-
if (ServerError.is(error)) {
|
|
317
|
-
const first = firstGraphQLErrorInBody(error.bodyText);
|
|
318
|
-
if (first) return describeGraphQLError(first);
|
|
319
|
-
}
|
|
320
|
-
if (error instanceof Error) {
|
|
321
|
-
return error.message || fallback;
|
|
322
|
-
}
|
|
323
|
-
if (typeof error === "string" && error.length > 0) {
|
|
324
|
-
return error;
|
|
325
|
-
}
|
|
326
|
-
return fallback;
|
|
327
|
-
}
|
|
328
|
-
function throwIfResultError(result) {
|
|
329
|
-
if (result.error) {
|
|
330
|
-
throw new Error(describeOperationError(result.error), {
|
|
331
|
-
cause: result.error
|
|
332
|
-
});
|
|
333
|
-
}
|
|
334
|
-
return result;
|
|
335
|
-
}
|
|
336
|
-
function hasForbiddenCode(errors) {
|
|
337
|
-
return (errors ?? []).some((error) => error.extensions?.code === "FORBIDDEN");
|
|
338
|
-
}
|
|
339
|
-
function isForbiddenError(error) {
|
|
340
|
-
if (CombinedGraphQLErrors.is(error)) {
|
|
341
|
-
return hasForbiddenCode(error.errors);
|
|
342
|
-
}
|
|
343
|
-
if (ServerError.is(error)) {
|
|
344
|
-
if (error.statusCode === 403) return true;
|
|
345
|
-
const first = firstGraphQLErrorInBody(error.bodyText);
|
|
346
|
-
return first ? hasForbiddenCode([first]) : false;
|
|
347
|
-
}
|
|
348
|
-
if (error instanceof Error && error.cause !== void 0) {
|
|
349
|
-
return isForbiddenError(error.cause);
|
|
350
|
-
}
|
|
351
|
-
return false;
|
|
352
|
-
}
|
|
353
278
|
|
|
354
279
|
// src/billing/quota.ts
|
|
355
280
|
var RUNS_QUOTA_NAME = "fluidgrids.runs.monthly";
|
|
@@ -6358,6 +6283,9 @@ function FluidGridsProvider({
|
|
|
6358
6283
|
tenantId,
|
|
6359
6284
|
organizationId,
|
|
6360
6285
|
t,
|
|
6286
|
+
theme,
|
|
6287
|
+
auth,
|
|
6288
|
+
onEvent,
|
|
6361
6289
|
workspaceClient: externalWorkspaceClient,
|
|
6362
6290
|
globalClient: externalGlobalClient,
|
|
6363
6291
|
apolloClient: legacyClient,
|
|
@@ -6476,21 +6404,44 @@ function FluidGridsProvider({
|
|
|
6476
6404
|
resetGlobalStoreClient();
|
|
6477
6405
|
};
|
|
6478
6406
|
}, [globalClient]);
|
|
6407
|
+
const appliedTokens = useRef(null);
|
|
6408
|
+
const ownedHostHooks = useRef(/* @__PURE__ */ new Set());
|
|
6409
|
+
useEffect(
|
|
6410
|
+
() => () => {
|
|
6411
|
+
appliedTokens.current = null;
|
|
6412
|
+
ownedHostHooks.current.clear();
|
|
6413
|
+
resetFluidGridsConfig();
|
|
6414
|
+
},
|
|
6415
|
+
[]
|
|
6416
|
+
);
|
|
6479
6417
|
useEffect(() => {
|
|
6480
|
-
|
|
6418
|
+
const patch = {
|
|
6481
6419
|
apiGatewayUrl,
|
|
6482
6420
|
globalApiUrl,
|
|
6483
|
-
authToken,
|
|
6484
|
-
workspaceToken,
|
|
6485
6421
|
workspaceId,
|
|
6486
6422
|
productId: resolvedProductId,
|
|
6487
6423
|
trustedOrigins,
|
|
6488
6424
|
tenantId,
|
|
6489
6425
|
organizationId
|
|
6490
|
-
});
|
|
6491
|
-
return () => {
|
|
6492
|
-
resetFluidGridsConfig();
|
|
6493
6426
|
};
|
|
6427
|
+
const applied = appliedTokens.current;
|
|
6428
|
+
if (!applied || applied.authToken !== authToken || applied.workspaceToken !== workspaceToken) {
|
|
6429
|
+
patch.authToken = authToken;
|
|
6430
|
+
patch.workspaceToken = workspaceToken;
|
|
6431
|
+
appliedTokens.current = { authToken, workspaceToken };
|
|
6432
|
+
}
|
|
6433
|
+
const owned = ownedHostHooks.current;
|
|
6434
|
+
const writes = (key, value) => {
|
|
6435
|
+
if (value !== void 0) {
|
|
6436
|
+
owned.add(key);
|
|
6437
|
+
return true;
|
|
6438
|
+
}
|
|
6439
|
+
return owned.delete(key);
|
|
6440
|
+
};
|
|
6441
|
+
if (writes("theme", theme)) patch.theme = theme;
|
|
6442
|
+
if (writes("auth", auth)) patch.auth = auth;
|
|
6443
|
+
if (writes("onEvent", onEvent)) patch.onEvent = onEvent;
|
|
6444
|
+
setFluidGridsConfig(patch);
|
|
6494
6445
|
}, [
|
|
6495
6446
|
apiGatewayUrl,
|
|
6496
6447
|
globalApiUrl,
|
|
@@ -6500,7 +6451,10 @@ function FluidGridsProvider({
|
|
|
6500
6451
|
resolvedProductId,
|
|
6501
6452
|
trustedOrigins,
|
|
6502
6453
|
tenantId,
|
|
6503
|
-
organizationId
|
|
6454
|
+
organizationId,
|
|
6455
|
+
theme,
|
|
6456
|
+
auth,
|
|
6457
|
+
onEvent
|
|
6504
6458
|
]);
|
|
6505
6459
|
const contextValue = useMemo(() => {
|
|
6506
6460
|
return {
|
|
@@ -7389,6 +7343,11 @@ function useSaveWorkflow() {
|
|
|
7389
7343
|
}
|
|
7390
7344
|
if (savedDbId) {
|
|
7391
7345
|
notifyWorkflowSaved(workflowKey);
|
|
7346
|
+
emitFluidGridsEvent("workflow:saved", {
|
|
7347
|
+
workflowKey,
|
|
7348
|
+
version: savedVersion || void 0,
|
|
7349
|
+
id: savedDbId
|
|
7350
|
+
});
|
|
7392
7351
|
const config = getFluidGridsConfig();
|
|
7393
7352
|
if (config.onWorkflowSaved) {
|
|
7394
7353
|
try {
|
|
@@ -7412,6 +7371,7 @@ function useSaveWorkflow() {
|
|
|
7412
7371
|
} catch (error) {
|
|
7413
7372
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
7414
7373
|
console.error("Error saving workflow:", message);
|
|
7374
|
+
emitOperationErrorEvent("workflow:save", error);
|
|
7415
7375
|
const cause = error instanceof Error ? error.cause : void 0;
|
|
7416
7376
|
const quotaExhausted2 = isQuotaExhaustedFailure(cause) || isQuotaExhaustedFailure(error);
|
|
7417
7377
|
const conflict = findSaveConflict(error);
|
|
@@ -8240,6 +8200,11 @@ function useNodeExecution() {
|
|
|
8240
8200
|
processNodeStates(runId, run.nodeStates);
|
|
8241
8201
|
}
|
|
8242
8202
|
if (TERMINAL_STATUSES.has(run.status)) {
|
|
8203
|
+
emitRunCompletedOnce({
|
|
8204
|
+
runId,
|
|
8205
|
+
status: run.status,
|
|
8206
|
+
workflowKey: run.workflowKey ?? void 0
|
|
8207
|
+
});
|
|
8243
8208
|
if (analyticsTrigger && run.status === "FAILED") {
|
|
8244
8209
|
emitRunFailed(bus, {
|
|
8245
8210
|
workspaceId,
|
|
@@ -8438,6 +8403,11 @@ function useNodeExecution() {
|
|
|
8438
8403
|
executionId: backendRunId,
|
|
8439
8404
|
trigger: "test"
|
|
8440
8405
|
});
|
|
8406
|
+
emitFluidGridsEvent("run:started", {
|
|
8407
|
+
runId: backendRunId,
|
|
8408
|
+
workflowKey: triggerResult.workflowKey,
|
|
8409
|
+
mode: "TEST"
|
|
8410
|
+
});
|
|
8441
8411
|
pollRunUpdates(backendRunId, "test");
|
|
8442
8412
|
return { success: true, runId: backendRunId };
|
|
8443
8413
|
}
|
|
@@ -8446,6 +8416,7 @@ function useNodeExecution() {
|
|
|
8446
8416
|
return { success: false, error: "No result from trigger" };
|
|
8447
8417
|
} catch (error) {
|
|
8448
8418
|
console.error("[useNodeExecution] Error triggering workflow:", error);
|
|
8419
|
+
emitOperationErrorEvent("run:start", error);
|
|
8449
8420
|
const quotaExhausted = openRunQuotaUpgradePrompt(error, tr, {
|
|
8450
8421
|
bus,
|
|
8451
8422
|
workspaceId,
|
|
@@ -8504,6 +8475,11 @@ function useNodeExecution() {
|
|
|
8504
8475
|
executionId: runId,
|
|
8505
8476
|
trigger: "webhook"
|
|
8506
8477
|
});
|
|
8478
|
+
emitFluidGridsEvent("run:started", {
|
|
8479
|
+
runId,
|
|
8480
|
+
workflowKey: workflow.workflowKey || workflow.id,
|
|
8481
|
+
mode: "TEST"
|
|
8482
|
+
});
|
|
8507
8483
|
pollRunUpdates(runId, "webhook");
|
|
8508
8484
|
},
|
|
8509
8485
|
[
|
|
@@ -8553,6 +8529,11 @@ function useNodeExecution() {
|
|
|
8553
8529
|
executionId: backendRunId,
|
|
8554
8530
|
trigger: "test"
|
|
8555
8531
|
});
|
|
8532
|
+
emitFluidGridsEvent("run:started", {
|
|
8533
|
+
runId: backendRunId,
|
|
8534
|
+
workflowKey: runFromNodeResult.workflowKey,
|
|
8535
|
+
mode: "TEST"
|
|
8536
|
+
});
|
|
8556
8537
|
pollRunUpdates(backendRunId, "test");
|
|
8557
8538
|
return { success: true, runId: backendRunId };
|
|
8558
8539
|
}
|
|
@@ -8561,6 +8542,7 @@ function useNodeExecution() {
|
|
|
8561
8542
|
return { success: false, error: "No result from runFromNode" };
|
|
8562
8543
|
} catch (error) {
|
|
8563
8544
|
console.error("[useNodeExecution] Error running from node:", error);
|
|
8545
|
+
emitOperationErrorEvent("run:start", error);
|
|
8564
8546
|
const quotaExhausted = openRunQuotaUpgradePrompt(error, tr, {
|
|
8565
8547
|
bus,
|
|
8566
8548
|
workspaceId,
|
|
@@ -10137,4 +10119,4 @@ function createNodeWithDefaultData(type, data) {
|
|
|
10137
10119
|
return Object.assign(createNodeData(type, defaultData), data);
|
|
10138
10120
|
}
|
|
10139
10121
|
|
|
10140
|
-
export { AUTOSAVE_DEBOUNCE_MS, AUTOSAVE_RETRY_DELAYS_MS, AVAILABLE_NODES, BILLING_PLANS_PATH, CODE_WORKFLOW_NODE_TYPE, ConnectionFormDialog, ConnectionSelector, DURABLE_FUNCTION_NODE_TYPES, EDIT_SESSION_ID, ExpressionEditor, FLUIDGRIDS_FLAGS, FLUIDGRIDS_FLAG_DEFAULTS, FluidGridsContext, FluidGridsProvider, NODES, NODES_METADATA, NODE_CONFIGS, NODE_OPERATION_DRAG_DATA_FORMAT, NODE_TYPES, NODE_TYPE_DRAG_DATA_FORMAT, NodePropertyPanel, NodeTypeIcon, PHASE_C_FLAGS_OFF, RUNS_QUOTA_NAME, RUN_CONTROL_NODE_TYPES, STICKY_NOTE_TYPE, WORKFLOWS_QUOTA_NAME, WORKFLOW_TEST_NODE_TYPES, autosaveAllowedFor, bannerOf, blankWorkflowCreateInput, buildOperationSeed, buildStickyNode, builderPathOf, canAutosave, canRenderOperationPanel, canSignalRun, changedSourceFiles, childRunIdOf, classifyCreateRefusal, clearCodeWorkflowDefinitionCache, codeBuildIdOf, components_default, createConfiguredNode, createThenOpen, declaredOutputFields, declaredSignals, defaultSourcePath, departingSave,
|
|
10122
|
+
export { AUTOSAVE_DEBOUNCE_MS, AUTOSAVE_RETRY_DELAYS_MS, AVAILABLE_NODES, BILLING_PLANS_PATH, CODE_WORKFLOW_NODE_TYPE, ConnectionFormDialog, ConnectionSelector, DURABLE_FUNCTION_NODE_TYPES, EDIT_SESSION_ID, ExpressionEditor, FLUIDGRIDS_FLAGS, FLUIDGRIDS_FLAG_DEFAULTS, FluidGridsContext, FluidGridsProvider, NODES, NODES_METADATA, NODE_CONFIGS, NODE_OPERATION_DRAG_DATA_FORMAT, NODE_TYPES, NODE_TYPE_DRAG_DATA_FORMAT, NodePropertyPanel, NodeTypeIcon, PHASE_C_FLAGS_OFF, RUNS_QUOTA_NAME, RUN_CONTROL_NODE_TYPES, STICKY_NOTE_TYPE, WORKFLOWS_QUOTA_NAME, WORKFLOW_TEST_NODE_TYPES, autosaveAllowedFor, bannerOf, blankWorkflowCreateInput, buildOperationSeed, buildStickyNode, builderPathOf, canAutosave, canRenderOperationPanel, canSignalRun, changedSourceFiles, childRunIdOf, classifyCreateRefusal, clearCodeWorkflowDefinitionCache, codeBuildIdOf, components_default, createConfiguredNode, createThenOpen, declaredOutputFields, declaredSignals, defaultSourcePath, departingSave, diagnosticsByPath, editStateFor, editingLeaseLocked, emitNodeInstalled, emitRunFailed, emitRunLimitHit, emitRunStarted, emitTemplateUsed, emitUpgradeClicked, emitWorkflowCreated, emitWorkflowLimitHit, emitWorkflowPublished, ensureNodeConfigsLoaded, fieldsFromIO, fieldsFromValue, filterPaletteNodes, findQuotaRefusal, findSaveConflict, forgetSessionForReload, formatParameterValue, getNodeDetail, getNodeMetadata, inAppLeaveTarget, interfaceFields, interfaceHandlers, isDurableFunctionNodeType, isEditableSourcePath, isFlowComplete, isImageIcon, isLocked, isNodeConfigsInitialized, isNodeTypeHiddenFromPalette, isParamVisible, isQuotaExhaustedFailure, isRunControlNodeType, isTriggerOperation, leaseCallQueue, leavingLosesChanges, listCustomBlocks, liveInternalOperations, loadDefinitionJson, mergeStickyNotes, nodeAccent, nodesOf, onNodeTypesUpdate, openRunQuotaUpgradePrompt, parseParameterValue, parseRawSignalPayload, pathToExpression, payloadFromCardValues, phaseAfterAcquire, phaseAfterTakeOver, projectLanguage, readCodeWorkflowState, readDisplayOptions, refetchStoreNodes, registerCustomBlock, registerWorkflowNodeTypes, releasesOnClose, rememberOwnStatusChange, rememberRevision, rememberSessionForReload, resolveInputHandles, resolveNodeOperation, resolveOperationName, resolveOutputHandles, resolvePhaseCFlags, resolveUiSpec, runSignalTargets, runTriggerFromMode, saveIndicatorOf, savedEverythingBeforeLeaving, sessionBeforeReload, shouldReleaseForIdle, signalPayloadCard, sourceLanguageOf, stripSubmitActions, structuredParameterType, subscribeWorkflowSaved, synchronizeOperationUpdate, tickAction, touchesSavedFields, useAgentDefinitionList, useAgentDefinitions, useCodeWorkflowInterface, useConnection, useConnections, useConnectionsByProvider, useContinuousOptimisationEnabled, useCreateConnection, useDurableFunctionNodesEnabled, useDurableParityEnabled, useEditLeaseLocked, useEditLeaseStore, useFlowStore, useFlowValidator, useFluidGridsAnalytics, useFluidGridsContext, useFluidGridsFlag, useGuardedNavigate, useInitiateOAuth, useInsertNode, useIsValidConnection, useManualSave, useNodeExecution, useNodeRegistryRevision, usePaletteGates, usePhaseCFlags, useProviders, useRunGuard, useSaveStatusStore, useSaveWorkflow, useSelfHostedWorkersEnabled, useWorkflowTestsEnabled, watchLeavingLosesChanges, workflowFingerprint };
|