@tai42/studio-sdk 9.3.0 → 11.0.0
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 +45 -6
- package/SECURITY.md +10 -2
- package/dist/components/components.css +18 -0
- package/dist/components/dirty-guard.d.ts +23 -10
- package/dist/components/dirty-guard.d.ts.map +1 -1
- package/dist/components/dirty-guard.js +22 -12
- package/dist/components/dirty-guard.js.map +1 -1
- package/dist/components/field.d.ts.map +1 -1
- package/dist/components/field.js +1 -1
- package/dist/components/field.js.map +1 -1
- package/dist/components/fleet-report.d.ts +12 -3
- package/dist/components/fleet-report.d.ts.map +1 -1
- package/dist/components/fleet-report.js +28 -9
- package/dist/components/fleet-report.js.map +1 -1
- package/dist/components/icons.d.ts +4 -0
- package/dist/components/icons.d.ts.map +1 -1
- package/dist/components/icons.js +5 -0
- package/dist/components/icons.js.map +1 -1
- package/dist/hooks/useApi.d.ts +348 -2
- package/dist/hooks/useApi.d.ts.map +1 -1
- package/dist/host.d.ts +1 -1
- package/dist/host.d.ts.map +1 -1
- package/dist/index.d.ts +18 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +23 -11
- package/dist/index.js.map +1 -1
- package/dist/navigation/context.d.ts +6 -2
- package/dist/navigation/context.d.ts.map +1 -1
- package/dist/navigation/context.js +10 -2
- package/dist/navigation/context.js.map +1 -1
- package/dist/navigation/types.d.ts +1 -0
- package/dist/navigation/types.d.ts.map +1 -1
- package/dist/plugin/host-state.d.ts +16 -0
- package/dist/plugin/host-state.d.ts.map +1 -1
- package/dist/plugin/host-state.js +1 -0
- package/dist/plugin/host-state.js.map +1 -1
- package/dist/plugin/types.d.ts +17 -7
- package/dist/plugin/types.d.ts.map +1 -1
- package/dist/schema-form/SchemaForm.d.ts +4 -3
- package/dist/schema-form/SchemaForm.d.ts.map +1 -1
- package/dist/schema-form/SchemaForm.js.map +1 -1
- package/dist/schema-form/SecretRefField.d.ts.map +1 -1
- package/dist/schema-form/SecretRefField.js +3 -2
- package/dist/schema-form/SecretRefField.js.map +1 -1
- package/dist/schema-form/context.d.ts +2 -2
- package/dist/schema-form/default-value.d.ts +12 -0
- package/dist/schema-form/default-value.d.ts.map +1 -1
- package/dist/schema-form/default-value.js +34 -3
- package/dist/schema-form/default-value.js.map +1 -1
- package/dist/schema-form/field-node.d.ts +7 -0
- package/dist/schema-form/field-node.d.ts.map +1 -1
- package/dist/schema-form/field-node.js +3 -2
- package/dist/schema-form/field-node.js.map +1 -1
- package/dist/schema-form/index.d.ts +11 -11
- package/dist/schema-form/index.js +11 -11
- package/dist/schema-form/object-fields.d.ts +3 -1
- package/dist/schema-form/object-fields.d.ts.map +1 -1
- package/dist/schema-form/object-fields.js +2 -2
- package/dist/schema-form/object-fields.js.map +1 -1
- package/dist/schema-form/string-field.d.ts +3 -2
- package/dist/schema-form/string-field.d.ts.map +1 -1
- package/dist/schema-form/string-field.js.map +1 -1
- package/dist/schema-form/union-field.d.ts +5 -2
- package/dist/schema-form/union-field.d.ts.map +1 -1
- package/dist/schema-form/union-field.js +68 -15
- package/dist/schema-form/union-field.js.map +1 -1
- package/package.json +3 -3
- package/src/components/components.css +18 -0
- package/src/components/dirty-guard.tsx +23 -13
- package/src/components/field.tsx +10 -5
- package/src/components/fleet-report.tsx +44 -13
- package/src/components/icons.tsx +19 -0
- package/src/host.ts +5 -1
- package/src/index.ts +24 -31
- package/src/navigation/context.tsx +16 -1
- package/src/navigation/types.ts +3 -0
- package/src/plugin/host-state.ts +18 -0
- package/src/plugin/types.ts +17 -7
- package/src/schema-form/SchemaForm.tsx +4 -3
- package/src/schema-form/SecretRefField.tsx +3 -2
- package/src/schema-form/context.ts +2 -2
- package/src/schema-form/default-value.ts +36 -3
- package/src/schema-form/field-node.tsx +21 -2
- package/src/schema-form/index.ts +11 -11
- package/src/schema-form/object-fields.tsx +4 -0
- package/src/schema-form/string-field.tsx +3 -2
- package/src/schema-form/union-field.tsx +85 -19
- package/dist/jq.d.ts +0 -31
- package/dist/jq.d.ts.map +0 -1
- package/dist/jq.js +0 -41
- package/dist/jq.js.map +0 -1
- package/src/jq.ts +0 -61
|
@@ -3,7 +3,7 @@ import { FieldNode } from './field-node';
|
|
|
3
3
|
function isPlainObject(value) {
|
|
4
4
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
5
5
|
}
|
|
6
|
-
export function ObjectFields({ properties, requiredKeys, root, value, onChange, path, errors, idPrefix, skip, }) {
|
|
6
|
+
export function ObjectFields({ properties, requiredKeys, root, value, onChange, path, errors, idPrefix, skip, markRequired = false, }) {
|
|
7
7
|
const obj = isPlainObject(value) ? value : {};
|
|
8
8
|
return (_jsx(_Fragment, { children: properties.map(([name, propSchema]) => {
|
|
9
9
|
if (skip !== undefined && name === skip)
|
|
@@ -11,7 +11,7 @@ export function ObjectFields({ properties, requiredKeys, root, value, onChange,
|
|
|
11
11
|
const childPath = path === '' ? name : `${path}.${name}`;
|
|
12
12
|
return (_jsx(FieldNode, { schema: propSchema, root: root, value: obj[name], onChange: (next) => {
|
|
13
13
|
onChange(setKey(obj, name, next));
|
|
14
|
-
}, path: childPath, label: name, required: requiredKeys.has(name), errors: errors, idPrefix: idPrefix }, name));
|
|
14
|
+
}, path: childPath, label: name, required: requiredKeys.has(name), markRequired: markRequired, errors: errors, idPrefix: idPrefix }, name));
|
|
15
15
|
}) }));
|
|
16
16
|
}
|
|
17
17
|
function setKey(obj, name, next) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"object-fields.js","sourceRoot":"","sources":["../../src/schema-form/object-fields.tsx"],"names":[],"mappings":";AAQA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAGzC,SAAS,aAAa,CAAC,KAAc;IACnC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,EAC3B,UAAU,EACV,YAAY,EACZ,IAAI,EACJ,KAAK,EACL,QAAQ,EACR,IAAI,EACJ,MAAM,EACN,QAAQ,EACR,IAAI,
|
|
1
|
+
{"version":3,"file":"object-fields.js","sourceRoot":"","sources":["../../src/schema-form/object-fields.tsx"],"names":[],"mappings":";AAQA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAGzC,SAAS,aAAa,CAAC,KAAc;IACnC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,EAC3B,UAAU,EACV,YAAY,EACZ,IAAI,EACJ,KAAK,EACL,QAAQ,EACR,IAAI,EACJ,MAAM,EACN,QAAQ,EACR,IAAI,EACJ,YAAY,GAAG,KAAK,GAarB;IACC,MAAM,GAAG,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9C,OAAO,CACL,4BACG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,UAAU,CAAC,EAAE,EAAE;YACrC,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,IAAI;gBAAE,OAAO,IAAI,CAAC;YACrD,MAAM,SAAS,GAAG,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,IAAI,EAAE,CAAC;YACzD,OAAO,CACL,KAAC,SAAS,IAER,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,GAAG,CAAC,IAAI,CAAC,EAChB,QAAQ,EAAE,CAAC,IAAI,EAAE,EAAE;oBACjB,QAAQ,CAAC,MAAM,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;gBACpC,CAAC,EACD,IAAI,EAAE,SAAS,EACf,KAAK,EAAE,IAAI,EACX,QAAQ,EAAE,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,EAChC,YAAY,EAAE,YAAY,EAC1B,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,QAAQ,IAZb,IAAI,CAaT,CACH,CAAC;QACJ,CAAC,CAAC,GACD,CACJ,CAAC;AACJ,CAAC;AAED,SAAS,MAAM,CACb,GAA4B,EAC5B,IAAY,EACZ,IAAa;IAEb,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,GAAG,GAAG,CAAC;QAC1C,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,EAAE,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC;AAClC,CAAC"}
|
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
* control instead; and when the form supplies a completion provider, the input is
|
|
7
7
|
* backed by argument autocomplete.
|
|
8
8
|
*
|
|
9
|
-
* NO JQ EDGE. This module — and every module under `schema-form
|
|
10
|
-
*
|
|
9
|
+
* NO JQ EDGE. This module — and every module under `schema-form`, and the package
|
|
10
|
+
* barrel above them — names no jq type and imports `@tai42/jq-studio` neither
|
|
11
|
+
* statically NOR dynamically.
|
|
11
12
|
* The jq authoring door drags a heavy subgraph (the xyflow visual editor, a Web
|
|
12
13
|
* Worker entry, and a multi-megabyte wasm engine), and a bundler EMITS that whole
|
|
13
14
|
* subgraph for a dynamic import just as it does for a static one — `lazy` defers
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"string-field.d.ts","sourceRoot":"","sources":["../../src/schema-form/string-field.tsx"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"string-field.d.ts","sourceRoot":"","sources":["../../src/schema-form/string-field.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAQvC,OAAO,KAAK,EAAE,oBAAoB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAMpE,wBAAgB,WAAW,CAAC,EAC1B,OAAO,EACP,WAAW,EACX,KAAK,EACL,MAAM,EACN,KAAK,EACL,UAAU,EACV,OAAO,EACP,KAAK,EACL,QAAQ,EACR,QAAQ,GACT,EAAE;IACD,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,KAAK,EAAE,WAAW,GAAG,SAAS,CAAC;IAC/B,UAAU,EAAE,oBAAoB,GAAG,SAAS,CAAC;IAC7C,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CACpC,GAAG,SAAS,CAqEZ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"string-field.js","sourceRoot":"","sources":["../../src/schema-form/string-field.tsx"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"string-field.js","sourceRoot":"","sources":["../../src/schema-form/string-field.tsx"],"names":[],"mappings":";AAqBA,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAE7E,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAGzC,OAAO,EAAE,yBAAyB,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AAC9E,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAG3C,MAAM,UAAU,WAAW,CAAC,EAC1B,OAAO,EACP,WAAW,EACX,KAAK,EACL,MAAM,EACN,KAAK,EACL,UAAU,EACV,OAAO,EACP,KAAK,EACL,QAAQ,EACR,QAAQ,GAYT;IACC,MAAM,kBAAkB,GAAG,UAAU,CAAC,yBAAyB,CAAC,CAAC;IACjE,MAAM,eAAe,GAAG,UAAU,CAAC,sBAAsB,CAAC,CAAC;IAC3D,MAAM,OAAO,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;IACvD,4EAA4E;IAC5E,oDAAoD;IACpD,MAAM,IAAI,GAAG,CAAC,IAAY,EAAQ,EAAE;QAClC,QAAQ,CAAC,IAAI,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACxD,CAAC,CAAC;IAEF,gFAAgF;IAChF,+EAA+E;IAC/E,6EAA6E;IAC7E,6EAA6E;IAC7E,uEAAuE;IACvE,iEAAiE;IACjE,EAAE;IACF,gFAAgF;IAChF,0EAA0E;IAC1E,qCAAqC;IACrC,IAAI,UAAU,KAAK,SAAS,IAAI,eAAe,KAAK,SAAS,EAAE,CAAC;QAC9D,OAAO,CACL,KAAC,eAAe,IACd,SAAS,EAAE,eAAe,EAC1B,OAAO,EAAE,OAAO,EAChB,WAAW,EAAE,WAAW,EACxB,KAAK,EAAE,KAAK,EACZ,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,IAAI,GACd,CACH,CAAC;IACJ,CAAC;IAED,4EAA4E;IAC5E,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,OAAO,CACL,KAAC,UAAU,IACT,OAAO,EAAE,OAAO,EAChB,WAAW,EAAE,WAAW,EACxB,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,IAAI,GACd,CACH,CAAC;IACJ,CAAC;IAED,OAAO,CACL,KAAC,KAAK,IAAC,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK,YAC1D,kBAAkB,KAAK,SAAS,CAAC,CAAC,CAAC,CAClC,KAAC,eAAe,IACd,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,IAAI,EACd,QAAQ,EAAE,kBAAkB,GAC5B,CACH,CAAC,CAAC,CAAC,CACF,KAAC,SAAS,IACR,IAAI,EAAE,eAAe,CAAC,MAAM,CAAC,EAC7B,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE;gBAClB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC3B,CAAC,GACD,CACH,GACK,CACT,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,SAAS,eAAe,CAAC,EACvB,OAAO,EACP,KAAK,EACL,QAAQ,EACR,QAAQ,GAMT;IACC,2EAA2E;IAC3E,+EAA+E;IAC/E,qDAAqD;IACrD,MAAM,gBAAgB,GAAG,WAAW,CAClC,CAAC,OAAe,EAAE,EAAE,CAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,EAC/C,CAAC,QAAQ,EAAE,OAAO,CAAC,CACpB,CAAC;IACF,8EAA8E;IAC9E,6EAA6E;IAC7E,4EAA4E;IAC5E,8EAA8E;IAC9E,+BAA+B;IAC/B,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAC;IAC5D,kEAAkE;IAClE,MAAM,OAAO,GAAG,WAAW,CACzB,CAAC,KAAc,EAAE,EAAE;QACjB,OAAO,CAAC,KAAK,CAAC,kDAAkD,OAAO,GAAG,EAAE,KAAK,CAAC,CAAC;QACnF,UAAU,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;IAClC,CAAC,EACD,CAAC,OAAO,CAAC,CACV,CAAC;IAEF,OAAO,CACL,8BACE,KAAC,eAAe,IACd,KAAK,EAAE,KAAK;gBACZ,uEAAuE;gBACvE,2DAA2D;gBAC3D,QAAQ,EAAE,CAAC,IAAI,EAAE,EAAE;oBACjB,UAAU,CAAC,IAAI,CAAC,CAAC;oBACjB,QAAQ,CAAC,IAAI,CAAC,CAAC;gBACjB,CAAC,EACD,gBAAgB,EAAE,gBAAgB,EAClC,OAAO,EAAE,OAAO,GAChB,EAID,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CACzB,aAAG,IAAI,EAAC,QAAQ,EAAC,SAAS,EAAC,gBAAgB,EAAC,KAAK,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,aAC9D,KAAC,iBAAiB,KAAG,EACpB,gCAAgC,OAAO,EAAE,IACxC,CACL,IACA,CACJ,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,SAAS,eAAe,CAAC,EACvB,SAAS,EAAE,IAAI,EACf,OAAO,EACP,WAAW,EACX,KAAK,EACL,UAAU,EACV,OAAO,EACP,KAAK,EACL,QAAQ,GAUT;IACC,6EAA6E;IAC7E,+CAA+C;IAC/C,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,eAAe,CAAC,UAAU,EAAE,OAAO,CAAC,EAAE,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;IACzF,OAAO,CACL,KAAC,QAAQ,IACP,QAAQ,EACN,KAAC,uBAAuB,IACtB,OAAO,EAAE,OAAO,EAChB,WAAW,EAAE,WAAW,EACxB,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,KAAK,GACZ,YAGJ,KAAC,IAAI,IACH,KAAK,EAAE,OAAO,EACd,WAAW,EAAE,WAAW,EACxB,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,KAAK,EACZ,SAAS,QACT,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,QAAQ,GAClB,GACO,CACZ,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,SAAS,uBAAuB,CAAC,EAC/B,OAAO,EACP,WAAW,EACX,KAAK,EACL,KAAK,GAMN;IACC,OAAO,CACL,KAAC,KAAK,IAAC,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK,YAC3D,KAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,qBAAW,MAAM,GAAG,GAC9C,CACT,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,SAAS,eAAe,CACtB,UAAgC,EAChC,OAAe;IAEf,MAAM,QAAQ,GACZ,UAAU,CAAC,KAAK,KAAK,SAAS;QAC9B,UAAU,CAAC,KAAK,KAAK,SAAS;QAC9B,UAAU,CAAC,IAAI,KAAK,SAAS;QAC7B,UAAU,CAAC,OAAO,KAAK,SAAS;QAChC,UAAU,CAAC,OAAO,KAAK,SAAS;QAChC,UAAU,CAAC,SAAS,CAAC;IACvB,IAAI,CAAC,QAAQ;QAAE,OAAO,SAAS,CAAC;IAChC,OAAO;QACL,0EAA0E;QAC1E,EAAE,EAAE,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,qBAAqB,OAAO,EAAE;QACzE,KAAK,EAAE,UAAU,CAAC,KAAK,IAAI,OAAO;QAClC,KAAK,EAAE,UAAU,CAAC,KAAK,IAAI,EAAE;QAC7B,IAAI,EAAE,UAAU,CAAC,IAAI,IAAI,EAAE;QAC3B,OAAO,EAAE,UAAU,CAAC,OAAO,IAAI,EAAE;QACjC,GAAG,CAAC,UAAU,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC;QAC5E,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC/D,CAAC;AACJ,CAAC;AAED,MAAM,kBAAkB,GAA2B;IACjD,KAAK,EAAE,OAAO;IACd,GAAG,EAAE,KAAK;IACV,eAAe,EAAE,KAAK;IACtB,IAAI,EAAE,MAAM;IACZ,WAAW,EAAE,gBAAgB;IAC7B,IAAI,EAAE,MAAM;CACb,CAAC;AAEF,SAAS,eAAe,CAAC,MAA0B;IACjD,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC;IACxC,OAAO,kBAAkB,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC;AAC9C,CAAC"}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The union field renderer: a variant picker plus the active variant's fields.
|
|
3
3
|
* An object variant renders its properties inline (skipping the discriminator
|
|
4
|
-
* tag, which the picker owns)
|
|
5
|
-
*
|
|
4
|
+
* tag, which the picker owns), with the variant's required fields carrying the
|
|
5
|
+
* design system's required marker; a scalar/enum variant renders as a single
|
|
6
|
+
* nested {@link FieldNode}. Selecting a variant seeds a concrete value for it,
|
|
7
|
+
* preserving the fields the outgoing value shares with the new variant (see
|
|
8
|
+
* {@link switchVariantValue}).
|
|
6
9
|
*/
|
|
7
10
|
import type { ReactNode } from 'react';
|
|
8
11
|
import { type FieldModel } from './classify';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"union-field.d.ts","sourceRoot":"","sources":["../../src/schema-form/union-field.tsx"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"union-field.d.ts","sourceRoot":"","sources":["../../src/schema-form/union-field.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAIvC,OAAO,EAAkB,KAAK,UAAU,EAAqB,MAAM,YAAY,CAAC;AAQhF,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAqF5D,wBAAgB,UAAU,CAAC,EACzB,OAAO,EACP,WAAW,EACX,KAAK,EACL,KAAK,EACL,IAAI,EACJ,KAAK,EACL,QAAQ,EACR,IAAI,EACJ,MAAM,EACN,QAAQ,GACT,EAAE;IACD,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,KAAK,EAAE,OAAO,CAAC,UAAU,EAAE;QAAE,IAAI,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAC9C,IAAI,EAAE,UAAU,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,gBAAgB,GAAG,SAAS,CAAC;IACrC,QAAQ,EAAE,MAAM,CAAC;CAClB,GAAG,SAAS,CA2DZ"}
|
|
@@ -2,21 +2,25 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { Field } from '../components/field';
|
|
3
3
|
import { Select } from '../components/select';
|
|
4
4
|
import { classifySchema } from './classify';
|
|
5
|
-
import {
|
|
5
|
+
import { skeletonValueForSchema } from './default-value';
|
|
6
6
|
import { FieldGroup } from './field-group';
|
|
7
7
|
import { FieldNode } from './field-node';
|
|
8
8
|
import { ObjectFields } from './object-fields';
|
|
9
9
|
import { resolveRef } from './resolve';
|
|
10
10
|
import { groupClass } from './styles';
|
|
11
11
|
import { activeVariantIndex } from './union';
|
|
12
|
+
function isPlainObject(value) {
|
|
13
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
14
|
+
}
|
|
12
15
|
/**
|
|
13
|
-
* A concrete seed for a chosen union variant. Object variants get their
|
|
14
|
-
* required
|
|
16
|
+
* A concrete seed for a chosen union variant. Object variants get their full
|
|
17
|
+
* skeleton (every required field minted, so the seed validates against the
|
|
18
|
+
* variant's own schema); a scalar/enum variant that has no explicit default
|
|
15
19
|
* still needs a non-`undefined` value so the selection sticks (otherwise
|
|
16
20
|
* `activeVariantIndex` reads it back as "no variant" and the picker snaps empty).
|
|
17
21
|
*/
|
|
18
22
|
function seedVariantValue(schema, root) {
|
|
19
|
-
const seeded =
|
|
23
|
+
const seeded = skeletonValueForSchema(schema, root);
|
|
20
24
|
if (seeded !== undefined)
|
|
21
25
|
return seeded;
|
|
22
26
|
const resolved = resolveRef(schema, root);
|
|
@@ -24,16 +28,65 @@ function seedVariantValue(schema, root) {
|
|
|
24
28
|
return resolved.const;
|
|
25
29
|
if (resolved.enum !== undefined && resolved.enum.length > 0)
|
|
26
30
|
return resolved.enum[0];
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* The value committed when the user switches to `target`. Typed values SURVIVE
|
|
35
|
+
* the switch: the target's skeleton is minted first, then every top-level field
|
|
36
|
+
* of the current value whose NAME exists in the target variant's properties is
|
|
37
|
+
* carried over wholesale — the merge happens at the top level only, each carried
|
|
38
|
+
* field keeping its nested contents as-is — so fields both variants share are
|
|
39
|
+
* never silently discarded. Only fields absent from the current value keep
|
|
40
|
+
* their freshly minted seed. The discriminator tag is never carried: it always
|
|
41
|
+
* comes from the target's seed (the old tag would re-select the old variant).
|
|
42
|
+
* A non-object side (scalar variant, or a non-object current value) has no
|
|
43
|
+
* fields to carry, so it reseeds wholesale.
|
|
44
|
+
*/
|
|
45
|
+
function switchVariantValue(current, target, discriminator, root) {
|
|
46
|
+
const seeded = seedVariantValue(target.schema, root);
|
|
47
|
+
if (!isPlainObject(current) || !isPlainObject(seeded))
|
|
48
|
+
return seeded;
|
|
49
|
+
const { model } = classifySchema(target.schema, root);
|
|
50
|
+
if (model.kind !== 'object')
|
|
51
|
+
return seeded;
|
|
52
|
+
const targetNames = new Set(model.properties.map(([name]) => name));
|
|
53
|
+
const merged = { ...seeded };
|
|
54
|
+
for (const [name, held] of Object.entries(current)) {
|
|
55
|
+
if (name === discriminator)
|
|
56
|
+
continue;
|
|
57
|
+
if (targetNames.has(name))
|
|
58
|
+
merged[name] = held;
|
|
59
|
+
}
|
|
60
|
+
return merged;
|
|
61
|
+
}
|
|
62
|
+
/** Title-case a property name: `kind` → "Kind", `content_type` → "Content Type". */
|
|
63
|
+
function titleCaseName(name) {
|
|
64
|
+
return name
|
|
65
|
+
.split(/[_\-\s]+/)
|
|
66
|
+
.filter((part) => part.length > 0)
|
|
67
|
+
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
68
|
+
.join(' ');
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* The variant picker's label. A discriminated union names the picker after the
|
|
72
|
+
* discriminator property it sets — the property's schema `title` when a variant
|
|
73
|
+
* declares one, else the property name title-cased — so the picker reads as the
|
|
74
|
+
* field it is ("Kind", "Format"). Only a union without a discriminator falls
|
|
75
|
+
* back to the generic "Variant".
|
|
76
|
+
*/
|
|
77
|
+
function pickerLabel(discriminator, variants, root) {
|
|
78
|
+
if (discriminator === undefined)
|
|
79
|
+
return 'Variant';
|
|
80
|
+
for (const variant of variants) {
|
|
81
|
+
const property = resolveRef(variant.schema, root).properties?.[discriminator];
|
|
82
|
+
if (property === undefined)
|
|
83
|
+
continue;
|
|
84
|
+
const title = property.title ?? resolveRef(property, root).title;
|
|
85
|
+
if (typeof title === 'string' && title.length > 0)
|
|
86
|
+
return title;
|
|
36
87
|
}
|
|
88
|
+
const cased = titleCaseName(discriminator);
|
|
89
|
+
return cased.length > 0 ? cased : 'Variant';
|
|
37
90
|
}
|
|
38
91
|
export function UnionField({ heading, description, error, model, root, value, onChange, path, errors, idPrefix, }) {
|
|
39
92
|
const index = activeVariantIndex(value, model.variants, model.discriminator, root);
|
|
@@ -46,10 +99,10 @@ export function UnionField({ heading, description, error, model, root, value, on
|
|
|
46
99
|
const variant = model.variants[position];
|
|
47
100
|
if (variant === undefined)
|
|
48
101
|
return;
|
|
49
|
-
onChange(
|
|
102
|
+
onChange(switchVariantValue(value, variant, model.discriminator, root));
|
|
50
103
|
};
|
|
51
104
|
const active = index === -1 ? undefined : model.variants[index];
|
|
52
105
|
const activeClassified = active === undefined ? undefined : classifySchema(active.schema, root);
|
|
53
|
-
return (_jsxs(FieldGroup, { heading: heading, description: description, error: error, atRoot:
|
|
106
|
+
return (_jsxs(FieldGroup, { heading: heading, description: description, error: error, atRoot: path === '', children: [_jsx(Field, { label: pickerLabel(model.discriminator, model.variants, root), children: _jsx(Select, { options: options, value: index === -1 ? '' : String(index), placeholder: "Select a variant\u2026", onValueChange: selectVariant }) }), activeClassified?.model.kind === 'object' ? (_jsx("div", { className: groupClass, children: _jsx(ObjectFields, { properties: activeClassified.model.properties, requiredKeys: activeClassified.model.required, root: root, value: value, onChange: onChange, path: path, errors: errors, idPrefix: idPrefix, skip: model.discriminator, markRequired: true }) })) : active !== undefined ? (_jsx(FieldNode, { schema: active.schema, root: root, value: value, onChange: onChange, path: path, label: active.label, required: true, errors: errors, idPrefix: idPrefix })) : null] }));
|
|
54
107
|
}
|
|
55
108
|
//# sourceMappingURL=union-field.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"union-field.js","sourceRoot":"","sources":["../../src/schema-form/union-field.tsx"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"union-field.js","sourceRoot":"","sources":["../../src/schema-form/union-field.tsx"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tai42/studio-sdk",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "11.0.0",
|
|
4
4
|
"description": "The Studio plugin contract, shared UI components, and hooks that every feature builds on.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "tai42 <oss@tai42.ai>",
|
|
@@ -73,6 +73,7 @@
|
|
|
73
73
|
},
|
|
74
74
|
"devDependencies": {
|
|
75
75
|
"@microsoft/api-extractor": "7.58.12",
|
|
76
|
+
"@tai42/jq-studio": "^0.1.3",
|
|
76
77
|
"@testing-library/jest-dom": "^6.9.1",
|
|
77
78
|
"@testing-library/react": "^16.3.2",
|
|
78
79
|
"@testing-library/user-event": "^14.6.6",
|
|
@@ -94,8 +95,7 @@
|
|
|
94
95
|
"@radix-ui/react-select": "^2.3.2",
|
|
95
96
|
"@radix-ui/react-tabs": "^1.1.16",
|
|
96
97
|
"@radix-ui/react-tooltip": "^1.2.11",
|
|
97
|
-
"@tai42/
|
|
98
|
-
"@tai42/api-client": "9.3.0"
|
|
98
|
+
"@tai42/api-client": "11.0.0"
|
|
99
99
|
},
|
|
100
100
|
"scripts": {
|
|
101
101
|
"build": "tsc -b tsconfig.build.json && node scripts/copy-assets.mjs",
|
|
@@ -984,6 +984,24 @@
|
|
|
984
984
|
background-image: linear-gradient(var(--tai-color-accent-tint), var(--tai-color-accent-tint));
|
|
985
985
|
}
|
|
986
986
|
|
|
987
|
+
/* The HOST-APPLIED provenance mark on plugin-contributed nav (the shell renders
|
|
988
|
+
it; a plugin cannot suppress or restyle it). A small muted glyph that links to
|
|
989
|
+
the plugin's marketplace row and brightens on hover/focus. It sits beside a nav
|
|
990
|
+
row (per-entry, in a core section) or beside a self-named section header. */
|
|
991
|
+
.tai-plugin-badge {
|
|
992
|
+
display: inline-flex;
|
|
993
|
+
align-items: center;
|
|
994
|
+
justify-content: center;
|
|
995
|
+
flex: none;
|
|
996
|
+
color: var(--tai-color-text-muted);
|
|
997
|
+
border-radius: var(--tai-radius-sm);
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
.tai-plugin-badge:hover,
|
|
1001
|
+
.tai-plugin-badge:focus-visible {
|
|
1002
|
+
color: var(--tai-color-text);
|
|
1003
|
+
}
|
|
1004
|
+
|
|
987
1005
|
/* Skip-to-content: off-screen until focused, so a keyboard or screen-reader
|
|
988
1006
|
user can bypass the sidebar nav and jump straight to the page content
|
|
989
1007
|
(WCAG 2.4.1). It is the first focusable element in the shell. */
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Unsaved-changes guard for
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* {@link
|
|
7
|
-
*
|
|
2
|
+
* Unsaved-changes guard for editors that get torn down or navigated away from. One
|
|
3
|
+
* registry closes the gap: editors report dirtiness via {@link useRegisterDirty}; the
|
|
4
|
+
* enclosing {@link DirtyGuardBoundary} arms {@link useNavigationGuard} from that
|
|
5
|
+
* registry, so a route navigation confirms through a shared dialog and a full-page
|
|
6
|
+
* unload raises the native prompt. {@link GuardedTabs} adds a tab-switch confirm on
|
|
7
|
+
* top of the same boundary — `Tabs` unmount inactive panels, so a switch away from a
|
|
8
|
+
* dirty editor is held behind the confirm too. The dialog is one shared
|
|
8
9
|
* {@link ConfirmDialog} driven by a pending-promise resolver, so the guard's
|
|
9
10
|
* `Promise<boolean>` handler and the tab switch both settle against it.
|
|
10
11
|
*/
|
|
@@ -36,7 +37,16 @@ interface DirtyGuardValue {
|
|
|
36
37
|
|
|
37
38
|
const DirtyGuardContext = createContext<DirtyGuardValue | null>(null);
|
|
38
39
|
|
|
39
|
-
|
|
40
|
+
/**
|
|
41
|
+
* Boundary that guards navigation away from a region holding a dirty editor. Editors
|
|
42
|
+
* inside it arm the guard through {@link useRegisterDirty}; while any is dirty a route
|
|
43
|
+
* navigation (a route-token/plugin navigate, an {@link AppLink}, or a browser
|
|
44
|
+
* back/forward) confirms through the shared discard dialog, and a full-page unload
|
|
45
|
+
* raises the native prompt. Use this directly to guard a dirty editor that is a plain
|
|
46
|
+
* page section (no tabs); {@link GuardedTabs} wraps this same boundary to additionally
|
|
47
|
+
* guard tab switches.
|
|
48
|
+
*/
|
|
49
|
+
export function DirtyGuardBoundary({ children }: { readonly children: ReactNode }): ReactNode {
|
|
40
50
|
const dirtyIds = useRef<Set<string>>(new Set());
|
|
41
51
|
// Mirror the registry's non-empty state into React so the navigation guard's
|
|
42
52
|
// `when` re-arms as editors go dirty/clean.
|
|
@@ -96,9 +106,9 @@ function DirtyGuardProvider({ children }: { readonly children: ReactNode }): Rea
|
|
|
96
106
|
}
|
|
97
107
|
|
|
98
108
|
/**
|
|
99
|
-
* Report an editor's dirty state to the enclosing {@link
|
|
100
|
-
* outside a
|
|
101
|
-
* the hook is always safe to call.
|
|
109
|
+
* Report an editor's dirty state to the enclosing {@link DirtyGuardBoundary} (which
|
|
110
|
+
* {@link GuardedTabs} also provides). A no-op outside a boundary (an editor rendered
|
|
111
|
+
* standalone, e.g. in isolation tests) so the hook is always safe to call.
|
|
102
112
|
*/
|
|
103
113
|
export function useRegisterDirty(dirty: boolean): void {
|
|
104
114
|
const ctx = useContext(DirtyGuardContext);
|
|
@@ -135,7 +145,7 @@ function GuardedTabsInner({
|
|
|
135
145
|
|
|
136
146
|
/**
|
|
137
147
|
* A drop-in replacement for {@link Tabs} that guards a switch away from a dirty
|
|
138
|
-
* editor. Wraps the tabs in a {@link
|
|
148
|
+
* editor. Wraps the tabs in a {@link DirtyGuardBoundary}, so an editor rendered in
|
|
139
149
|
* any panel can arm the guard through {@link useRegisterDirty}.
|
|
140
150
|
*/
|
|
141
151
|
export function GuardedTabs({
|
|
@@ -146,8 +156,8 @@ export function GuardedTabs({
|
|
|
146
156
|
readonly defaultValue?: string;
|
|
147
157
|
}): ReactNode {
|
|
148
158
|
return (
|
|
149
|
-
<
|
|
159
|
+
<DirtyGuardBoundary>
|
|
150
160
|
<GuardedTabsInner items={items} defaultValue={defaultValue} />
|
|
151
|
-
</
|
|
161
|
+
</DirtyGuardBoundary>
|
|
152
162
|
);
|
|
153
163
|
}
|
package/src/components/field.tsx
CHANGED
|
@@ -155,6 +155,16 @@ export function Field({
|
|
|
155
155
|
{label}
|
|
156
156
|
</label>
|
|
157
157
|
)}
|
|
158
|
+
{/* The description sits BETWEEN the label and the control, so it stays
|
|
159
|
+
adjacent to the label it glosses. After the control it drifts: a
|
|
160
|
+
group Field can wrap an arbitrarily tall surface (a whole schema
|
|
161
|
+
form), and a description below that surface reads as a footnote to
|
|
162
|
+
nothing. */}
|
|
163
|
+
{description !== undefined ? (
|
|
164
|
+
<p id={descriptionId} className="tai-field-hint" style={{ margin: 0 }}>
|
|
165
|
+
{description}
|
|
166
|
+
</p>
|
|
167
|
+
) : null}
|
|
158
168
|
{group ? (
|
|
159
169
|
<div
|
|
160
170
|
role="group"
|
|
@@ -167,11 +177,6 @@ export function Field({
|
|
|
167
177
|
) : (
|
|
168
178
|
children
|
|
169
179
|
)}
|
|
170
|
-
{description !== undefined ? (
|
|
171
|
-
<p id={descriptionId} className="tai-field-hint" style={{ margin: 0 }}>
|
|
172
|
-
{description}
|
|
173
|
-
</p>
|
|
174
|
-
) : null}
|
|
175
180
|
{/* The icon carries the invalid state alongside the color, never the color
|
|
176
181
|
alone — and it is the ERROR mark: a rejected value is a definite
|
|
177
182
|
negative, not the warning the triangle states. */}
|
|
@@ -9,7 +9,10 @@
|
|
|
9
9
|
* used by every config-mutation surface) reports a saved change that did not fully
|
|
10
10
|
* propagate and points the operator at the System page to reload; `'reload'` (the
|
|
11
11
|
* System page's own fleet-reload action) drops the "Change saved" framing — nothing
|
|
12
|
-
* was saved, a reload was dispatched — and the self-referential System-page pointer
|
|
12
|
+
* was saved, a reload was dispatched — and the self-referential System-page pointer;
|
|
13
|
+
* `'deregister'` and `'remove'` (detach fan-outs) likewise drop the "Change saved"
|
|
14
|
+
* framing and points the operator back at re-running the deregister, because a
|
|
15
|
+
* reload would re-attach the very server being detached — the wrong remediation.
|
|
13
16
|
*
|
|
14
17
|
* A `converged` summary (every worker applied, or a lone-worker local-only change)
|
|
15
18
|
* renders NOTHING — the calling surface shows its own success. A `degraded` summary
|
|
@@ -73,26 +76,44 @@ const OUTCOME_STATUS: Record<FleetFailureOutcome, StatusTone> = {
|
|
|
73
76
|
*/
|
|
74
77
|
export interface FleetReportProps {
|
|
75
78
|
readonly summary: FleetReportSummary | null;
|
|
76
|
-
/**
|
|
77
|
-
|
|
79
|
+
/**
|
|
80
|
+
* Whose framing the copy takes: a saved config change (`'save'`), a dispatched
|
|
81
|
+
* reload (`'reload'`), a connector detach fan-out (`'deregister'`), or a live-registry
|
|
82
|
+
* tool removal (`'remove'`). All but `'save'` drop the "Change saved" framing;
|
|
83
|
+
* `'deregister'` and `'remove'` also point remediation back at re-running that
|
|
84
|
+
* same detach, since a reload would re-attach the detached server or tool.
|
|
85
|
+
*/
|
|
86
|
+
readonly action?: 'save' | 'reload' | 'deregister' | 'remove';
|
|
78
87
|
}
|
|
79
88
|
|
|
80
89
|
export function FleetReport({ summary, action = 'save' }: FleetReportProps): ReactNode {
|
|
81
90
|
if (summary === null || summary.status === 'converged') return null;
|
|
82
91
|
|
|
92
|
+
// Only a saved config change carries the "Change saved" framing; a reload or a
|
|
93
|
+
// deregister saved nothing.
|
|
94
|
+
const savedFraming = action === 'save';
|
|
95
|
+
|
|
83
96
|
if (summary.status === 'unreachable') {
|
|
97
|
+
// Where to send the operator once the bus is back: re-run the same op, except a
|
|
98
|
+
// saved change reloads from the System page.
|
|
99
|
+
const unreachableRemediation =
|
|
100
|
+
action === 'deregister'
|
|
101
|
+
? 'Re-run the deregister once the bus is back.'
|
|
102
|
+
: action === 'remove'
|
|
103
|
+
? 'Re-run the remove once the bus is back.'
|
|
104
|
+
: action === 'reload'
|
|
105
|
+
? 'Re-run the reload once the bus is back.'
|
|
106
|
+
: 'Re-run the reload from the System page once the bus is back.';
|
|
84
107
|
return (
|
|
85
108
|
<div role="alert" className="tai-error-state tai-stack tai-stack-2">
|
|
86
109
|
<strong className="tai-status tai-status-err">
|
|
87
110
|
<XCircleIcon />
|
|
88
|
-
{
|
|
89
|
-
? '
|
|
90
|
-
: '
|
|
111
|
+
{savedFraming
|
|
112
|
+
? 'Change saved, but the worker fleet was not reached'
|
|
113
|
+
: 'The worker fleet was not reached'}
|
|
91
114
|
</strong>
|
|
92
115
|
<p>
|
|
93
|
-
{
|
|
94
|
-
? 'The worker bus was unreachable, so other workers may still be running the old config. Re-run the reload once the bus is back.'
|
|
95
|
-
: 'The worker bus was unreachable, so other workers may still be running the old config. Re-run the reload from the System page once the bus is back.'}
|
|
116
|
+
{`The worker bus was unreachable, so other workers may still be running the old config. ${unreachableRemediation}`}
|
|
96
117
|
</p>
|
|
97
118
|
{/* The bus error is a message, not a listing: it wraps rather than scrolls. */}
|
|
98
119
|
{summary.error !== null ? (
|
|
@@ -111,17 +132,27 @@ export function FleetReport({ summary, action = 'save' }: FleetReportProps): Rea
|
|
|
111
132
|
// worker is the commonest degraded fleet there is.
|
|
112
133
|
const count = summary.failures.length;
|
|
113
134
|
const workers = `${String(count)} worker${count === 1 ? '' : 's'}`;
|
|
135
|
+
// How the operator converges the stranded workers: re-run the same op, except a
|
|
136
|
+
// saved change reloads the fleet from the System page.
|
|
137
|
+
const remediation =
|
|
138
|
+
action === 'deregister'
|
|
139
|
+
? 're-run the deregister'
|
|
140
|
+
: action === 'remove'
|
|
141
|
+
? 're-run the remove'
|
|
142
|
+
: action === 'reload'
|
|
143
|
+
? 're-run the reload'
|
|
144
|
+
: 'reload the fleet from the System page';
|
|
114
145
|
return (
|
|
115
146
|
<div role="alert" className="tai-warn-state tai-stack tai-stack-2">
|
|
116
147
|
<strong className="tai-status tai-status-warn">
|
|
117
148
|
<AlertTriangleIcon />
|
|
118
|
-
{
|
|
119
|
-
?
|
|
120
|
-
:
|
|
149
|
+
{savedFraming
|
|
150
|
+
? `Change saved, but ${workers} did not converge`
|
|
151
|
+
: `${workers} did not converge`}
|
|
121
152
|
</strong>
|
|
122
153
|
<p>
|
|
123
154
|
{`${count === 1 ? 'This worker' : 'These workers'} may still be running the old config — ` +
|
|
124
|
-
|
|
155
|
+
remediation +
|
|
125
156
|
` to converge ${count === 1 ? 'it' : 'them'}.`}
|
|
126
157
|
</p>
|
|
127
158
|
<ul className="tai-stack tai-stack-2">
|
package/src/components/icons.tsx
CHANGED
|
@@ -504,6 +504,24 @@ export const GridIcon: IconComponent = (props) => (
|
|
|
504
504
|
</Icon>
|
|
505
505
|
);
|
|
506
506
|
|
|
507
|
+
/** Served endpoints: a broadcast node radiating to the tools it serves. */
|
|
508
|
+
export const ServedEndpointsIcon: IconComponent = (props) => (
|
|
509
|
+
<Icon {...props}>
|
|
510
|
+
<circle cx="12" cy="12" r="2.5" />
|
|
511
|
+
<path d="M7.8 7.8a6 6 0 0 0 0 8.4" />
|
|
512
|
+
<path d="M16.2 7.8a6 6 0 0 1 0 8.4" />
|
|
513
|
+
<path d="M5 5a9 9 0 0 0 0 14" />
|
|
514
|
+
<path d="M19 5a9 9 0 0 1 0 14" />
|
|
515
|
+
</Icon>
|
|
516
|
+
);
|
|
517
|
+
|
|
518
|
+
/** Plugin: a puzzle piece — the host's provenance mark for plugin-contributed nav. */
|
|
519
|
+
export const PluginIcon: IconComponent = (props) => (
|
|
520
|
+
<Icon {...props}>
|
|
521
|
+
<path d="M10 4a2 2 0 0 1 4 0c0 .8.7 1.4 1.5 1.4H18a1 1 0 0 1 1 1v2.6c0 .8.6 1.5 1.4 1.5a2 2 0 0 1 0 4c-.8 0-1.4.7-1.4 1.5V19a1 1 0 0 1-1 1h-2.6c-.8 0-1.4-.6-1.4-1.4a2 2 0 0 0-4 0c0 .8-.6 1.4-1.4 1.4H6a1 1 0 0 1-1-1v-2.5C5 15.7 4.4 15 3.6 15a2 2 0 0 1 0-4c.8 0 1.4-.7 1.4-1.5V6a1 1 0 0 1 1-1h2.5C9.3 5 10 4.4 10 3.6z" />
|
|
522
|
+
</Icon>
|
|
523
|
+
);
|
|
524
|
+
|
|
507
525
|
// -- Route mapping -----------------------------------------------------------
|
|
508
526
|
|
|
509
527
|
/**
|
|
@@ -519,6 +537,7 @@ export const NAV_ICONS: Readonly<Record<Exclude<RouteToken, 'login'>, IconCompon
|
|
|
519
537
|
extensions: ExtensionsIcon,
|
|
520
538
|
templates: TemplatesIcon,
|
|
521
539
|
connectors: ConnectorsIcon,
|
|
540
|
+
servedEndpoints: ServedEndpointsIcon,
|
|
522
541
|
hooks: HooksIcon,
|
|
523
542
|
storage: StorageIcon,
|
|
524
543
|
scheduling: SchedulingIcon,
|
package/src/host.ts
CHANGED
|
@@ -12,4 +12,8 @@ export {
|
|
|
12
12
|
subscribePluginHost,
|
|
13
13
|
usePluginContributions,
|
|
14
14
|
} from './plugin/host-state';
|
|
15
|
-
export type {
|
|
15
|
+
export type {
|
|
16
|
+
PluginLoaderState,
|
|
17
|
+
LoadedPlugin,
|
|
18
|
+
PluginContributionsSnapshot,
|
|
19
|
+
} from './plugin/host-state';
|
package/src/index.ts
CHANGED
|
@@ -11,9 +11,22 @@
|
|
|
11
11
|
* exported only from `@tai42/studio-sdk/host`, which the host bundle imports. See
|
|
12
12
|
* SECURITY.md for the trust boundary.
|
|
13
13
|
*
|
|
14
|
-
* The
|
|
15
|
-
* across the plugin boundary; this package imports nothing internal at
|
|
16
|
-
* (the `ApiClient`/`Interaction` types are type-only imports).
|
|
14
|
+
* The shared modules (react, react-dom, @tai42/studio-sdk, @tai42/jq-studio) are
|
|
15
|
+
* singletons across the plugin boundary; this package imports nothing internal at
|
|
16
|
+
* runtime (the `ApiClient`/`Interaction` types are type-only imports).
|
|
17
|
+
*
|
|
18
|
+
* NO JQ. The visual jq editor is `@tai42/jq-studio`, a separately published,
|
|
19
|
+
* client-agnostic package, and this barrel does not re-export it — not even as a
|
|
20
|
+
* thin pass-through. A bundler emits a package's Web Worker file and wasm engine
|
|
21
|
+
* from the mere PRESENCE of the module in the graph (the assets are emitted while
|
|
22
|
+
* the module is transformed, before tree-shaking can drop an unused re-export), so
|
|
23
|
+
* a pass-through here would put ~2.9MB of jq runtime into every consumer that
|
|
24
|
+
* imports this barrel for a Button. Consumers that want the editor import
|
|
25
|
+
* `@tai42/jq-studio` directly; the import map resolves that bare specifier to the
|
|
26
|
+
* one served copy, so the whole deployment still shares a single jq instance, a
|
|
27
|
+
* single primitives injection, and a single worker. What the SDK keeps is the
|
|
28
|
+
* INJECTION POINT — `ExpressionFieldContext` / `SchemaForm`'s `expressionField`
|
|
29
|
+
* prop, plus the mirrored contract types — which holds no edge to jq at all.
|
|
17
30
|
*/
|
|
18
31
|
// The design system, delivered by the BARREL so each host app loads it once and a
|
|
19
32
|
// plugin never ships its own copy. These are bare side-effect imports, so they
|
|
@@ -48,29 +61,6 @@ export type {
|
|
|
48
61
|
export { STUDIO_PLUGIN_API_VERSION, checkPluginApiVersion } from './plugin/version';
|
|
49
62
|
export type { VersionGateResult } from './plugin/version';
|
|
50
63
|
|
|
51
|
-
// -- jq fields (re-exported from @tai42/jq-studio; the platform owns no jq code) --
|
|
52
|
-
export {
|
|
53
|
-
JqField,
|
|
54
|
-
JQEditorDialog,
|
|
55
|
-
JqEditorDialog,
|
|
56
|
-
preloadJq,
|
|
57
|
-
installDefaultJqWorker,
|
|
58
|
-
PrimitivesProvider,
|
|
59
|
-
} from './jq';
|
|
60
|
-
export type {
|
|
61
|
-
JqFieldProps,
|
|
62
|
-
JQEditorDialogProps,
|
|
63
|
-
JqEditorDialogProps,
|
|
64
|
-
ExpressionLanguage,
|
|
65
|
-
JqInputKey,
|
|
66
|
-
JqInputShapeDescriptor,
|
|
67
|
-
SampleInputProvider,
|
|
68
|
-
ServerValidationResult,
|
|
69
|
-
ServerValidateHook,
|
|
70
|
-
JqFieldDeclaration,
|
|
71
|
-
Primitives,
|
|
72
|
-
} from './jq';
|
|
73
|
-
|
|
74
64
|
// -- Hooks -------------------------------------------------------------------
|
|
75
65
|
export { ApiProvider, useApi } from './hooks/useApi';
|
|
76
66
|
export type { ApiClient } from './hooks/useApi';
|
|
@@ -201,7 +191,7 @@ export { Dialog } from './components/dialog';
|
|
|
201
191
|
export type { DialogProps } from './components/dialog';
|
|
202
192
|
export { ConfirmDialog } from './components/confirm-dialog';
|
|
203
193
|
export type { ConfirmDialogProps } from './components/confirm-dialog';
|
|
204
|
-
export { GuardedTabs, useRegisterDirty } from './components/dirty-guard';
|
|
194
|
+
export { GuardedTabs, DirtyGuardBoundary, useRegisterDirty } from './components/dirty-guard';
|
|
205
195
|
export { FormDialog } from './components/form-dialog';
|
|
206
196
|
export type { FormDialogProps } from './components/form-dialog';
|
|
207
197
|
export { Drawer } from './components/drawer';
|
|
@@ -328,6 +318,8 @@ export {
|
|
|
328
318
|
ExtensionsIcon,
|
|
329
319
|
TemplatesIcon,
|
|
330
320
|
ConnectorsIcon,
|
|
321
|
+
ServedEndpointsIcon,
|
|
322
|
+
PluginIcon,
|
|
331
323
|
HooksIcon,
|
|
332
324
|
StorageIcon,
|
|
333
325
|
SchedulingIcon,
|
|
@@ -373,10 +365,11 @@ export {
|
|
|
373
365
|
SchemaForm,
|
|
374
366
|
RecordEntryRendererContext,
|
|
375
367
|
// The expression-door injection point: a host that wants `x-tai42-expression`
|
|
376
|
-
// fields to author through the visual editor
|
|
377
|
-
// `
|
|
378
|
-
//
|
|
379
|
-
//
|
|
368
|
+
// fields to author through the visual editor imports `JqField` from
|
|
369
|
+
// `@tai42/jq-studio` and hands it to a form (the `expressionField` prop) or
|
|
370
|
+
// mounts this context above its tree. A form with no door renders those fields
|
|
371
|
+
// as plain string inputs and stays free of the jq subgraph — the editor, its
|
|
372
|
+
// worker, and its wasm — entirely.
|
|
380
373
|
ExpressionFieldContext,
|
|
381
374
|
SecretRefField,
|
|
382
375
|
defaultValueForSchema,
|