@tai42/studio-sdk 1.0.1 → 1.1.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/dist/hooks/useApi.d.ts +142 -0
- package/dist/hooks/useApi.d.ts.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/schema-form/SecretRefField.d.ts +42 -0
- package/dist/schema-form/SecretRefField.d.ts.map +1 -0
- package/dist/schema-form/SecretRefField.js +94 -0
- package/dist/schema-form/SecretRefField.js.map +1 -0
- package/dist/schema-form/classify.d.ts +3 -0
- package/dist/schema-form/classify.d.ts.map +1 -1
- package/dist/schema-form/classify.js +17 -0
- package/dist/schema-form/classify.js.map +1 -1
- package/dist/schema-form/context.d.ts +24 -0
- package/dist/schema-form/context.d.ts.map +1 -1
- package/dist/schema-form/context.js +3 -0
- package/dist/schema-form/context.js.map +1 -1
- package/dist/schema-form/default-value.d.ts.map +1 -1
- package/dist/schema-form/default-value.js +2 -0
- package/dist/schema-form/default-value.js.map +1 -1
- package/dist/schema-form/field-node.d.ts.map +1 -1
- package/dist/schema-form/field-node.js +3 -0
- package/dist/schema-form/field-node.js.map +1 -1
- package/dist/schema-form/index.d.ts +4 -0
- package/dist/schema-form/index.d.ts.map +1 -1
- package/dist/schema-form/index.js +2 -0
- package/dist/schema-form/index.js.map +1 -1
- package/dist/schema-form/record-field.d.ts +15 -0
- package/dist/schema-form/record-field.d.ts.map +1 -0
- package/dist/schema-form/record-field.js +144 -0
- package/dist/schema-form/record-field.js.map +1 -0
- package/dist/schema-form/validate.d.ts.map +1 -1
- package/dist/schema-form/validate.js +10 -0
- package/dist/schema-form/validate.js.map +1 -1
- package/package.json +2 -2
- package/src/index.ts +6 -0
- package/src/schema-form/SecretRefField.tsx +247 -0
- package/src/schema-form/classify.ts +25 -0
- package/src/schema-form/context.ts +29 -0
- package/src/schema-form/default-value.ts +2 -0
- package/src/schema-form/field-node.tsx +16 -0
- package/src/schema-form/index.ts +4 -0
- package/src/schema-form/record-field.tsx +243 -0
- package/src/schema-form/validate.ts +10 -0
|
@@ -6,6 +6,10 @@
|
|
|
6
6
|
*/
|
|
7
7
|
export { SchemaForm } from './SchemaForm';
|
|
8
8
|
export type { SchemaFormProps, CompletionProvider } from './SchemaForm';
|
|
9
|
+
export { RecordEntryRendererContext } from './context';
|
|
10
|
+
export type { RecordEntryRenderer, RecordEntryContext } from './context';
|
|
11
|
+
export { SecretRefField } from './SecretRefField';
|
|
12
|
+
export type { SecretRefFieldProps, SecretRef } from './SecretRefField';
|
|
9
13
|
export { defaultValueForSchema } from './default-value';
|
|
10
14
|
export { validateAgainstSchema } from './validate';
|
|
11
15
|
export { resolveRef } from './resolve';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/schema-form/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,YAAY,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AACxE,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,YAAY,EAAE,UAAU,EAAE,cAAc,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/schema-form/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,YAAY,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AACxE,OAAO,EAAE,0BAA0B,EAAE,MAAM,WAAW,CAAC;AACvD,YAAY,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AACzE,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,YAAY,EAAE,mBAAmB,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACvE,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,YAAY,EAAE,UAAU,EAAE,cAAc,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC"}
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
* and submit.
|
|
6
6
|
*/
|
|
7
7
|
export { SchemaForm } from './SchemaForm';
|
|
8
|
+
export { RecordEntryRendererContext } from './context';
|
|
9
|
+
export { SecretRefField } from './SecretRefField';
|
|
8
10
|
export { defaultValueForSchema } from './default-value';
|
|
9
11
|
export { validateAgainstSchema } from './validate';
|
|
10
12
|
export { resolveRef } from './resolve';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/schema-form/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/schema-form/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,OAAO,EAAE,0BAA0B,EAAE,MAAM,WAAW,CAAC;AAEvD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import type { JsonSchema, SchemaFormErrors } from './types';
|
|
3
|
+
export declare function RecordField({ heading, description, error, values, root, value, onChange, path, errors, idPrefix, }: {
|
|
4
|
+
heading: string;
|
|
5
|
+
description: string | undefined;
|
|
6
|
+
error: string | undefined;
|
|
7
|
+
values: JsonSchema;
|
|
8
|
+
root: JsonSchema;
|
|
9
|
+
value: unknown;
|
|
10
|
+
onChange: (value: unknown) => void;
|
|
11
|
+
path: string;
|
|
12
|
+
errors: SchemaFormErrors | undefined;
|
|
13
|
+
idPrefix: string;
|
|
14
|
+
}): ReactNode;
|
|
15
|
+
//# sourceMappingURL=record-field.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"record-field.d.ts","sourceRoot":"","sources":["../../src/schema-form/record-field.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAWvC,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAuC5D,wBAAgB,WAAW,CAAC,EAC1B,OAAO,EACP,WAAW,EACX,KAAK,EACL,MAAM,EACN,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,MAAM,EAAE,UAAU,CAAC;IACnB,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,CA2HZ"}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* The record (string-keyed map) field renderer. Each entry is a key input plus a
|
|
4
|
+
* value editor built from the map's value schema; add appends a blank-key entry,
|
|
5
|
+
* remove drops one by row. Rows carry a synthetic stable id — not their key — so
|
|
6
|
+
* an entry keeps its identity (and focus) while its key is being typed, and so a
|
|
7
|
+
* transiently blank or duplicate key never remounts a row or clobbers another.
|
|
8
|
+
*
|
|
9
|
+
* The emitted value is a plain object of the VALID entries. A blank key and a
|
|
10
|
+
* duplicate key are held in local row state and surfaced (never emitted, never
|
|
11
|
+
* silently merged): the map cannot represent two entries under one key, so the
|
|
12
|
+
* later duplicate is withheld and flagged rather than overwriting the first.
|
|
13
|
+
*/
|
|
14
|
+
import { useContext, useRef, useState } from 'react';
|
|
15
|
+
import { CloseIcon } from '../components/icons';
|
|
16
|
+
import { Field } from '../components/field';
|
|
17
|
+
import { TextInput } from '../components/inputs';
|
|
18
|
+
import { Button } from '../components/primitives';
|
|
19
|
+
import { classifySchema } from './classify';
|
|
20
|
+
import { RecordEntryRendererContext } from './context';
|
|
21
|
+
import { defaultValueForSchema } from './default-value';
|
|
22
|
+
import { FieldGroup } from './field-group';
|
|
23
|
+
import { FieldNode } from './field-node';
|
|
24
|
+
function isPlainObject(value) {
|
|
25
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
26
|
+
}
|
|
27
|
+
function analyzeRows(rows) {
|
|
28
|
+
const value = {};
|
|
29
|
+
const seen = new Set();
|
|
30
|
+
const blankRowIds = new Set();
|
|
31
|
+
const duplicateRowIds = new Set();
|
|
32
|
+
for (const row of rows) {
|
|
33
|
+
if (row.key.trim() === '') {
|
|
34
|
+
blankRowIds.add(row.id);
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
if (seen.has(row.key)) {
|
|
38
|
+
duplicateRowIds.add(row.id);
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
seen.add(row.key);
|
|
42
|
+
value[row.key] = row.value;
|
|
43
|
+
}
|
|
44
|
+
return { value, blankRowIds, duplicateRowIds };
|
|
45
|
+
}
|
|
46
|
+
export function RecordField({ heading, description, error, values, root, value, onChange, path, errors, idPrefix, }) {
|
|
47
|
+
const nextId = useRef(0);
|
|
48
|
+
const rowsFromValue = (source) => isPlainObject(source)
|
|
49
|
+
? Object.entries(source).map(([key, entryValue]) => ({
|
|
50
|
+
id: nextId.current++,
|
|
51
|
+
key,
|
|
52
|
+
value: entryValue,
|
|
53
|
+
}))
|
|
54
|
+
: [];
|
|
55
|
+
const [rows, setRows] = useState(() => rowsFromValue(value));
|
|
56
|
+
// The last object THIS field emitted. A parent echoing our own value back
|
|
57
|
+
// passes it identity-equal, so the rows (which may hold a blank/duplicate key
|
|
58
|
+
// the emitted object cannot) survive; a parent that swaps in a different value
|
|
59
|
+
// (a reset, another record loaded) fails the check and resyncs the rows.
|
|
60
|
+
const lastEmitted = useRef(value);
|
|
61
|
+
if (value !== lastEmitted.current) {
|
|
62
|
+
lastEmitted.current = value;
|
|
63
|
+
setRows(rowsFromValue(value));
|
|
64
|
+
}
|
|
65
|
+
const renderEntry = useContext(RecordEntryRendererContext);
|
|
66
|
+
const commit = (nextRows) => {
|
|
67
|
+
setRows(nextRows);
|
|
68
|
+
const emitted = analyzeRows(nextRows).value;
|
|
69
|
+
lastEmitted.current = emitted;
|
|
70
|
+
onChange(emitted);
|
|
71
|
+
};
|
|
72
|
+
const setKey = (id, key) => {
|
|
73
|
+
commit(rows.map((row) => (row.id === id ? { ...row, key } : row)));
|
|
74
|
+
};
|
|
75
|
+
const setValue = (id, next) => {
|
|
76
|
+
commit(rows.map((row) => (row.id === id ? { ...row, value: next } : row)));
|
|
77
|
+
};
|
|
78
|
+
const addRow = () => {
|
|
79
|
+
commit([...rows, { id: nextId.current++, key: '', value: newEntryValue(values, root) }]);
|
|
80
|
+
};
|
|
81
|
+
const removeRow = (id) => {
|
|
82
|
+
commit(rows.filter((row) => row.id !== id));
|
|
83
|
+
};
|
|
84
|
+
const { blankRowIds, duplicateRowIds } = analyzeRows(rows);
|
|
85
|
+
const summary = keyFaultSummary(blankRowIds.size, duplicateRowIds.size);
|
|
86
|
+
return (_jsxs(FieldGroup, { heading: heading, description: description, error: error, atRoot: false, children: [rows.length === 0 ? _jsx("span", { className: "tai-field-hint", children: "No entries" }) : null, summary !== undefined ? (_jsx("span", { role: "alert", className: "tai-field-error", children: summary })) : null, rows.map((row, index) => {
|
|
87
|
+
const position = index + 1;
|
|
88
|
+
const keyFault = rowKeyFault(row.id, blankRowIds, duplicateRowIds);
|
|
89
|
+
const entryPath = path === '' ? row.key : `${path}.${row.key}`;
|
|
90
|
+
const defaultField = (_jsx(FieldNode, { schema: values, root: root, value: row.value, onChange: (next) => {
|
|
91
|
+
setValue(row.id, next);
|
|
92
|
+
}, path: entryPath, label: undefined, required: true, errors: errors, idPrefix: idPrefix }));
|
|
93
|
+
return (_jsxs("div", { className: "tai-row", children: [_jsx(Field, { label: `Key ${String(position)}`, error: keyFault, children: _jsx(TextInput, { value: row.key, onChange: (event) => {
|
|
94
|
+
setKey(row.id, event.target.value);
|
|
95
|
+
} }) }), _jsx("div", { style: { flex: 1 }, children: renderEntry === undefined
|
|
96
|
+
? defaultField
|
|
97
|
+
: renderEntry({
|
|
98
|
+
keyName: row.key,
|
|
99
|
+
path: entryPath,
|
|
100
|
+
valueSchema: values,
|
|
101
|
+
value: row.value,
|
|
102
|
+
onChange: (next) => {
|
|
103
|
+
setValue(row.id, next);
|
|
104
|
+
},
|
|
105
|
+
defaultField,
|
|
106
|
+
}) }), _jsxs(Button, { type: "button", variant: "secondary", "aria-label": `Remove entry ${String(position)}`, onClick: () => {
|
|
107
|
+
removeRow(row.id);
|
|
108
|
+
}, children: [_jsx(CloseIcon, {}), "Remove"] })] }, row.id));
|
|
109
|
+
}), _jsx("div", { children: _jsx(Button, { type: "button", variant: "secondary", onClick: addRow, children: "Add entry" }) })] }));
|
|
110
|
+
}
|
|
111
|
+
/** The inline key error for one row, or `undefined` when its key is fine. */
|
|
112
|
+
function rowKeyFault(id, blankRowIds, duplicateRowIds) {
|
|
113
|
+
if (blankRowIds.has(id))
|
|
114
|
+
return 'Key is required';
|
|
115
|
+
if (duplicateRowIds.has(id))
|
|
116
|
+
return 'Duplicate key';
|
|
117
|
+
return undefined;
|
|
118
|
+
}
|
|
119
|
+
/** A one-line summary of the map's key faults, or `undefined` when there are none. */
|
|
120
|
+
function keyFaultSummary(blankCount, duplicateCount) {
|
|
121
|
+
const parts = [];
|
|
122
|
+
if (blankCount > 0)
|
|
123
|
+
parts.push(`${String(blankCount)} entry with a blank key`);
|
|
124
|
+
if (duplicateCount > 0)
|
|
125
|
+
parts.push(`${String(duplicateCount)} entry with a duplicate key`);
|
|
126
|
+
if (parts.length === 0)
|
|
127
|
+
return undefined;
|
|
128
|
+
return `${parts.join(' and ')} (not saved until fixed)`;
|
|
129
|
+
}
|
|
130
|
+
function newEntryValue(schema, root) {
|
|
131
|
+
const seeded = defaultValueForSchema(schema, root);
|
|
132
|
+
if (seeded !== undefined)
|
|
133
|
+
return seeded;
|
|
134
|
+
const classified = classifySchema(schema, root);
|
|
135
|
+
switch (classified.model.kind) {
|
|
136
|
+
case 'string':
|
|
137
|
+
return '';
|
|
138
|
+
case 'boolean':
|
|
139
|
+
return false;
|
|
140
|
+
default:
|
|
141
|
+
return undefined;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=record-field.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"record-field.js","sourceRoot":"","sources":["../../src/schema-form/record-field.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/schema-form/validate.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAE5D,iDAAiD;AACjD,MAAM,WAAW,eAAe;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;CAClC;
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/schema-form/validate.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAE5D,iDAAiD;AACjD,MAAM,WAAW,eAAe;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;CAClC;AA6JD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,OAAO,EACd,OAAO,CAAC,EAAE,eAAe,GACxB,gBAAgB,CAIlB"}
|
|
@@ -136,6 +136,16 @@ function walk(schema, value, path, root, errors, maxUploadBytes) {
|
|
|
136
136
|
}
|
|
137
137
|
return;
|
|
138
138
|
}
|
|
139
|
+
case 'record': {
|
|
140
|
+
if (!isPlainObject(value)) {
|
|
141
|
+
errors[path] = 'must be an object';
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
for (const [key, entryValue] of Object.entries(value)) {
|
|
145
|
+
walk(model.values, entryValue, joinPath(path, key), root, errors, maxUploadBytes);
|
|
146
|
+
}
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
139
149
|
case 'union': {
|
|
140
150
|
const index = activeVariantIndex(value, model.variants, model.discriminator, root);
|
|
141
151
|
const variant = index === -1 ? undefined : model.variants[index];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/schema-form/validate.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/schema-form/validate.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tai42/studio-sdk",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.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>",
|
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
"@radix-ui/react-select": "^2.3.2",
|
|
90
90
|
"@radix-ui/react-tabs": "^1.1.16",
|
|
91
91
|
"@radix-ui/react-tooltip": "^1.2.11",
|
|
92
|
-
"@tai42/api-client": "1.0
|
|
92
|
+
"@tai42/api-client": "1.1.0"
|
|
93
93
|
},
|
|
94
94
|
"scripts": {
|
|
95
95
|
"build": "tsc -b tsconfig.build.json && node scripts/copy-assets.mjs",
|
package/src/index.ts
CHANGED
|
@@ -321,6 +321,8 @@ export type { IconProps, IconComponent } from './components/icons';
|
|
|
321
321
|
// -- Schema-driven forms -----------------------------------------------------
|
|
322
322
|
export {
|
|
323
323
|
SchemaForm,
|
|
324
|
+
RecordEntryRendererContext,
|
|
325
|
+
SecretRefField,
|
|
324
326
|
defaultValueForSchema,
|
|
325
327
|
validateAgainstSchema,
|
|
326
328
|
resolveRef,
|
|
@@ -328,6 +330,10 @@ export {
|
|
|
328
330
|
export type {
|
|
329
331
|
SchemaFormProps,
|
|
330
332
|
CompletionProvider,
|
|
333
|
+
RecordEntryRenderer,
|
|
334
|
+
RecordEntryContext,
|
|
335
|
+
SecretRefFieldProps,
|
|
336
|
+
SecretRef,
|
|
331
337
|
JsonSchema,
|
|
332
338
|
JsonSchemaType,
|
|
333
339
|
Discriminator,
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `SecretRefField` — a data-agnostic masked editor for ONE secret value that is
|
|
3
|
+
* EITHER a reference to an existing env key OR a freshly pasted secret. It knows
|
|
4
|
+
* nothing about the `!ENV ${KEY}` marker syntax or any wire format: it emits a
|
|
5
|
+
* discriminated {@link SecretRef} and the host maps that to whatever it stores
|
|
6
|
+
* (the consumer that mounts this — the McpTab editor — writes an `!ENV ${KEY}`
|
|
7
|
+
* marker for a `key` ref and runs the combined store-then-mark op for a `paste`).
|
|
8
|
+
*
|
|
9
|
+
* WRITE-ONLY for a pasted secret: the plaintext lives only in local editor state
|
|
10
|
+
* until the user commits it, at which point it leaves the DOM entirely (held only
|
|
11
|
+
* in the emitted value the host holds) — the committed chip renders a fixed mask,
|
|
12
|
+
* never the secret, and offers NO reveal. A picked key's NAME is not itself the
|
|
13
|
+
* secret, so its chip is revealable on click.
|
|
14
|
+
*
|
|
15
|
+
* FAIL CLOSED: env-key picking is offered only when `keyPickingAvailable` is
|
|
16
|
+
* explicitly true (the host passes it from whether the projection carries the env
|
|
17
|
+
* route). Absent, the field is paste-only.
|
|
18
|
+
*/
|
|
19
|
+
import { useEffect, useState } from 'react';
|
|
20
|
+
import type { ReactNode } from 'react';
|
|
21
|
+
|
|
22
|
+
import { Field } from '../components/field';
|
|
23
|
+
import { EyeIcon, EyeOffIcon } from '../components/icons';
|
|
24
|
+
import { TextInput } from '../components/inputs';
|
|
25
|
+
import { Button } from '../components/primitives';
|
|
26
|
+
import { Select } from '../components/select';
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* The value {@link SecretRefField} emits and reads back. The `source` discriminant
|
|
30
|
+
* is what the host branches on:
|
|
31
|
+
* - `key` — reference an existing env key; the host writes `!ENV ${key}`.
|
|
32
|
+
* - `paste` — a new plaintext secret; the host stores it under a generated key
|
|
33
|
+
* (combined op) and writes the resulting marker. `secret` is
|
|
34
|
+
* write-only and is never rendered.
|
|
35
|
+
*/
|
|
36
|
+
export type SecretRef =
|
|
37
|
+
| { readonly source: 'key'; readonly key: string }
|
|
38
|
+
| { readonly source: 'paste'; readonly secret: string };
|
|
39
|
+
|
|
40
|
+
export interface SecretRefFieldProps {
|
|
41
|
+
/** The current value, or `undefined` when nothing has been provided yet. */
|
|
42
|
+
readonly value: SecretRef | undefined;
|
|
43
|
+
/** Fired once when a value is provided (a key picked, or a paste committed). */
|
|
44
|
+
readonly onChange: (value: SecretRef) => void;
|
|
45
|
+
/** Env key NAMES the host supplies (e.g. envConfig.secret_keys). Never fetched here. */
|
|
46
|
+
readonly availableKeys: readonly string[];
|
|
47
|
+
/**
|
|
48
|
+
* Whether env-key picking is available at all — the host passes it from whether
|
|
49
|
+
* the projection carries the env route. Omitted or false: paste-only (fail
|
|
50
|
+
* closed).
|
|
51
|
+
*/
|
|
52
|
+
readonly keyPickingAvailable?: boolean;
|
|
53
|
+
/**
|
|
54
|
+
* When set, PASTING a new secret is blocked and this reason is surfaced inline
|
|
55
|
+
* (referencing an existing key stays available). The host passes it when a paste
|
|
56
|
+
* right now would land in the wrong place — an unsaved structural edit has shifted
|
|
57
|
+
* the target pointer, or the entry has no key yet to hint the generated name.
|
|
58
|
+
*/
|
|
59
|
+
readonly pasteDisabledReason?: string;
|
|
60
|
+
/** Visible field label; the accessible name of the inner control. */
|
|
61
|
+
readonly label?: string;
|
|
62
|
+
readonly idPrefix?: string;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** A fixed-width mask that never encodes the masked value's length. */
|
|
66
|
+
const MASK = '••••••••';
|
|
67
|
+
|
|
68
|
+
export function SecretRefField({
|
|
69
|
+
value,
|
|
70
|
+
onChange,
|
|
71
|
+
availableKeys,
|
|
72
|
+
keyPickingAvailable,
|
|
73
|
+
pasteDisabledReason,
|
|
74
|
+
label = 'Secret',
|
|
75
|
+
idPrefix = 'secret-ref',
|
|
76
|
+
}: SecretRefFieldProps): ReactNode {
|
|
77
|
+
const canPick = keyPickingAvailable === true;
|
|
78
|
+
const pasteBlocked = pasteDisabledReason !== undefined;
|
|
79
|
+
|
|
80
|
+
// Editing is forced while there is no value to show as a chip; otherwise the
|
|
81
|
+
// chip is shown until the user asks to replace it.
|
|
82
|
+
const [editing, setEditing] = useState(value === undefined);
|
|
83
|
+
const [mode, setMode] = useState<'key' | 'paste'>(
|
|
84
|
+
value?.source === 'key' && canPick ? 'key' : 'paste',
|
|
85
|
+
);
|
|
86
|
+
const [draftSecret, setDraftSecret] = useState('');
|
|
87
|
+
const [pickedKey, setPickedKey] = useState('');
|
|
88
|
+
const [revealed, setRevealed] = useState(false);
|
|
89
|
+
|
|
90
|
+
// A different committed value must never keep the prior reveal: revealing key B
|
|
91
|
+
// after B replaced A would name the wrong key. Reset on a STABLE signature of the
|
|
92
|
+
// value rather than its object identity, so a host that re-creates an equal
|
|
93
|
+
// `value` object each render never collapses an open reveal.
|
|
94
|
+
const valueSignature =
|
|
95
|
+
value === undefined ? '' : value.source === 'key' ? `key:${value.key}` : 'paste';
|
|
96
|
+
useEffect(() => {
|
|
97
|
+
setRevealed(false);
|
|
98
|
+
}, [valueSignature]);
|
|
99
|
+
|
|
100
|
+
const effectiveMode = canPick ? mode : 'paste';
|
|
101
|
+
|
|
102
|
+
const commitKey = (key: string): void => {
|
|
103
|
+
setPickedKey(key);
|
|
104
|
+
if (key === '') return;
|
|
105
|
+
onChange({ source: 'key', key });
|
|
106
|
+
setEditing(false);
|
|
107
|
+
};
|
|
108
|
+
const commitPaste = (): void => {
|
|
109
|
+
if (draftSecret === '' || pasteBlocked) return;
|
|
110
|
+
onChange({ source: 'paste', secret: draftSecret });
|
|
111
|
+
// The plaintext leaves the DOM: it now lives only in the emitted value.
|
|
112
|
+
setDraftSecret('');
|
|
113
|
+
setEditing(false);
|
|
114
|
+
};
|
|
115
|
+
const startEditing = (): void => {
|
|
116
|
+
setDraftSecret('');
|
|
117
|
+
setPickedKey('');
|
|
118
|
+
setRevealed(false);
|
|
119
|
+
setMode(value?.source === 'key' && canPick ? 'key' : 'paste');
|
|
120
|
+
setEditing(true);
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
if (!editing && value !== undefined) {
|
|
124
|
+
return (
|
|
125
|
+
<div data-testid={idPrefix}>
|
|
126
|
+
<SecretChip
|
|
127
|
+
value={value}
|
|
128
|
+
revealed={revealed}
|
|
129
|
+
onToggleReveal={() => {
|
|
130
|
+
setRevealed((prev) => !prev);
|
|
131
|
+
}}
|
|
132
|
+
/>
|
|
133
|
+
<Button type="button" variant="secondary" onClick={startEditing}>
|
|
134
|
+
{value.source === 'key' ? 'Change reference' : 'Replace secret'}
|
|
135
|
+
</Button>
|
|
136
|
+
</div>
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return (
|
|
141
|
+
<div data-testid={idPrefix}>
|
|
142
|
+
{canPick ? (
|
|
143
|
+
<div className="tai-row" role="group" aria-label={`${label} source`}>
|
|
144
|
+
<Button
|
|
145
|
+
type="button"
|
|
146
|
+
variant={effectiveMode === 'key' ? 'primary' : 'secondary'}
|
|
147
|
+
aria-pressed={effectiveMode === 'key'}
|
|
148
|
+
onClick={() => {
|
|
149
|
+
setMode('key');
|
|
150
|
+
}}
|
|
151
|
+
>
|
|
152
|
+
Reference existing key
|
|
153
|
+
</Button>
|
|
154
|
+
<Button
|
|
155
|
+
type="button"
|
|
156
|
+
variant={effectiveMode === 'paste' ? 'primary' : 'secondary'}
|
|
157
|
+
aria-pressed={effectiveMode === 'paste'}
|
|
158
|
+
onClick={() => {
|
|
159
|
+
setMode('paste');
|
|
160
|
+
}}
|
|
161
|
+
>
|
|
162
|
+
Paste new secret
|
|
163
|
+
</Button>
|
|
164
|
+
</div>
|
|
165
|
+
) : null}
|
|
166
|
+
|
|
167
|
+
{effectiveMode === 'key' ? (
|
|
168
|
+
availableKeys.length === 0 ? (
|
|
169
|
+
<span className="tai-field-hint">No keys available</span>
|
|
170
|
+
) : (
|
|
171
|
+
<Field label={label}>
|
|
172
|
+
<Select
|
|
173
|
+
value={pickedKey === '' ? undefined : pickedKey}
|
|
174
|
+
onValueChange={commitKey}
|
|
175
|
+
placeholder="Select a key"
|
|
176
|
+
options={availableKeys.map((key) => ({ value: key, label: key }))}
|
|
177
|
+
/>
|
|
178
|
+
</Field>
|
|
179
|
+
)
|
|
180
|
+
) : (
|
|
181
|
+
<div className="tai-row">
|
|
182
|
+
<div style={{ flex: 1 }}>
|
|
183
|
+
<Field label={label} error={pasteDisabledReason}>
|
|
184
|
+
{/* type=password: the plaintext is masked and offers no reveal —
|
|
185
|
+
it is write-only. */}
|
|
186
|
+
<TextInput
|
|
187
|
+
type="password"
|
|
188
|
+
value={draftSecret}
|
|
189
|
+
onChange={(event) => {
|
|
190
|
+
setDraftSecret(event.target.value);
|
|
191
|
+
}}
|
|
192
|
+
autoComplete="off"
|
|
193
|
+
spellCheck={false}
|
|
194
|
+
placeholder="Paste a secret value"
|
|
195
|
+
/>
|
|
196
|
+
</Field>
|
|
197
|
+
</div>
|
|
198
|
+
<Button
|
|
199
|
+
type="button"
|
|
200
|
+
variant="primary"
|
|
201
|
+
disabled={draftSecret === '' || pasteBlocked}
|
|
202
|
+
onClick={commitPaste}
|
|
203
|
+
>
|
|
204
|
+
Use secret
|
|
205
|
+
</Button>
|
|
206
|
+
</div>
|
|
207
|
+
)}
|
|
208
|
+
</div>
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* The committed masked chip. A `key` ref names the key, revealable on click; a
|
|
214
|
+
* `paste` secret shows only that a new secret is staged — the plaintext is never
|
|
215
|
+
* a child of this tree.
|
|
216
|
+
*/
|
|
217
|
+
function SecretChip({
|
|
218
|
+
value,
|
|
219
|
+
revealed,
|
|
220
|
+
onToggleReveal,
|
|
221
|
+
}: {
|
|
222
|
+
value: SecretRef;
|
|
223
|
+
revealed: boolean;
|
|
224
|
+
onToggleReveal: () => void;
|
|
225
|
+
}): ReactNode {
|
|
226
|
+
if (value.source === 'paste') {
|
|
227
|
+
return (
|
|
228
|
+
<span className="tai-chip tai-chip-static">
|
|
229
|
+
New secret <span aria-hidden="true">{MASK}</span>
|
|
230
|
+
</span>
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
const toggleLabel = revealed ? 'Hide value' : 'Show value';
|
|
234
|
+
return (
|
|
235
|
+
<span className="tai-chip tai-chip-static">
|
|
236
|
+
<span>{revealed ? value.key : MASK}</span>
|
|
237
|
+
<button
|
|
238
|
+
type="button"
|
|
239
|
+
className="tai-icon-btn"
|
|
240
|
+
aria-label={toggleLabel}
|
|
241
|
+
onClick={onToggleReveal}
|
|
242
|
+
>
|
|
243
|
+
{revealed ? <EyeOffIcon /> : <EyeIcon />}
|
|
244
|
+
</button>
|
|
245
|
+
</span>
|
|
246
|
+
);
|
|
247
|
+
}
|
|
@@ -66,6 +66,14 @@ export type FieldModel =
|
|
|
66
66
|
readonly properties: readonly (readonly [string, JsonSchema])[];
|
|
67
67
|
readonly required: ReadonlySet<string>;
|
|
68
68
|
}
|
|
69
|
+
| {
|
|
70
|
+
// A string-keyed map typed by `additionalProperties` (no fixed
|
|
71
|
+
// `properties`), edited as key/value rows. `values` is the entry value
|
|
72
|
+
// schema AS WRITTEN — the entry editor resolves any `$ref` itself, exactly
|
|
73
|
+
// as `array.items` is.
|
|
74
|
+
readonly kind: 'record';
|
|
75
|
+
readonly values: JsonSchema;
|
|
76
|
+
}
|
|
69
77
|
| {
|
|
70
78
|
readonly kind: 'union';
|
|
71
79
|
readonly variants: readonly UnionVariant[];
|
|
@@ -279,6 +287,23 @@ export function classifySchema(raw: JsonSchema, root: JsonSchema): ClassifiedFie
|
|
|
279
287
|
}
|
|
280
288
|
case 'object': {
|
|
281
289
|
if (resolved.properties === undefined) {
|
|
290
|
+
// A free-form object typed by a VALUE SCHEMA (`additionalProperties` is a
|
|
291
|
+
// schema, not `false`/`true`/absent) is a string→X map — renderable as
|
|
292
|
+
// key/value rows. A boolean `additionalProperties` carries no value type
|
|
293
|
+
// to build an entry editor from, so it stays unsupported.
|
|
294
|
+
// Read as `unknown`: the value is parsed JSON, where `additionalProperties:
|
|
295
|
+
// null` is possible and `typeof null === 'object'` would otherwise classify
|
|
296
|
+
// it as a record with a `null` value schema.
|
|
297
|
+
const additional: unknown = resolved.additionalProperties;
|
|
298
|
+
if (typeof additional === 'object' && additional !== null) {
|
|
299
|
+
return {
|
|
300
|
+
model: { kind: 'record', values: additional as JsonSchema },
|
|
301
|
+
nullable: nullableByType,
|
|
302
|
+
schema: resolved,
|
|
303
|
+
title,
|
|
304
|
+
description,
|
|
305
|
+
};
|
|
306
|
+
}
|
|
282
307
|
return unsupported(
|
|
283
308
|
resolved,
|
|
284
309
|
'free-form object (additionalProperties map) is not supported',
|
|
@@ -4,9 +4,11 @@
|
|
|
4
4
|
* tree reads these here rather than every intermediate node drilling the prop.
|
|
5
5
|
*/
|
|
6
6
|
import { createContext } from 'react';
|
|
7
|
+
import type { ReactNode } from 'react';
|
|
7
8
|
|
|
8
9
|
import { DEFAULT_MAX_UPLOAD_BYTES } from './media';
|
|
9
10
|
import type { CompletionProvider } from './SchemaForm';
|
|
11
|
+
import type { JsonSchema } from './types';
|
|
10
12
|
|
|
11
13
|
// Ambient completion provider for the whole form. A string field deep in the
|
|
12
14
|
// tree reads it here rather than every intermediate node drilling the prop.
|
|
@@ -15,3 +17,30 @@ export const CompletionProviderContext = createContext<CompletionProvider | unde
|
|
|
15
17
|
// Ambient default upload cap for the whole form; a media field reads it here so
|
|
16
18
|
// intermediate object/array nodes never drill the prop.
|
|
17
19
|
export const MaxUploadBytesContext = createContext<number>(DEFAULT_MAX_UPLOAD_BYTES);
|
|
20
|
+
|
|
21
|
+
/** One record entry, handed to a host-supplied value renderer. */
|
|
22
|
+
export interface RecordEntryContext {
|
|
23
|
+
/** The entry's current key (may be blank/duplicate while the user edits). */
|
|
24
|
+
readonly keyName: string;
|
|
25
|
+
/** The entry value's form path (dotted from the form root). */
|
|
26
|
+
readonly path: string;
|
|
27
|
+
/** The entry value schema, as written (the renderer resolves any `$ref`). */
|
|
28
|
+
readonly valueSchema: JsonSchema;
|
|
29
|
+
readonly value: unknown;
|
|
30
|
+
readonly onChange: (value: unknown) => void;
|
|
31
|
+
/** The default value editor the record field would render for this entry. */
|
|
32
|
+
readonly defaultField: ReactNode;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* A host-supplied per-entry value renderer for `record` fields — the injection
|
|
37
|
+
* point a masked/secret editor (or any other value affordance) mounts through.
|
|
38
|
+
* It returns the node to render in the entry's value slot; returning
|
|
39
|
+
* `entry.defaultField` falls back to the built-in editor. Absent (the default),
|
|
40
|
+
* every entry renders its `defaultField`.
|
|
41
|
+
*/
|
|
42
|
+
export type RecordEntryRenderer = (entry: RecordEntryContext) => ReactNode;
|
|
43
|
+
|
|
44
|
+
// Ambient record-entry value renderer for the whole form; the record field reads
|
|
45
|
+
// it here so intermediate object/array/record nodes never drill the prop.
|
|
46
|
+
export const RecordEntryRendererContext = createContext<RecordEntryRenderer | undefined>(undefined);
|