@adcops/autocore-react 3.5.15 → 3.6.3
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/components/tis-editor/DeleteMethodDialog.d.ts +43 -0
- package/dist/components/tis-editor/DeleteMethodDialog.d.ts.map +1 -0
- package/dist/components/tis-editor/DeleteMethodDialog.js +1 -0
- package/dist/components/tis-editor/MethodTransfer.d.ts +69 -0
- package/dist/components/tis-editor/MethodTransfer.d.ts.map +1 -0
- package/dist/components/tis-editor/MethodTransfer.js +1 -0
- package/dist/components/tis-editor/TisConfigEditor.css +31 -0
- package/dist/components/tis-editor/TisConfigEditor.d.ts +9 -1
- package/dist/components/tis-editor/TisConfigEditor.d.ts.map +1 -1
- package/dist/components/tis-editor/TisConfigEditor.js +1 -1
- package/dist/components/tis-editor/editor/IdentitySection.d.ts.map +1 -1
- package/dist/components/tis-editor/editor/IdentitySection.js +1 -1
- package/dist/components/tis-editor/types.d.ts +11 -0
- package/dist/components/tis-editor/types.d.ts.map +1 -1
- package/dist/components/varpick/VariablePicker.d.ts.map +1 -1
- package/dist/components/varpick/VariablePicker.js +1 -1
- package/dist/components/varpick/varpick.css +84 -30
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +1 -1
- package/dist/hooks/useMethodSequence.d.ts +60 -0
- package/dist/hooks/useMethodSequence.d.ts.map +1 -0
- package/dist/hooks/useMethodSequence.js +1 -0
- package/package.json +1 -1
- package/src/components/tis-editor/DeleteMethodDialog.tsx +162 -0
- package/src/components/tis-editor/MethodTransfer.ts +138 -0
- package/src/components/tis-editor/TisConfigEditor.css +31 -0
- package/src/components/tis-editor/TisConfigEditor.tsx +305 -7
- package/src/components/tis-editor/editor/IdentitySection.tsx +33 -1
- package/src/components/tis-editor/types.ts +11 -0
- package/src/components/varpick/VariablePicker.tsx +4 -0
- package/src/components/varpick/varpick.css +84 -30
- package/src/hooks/index.ts +4 -0
- package/src/hooks/useMethodSequence.ts +128 -0
- package/tools/tests/dist/{TestFieldDialog-BvHAr2GQ.js → TestFieldDialog-Dph2oPfe.js} +1 -0
- package/tools/tests/dist/autocore-react.css +84 -30
- package/tools/tests/dist/tis-editor.entry.js +1 -1
- package/tools/tests/dist/varpick.entry.js +1 -1
- package/tools/tests/varpick.test.mjs +5 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DeleteMethodDialog — the three-step method deletion.
|
|
3
|
+
*
|
|
4
|
+
* Deleting a test method destroys more than a config entry. It takes the
|
|
5
|
+
* procedure that produced the numbers with it, and it orphans every run in
|
|
6
|
+
* history from the schema that gives those runs meaning: the column names, the
|
|
7
|
+
* units, the chart definitions. A `window.confirm` is not a proportionate gate
|
|
8
|
+
* on that.
|
|
9
|
+
*
|
|
10
|
+
* So the operator walks three steps and cannot skip any of them:
|
|
11
|
+
*
|
|
12
|
+
* 1. Read what goes. Named, counted, and explicit about the history.
|
|
13
|
+
* 2. Download the archive. MANDATORY, not advisory. `tis.export_method_zip`
|
|
14
|
+
* hands back every run of this method. The button
|
|
15
|
+
* gates step 3, so "I'll do it later" is not a
|
|
16
|
+
* path through this dialog.
|
|
17
|
+
* 3. Type the phrase. `YES I AM SURE`, exactly. A phrase cannot be
|
|
18
|
+
* hit by a mis-touch on a panel, and typing it is
|
|
19
|
+
* the moment the operator reads step 1 properly.
|
|
20
|
+
*
|
|
21
|
+
* The deletion itself is still STAGED — the TIS editor's Save is what persists
|
|
22
|
+
* it — but the sequence file and the operator's confidence are not, so this is
|
|
23
|
+
* where the friction belongs.
|
|
24
|
+
*/
|
|
25
|
+
/** Typed exactly, case-sensitive. */
|
|
26
|
+
export declare const DELETE_PHRASE = "YES I AM SURE";
|
|
27
|
+
export interface DeleteMethodDialogProps {
|
|
28
|
+
visible: boolean;
|
|
29
|
+
methodId: string | null;
|
|
30
|
+
/** True when this method's procedure is a file that will also be removed. */
|
|
31
|
+
hasSequence: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Fetch the archive of this method's runs and hand it to the browser.
|
|
34
|
+
* Resolves true once the download has been started.
|
|
35
|
+
*/
|
|
36
|
+
onDownloadArchive: (methodId: string) => Promise<boolean>;
|
|
37
|
+
onConfirm: () => void;
|
|
38
|
+
onCancel: () => void;
|
|
39
|
+
busy?: boolean;
|
|
40
|
+
}
|
|
41
|
+
export declare const DeleteMethodDialog: React.FC<DeleteMethodDialogProps>;
|
|
42
|
+
export default DeleteMethodDialog;
|
|
43
|
+
//# sourceMappingURL=DeleteMethodDialog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DeleteMethodDialog.d.ts","sourceRoot":"","sources":["../../../src/components/tis-editor/DeleteMethodDialog.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAQH,qCAAqC;AACrC,eAAO,MAAM,aAAa,kBAAkB,CAAC;AAE7C,MAAM,WAAW,uBAAuB;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,6EAA6E;IAC7E,WAAW,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,iBAAiB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1D,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,IAAI,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAAE,CAAC,uBAAuB,CA8GhE,CAAC;AAEF,eAAe,kBAAkB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import{useEffect,useState}from"react";import{Button}from"primereact/button";import{Dialog}from"primereact/dialog";import{InputText}from"primereact/inputtext";import{Message}from"primereact/message";export const DELETE_PHRASE="YES I AM SURE";export const DeleteMethodDialog=({visible:e,methodId:t,hasSequence:s,onDownloadArchive:i,onConfirm:n,onCancel:o,busy:r})=>{const[l,a]=useState(!1),[d,c]=useState(!1),[h,u]=useState(""),[p,m]=useState(null);useEffect(()=>{e&&(a(!1),c(!1),u(""),m(null))},[e,t]);const x=h===DELETE_PHRASE;return _jsxs(Dialog,{header:`Delete test method "${t??""}"`,visible:e,onHide:o,style:{width:"34rem"},modal:!0,children:[_jsxs("ol",{className:"tis-editor__delete-steps",children:[_jsxs("li",{children:[_jsx("strong",{children:"What this removes"}),_jsxs("ul",{children:[_jsx("li",{children:"The method definition: its fields, charts, results and asset references."}),s&&_jsx("li",{children:"Its sequence — the procedure that runs the test."}),_jsx("li",{children:"Nothing in the recorded data is erased, but every past run of this method loses the definition that names its columns. Reports and charts for those runs will no longer render."})]})]}),_jsxs("li",{children:[_jsx("strong",{children:"Download the archive"}),_jsx("p",{children:"Every run recorded under this method, as a ZIP. This is required — the confirmation below stays locked until the download has started."}),_jsx(Button,{label:l?"Archive downloaded":"Download archive",icon:d?"pi pi-spin pi-spinner":l?"pi pi-check":"pi pi-box",severity:l?"success":void 0,disabled:d||r,onClick:async()=>{if(t){c(!0),m(null);try{const e=await i(t);a(e),e||m("The archive could not be built, so nothing has been deleted.")}catch(e){m(`The archive could not be built, so nothing has been deleted: ${e instanceof Error?e.message:String(e)}`)}finally{c(!1)}}}})]}),_jsxs("li",{children:[_jsx("strong",{children:"Confirm"}),_jsxs("p",{children:["Type ",_jsx("code",{children:DELETE_PHRASE})," to enable the delete button."]}),_jsx(InputText,{value:h,onChange:e=>u(e.target.value),placeholder:DELETE_PHRASE,disabled:!l||r,style:{width:"100%"}})]})]}),p&&_jsx(Message,{severity:"error",text:p,style:{width:"100%"}}),_jsxs("div",{style:{display:"flex",gap:"0.5rem",justifyContent:"flex-end",marginTop:"1rem"},children:[_jsx(Button,{label:"Cancel",className:"p-button-text",onClick:o,disabled:r}),_jsx(Button,{label:"Delete method",icon:"pi pi-trash",className:"p-button-danger",disabled:!l||!x||r,onClick:n})]})]})};export default DeleteMethodDialog;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MethodTransfer — a whole test method as one portable file.
|
|
3
|
+
*
|
|
4
|
+
* ## Why the method and not the sequence
|
|
5
|
+
*
|
|
6
|
+
* A sequence-backed method is two halves with a contract between them: the
|
|
7
|
+
* schema declares the cycle columns, and the procedure's `store_value` steps
|
|
8
|
+
* fill them by name. Exporting either half alone produces something that looks
|
|
9
|
+
* like a method and silently is not — a schema with no producer records blank
|
|
10
|
+
* rows on every cycle forever, and a procedure with no schema stores values
|
|
11
|
+
* nothing displays. Neither failure announces itself.
|
|
12
|
+
*
|
|
13
|
+
* So the exportable unit is the pair. This is the same reasoning that made
|
|
14
|
+
* `acctl push methods` move both files with one verb.
|
|
15
|
+
*
|
|
16
|
+
* ## The file
|
|
17
|
+
*
|
|
18
|
+
* Plain JSON, human-readable, no archive container: it goes on a USB stick
|
|
19
|
+
* between companies and someone will open it in a text editor.
|
|
20
|
+
*
|
|
21
|
+
* {
|
|
22
|
+
* "format": "autocore-method",
|
|
23
|
+
* "version": 1,
|
|
24
|
+
* "method_id": "golf_compression",
|
|
25
|
+
* "schema": { ...test_methods.json entry... },
|
|
26
|
+
* "sequence": { ...seq.json..., or null for a control-backed method }
|
|
27
|
+
* }
|
|
28
|
+
*
|
|
29
|
+
* `method_id` is a SUGGESTION, not an instruction. The importer offers it and
|
|
30
|
+
* lets the operator rename, because a method list that fills up with
|
|
31
|
+
* `golf_compression_copy_3` is the complaint that follows otherwise.
|
|
32
|
+
*/
|
|
33
|
+
import type { TestMethod } from './types';
|
|
34
|
+
export declare const METHOD_FILE_FORMAT = "autocore-method";
|
|
35
|
+
export declare const METHOD_FILE_VERSION = 1;
|
|
36
|
+
export interface MethodTransferFile {
|
|
37
|
+
format: typeof METHOD_FILE_FORMAT;
|
|
38
|
+
version: number;
|
|
39
|
+
method_id: string;
|
|
40
|
+
schema: TestMethod;
|
|
41
|
+
/** The procedure, or null for a control-backed method. */
|
|
42
|
+
sequence: any | null;
|
|
43
|
+
}
|
|
44
|
+
/** Build the export payload. */
|
|
45
|
+
export declare function buildTransfer(methodId: string, schema: TestMethod, sequence: any | null): MethodTransferFile;
|
|
46
|
+
/**
|
|
47
|
+
* Legal method ids, and why the rule is this strict.
|
|
48
|
+
*
|
|
49
|
+
* The id becomes a path segment (`methods/<id>.seq.json`) and a directory name
|
|
50
|
+
* under the project (`<project>/<method_id>/<run_id>/`), both joined
|
|
51
|
+
* server-side, so anything that could traverse or quote-escape is refused at
|
|
52
|
+
* entry rather than sanitised silently — an id that comes back different from
|
|
53
|
+
* what was typed is how you end up with two methods you believe are one.
|
|
54
|
+
*
|
|
55
|
+
* It is also a Rust identifier stem in generated code, hence the leading-letter
|
|
56
|
+
* rule: `2point_bend` would emit `2pointBendTestManager`, which does not
|
|
57
|
+
* compile.
|
|
58
|
+
*/
|
|
59
|
+
export declare const METHOD_ID_RE: RegExp;
|
|
60
|
+
export declare const METHOD_ID_RULE = "Letters, digits and underscore only; must start with a letter.";
|
|
61
|
+
/** Parse and validate an imported file. Returns the file or a reason. */
|
|
62
|
+
export declare function parseTransfer(text: string): {
|
|
63
|
+
file: MethodTransferFile;
|
|
64
|
+
} | {
|
|
65
|
+
error: string;
|
|
66
|
+
};
|
|
67
|
+
/** Hand the browser a method export to save. */
|
|
68
|
+
export declare function downloadTransfer(file: MethodTransferFile): void;
|
|
69
|
+
//# sourceMappingURL=MethodTransfer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MethodTransfer.d.ts","sourceRoot":"","sources":["../../../src/components/tis-editor/MethodTransfer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE1C,eAAO,MAAM,kBAAkB,oBAAoB,CAAC;AACpD,eAAO,MAAM,mBAAmB,IAAI,CAAC;AAErC,MAAM,WAAW,kBAAkB;IAC/B,MAAM,EAAE,OAAO,kBAAkB,CAAC;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,UAAU,CAAC;IACnB,0DAA0D;IAC1D,QAAQ,EAAE,GAAG,GAAG,IAAI,CAAC;CACxB;AAED,gCAAgC;AAChC,wBAAgB,aAAa,CACzB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,UAAU,EAClB,QAAQ,EAAE,GAAG,GAAG,IAAI,GACrB,kBAAkB,CAQpB;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,YAAY,QAA4B,CAAC;AACtD,eAAO,MAAM,cAAc,mEACyC,CAAC;AAErE,yEAAyE;AACzE,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,kBAAkB,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CA4C5F;AAED,gDAAgD;AAChD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,kBAAkB,GAAG,IAAI,CAU/D"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const METHOD_FILE_FORMAT="autocore-method";export const METHOD_FILE_VERSION=1;export function buildTransfer(e,t,r){return{format:"autocore-method",version:1,method_id:e,schema:t,sequence:r??null}}export const METHOD_ID_RE=/^[A-Za-z][A-Za-z0-9_]*$/;export const METHOD_ID_RULE="Letters, digits and underscore only; must start with a letter.";export function parseTransfer(e){let t;try{t=JSON.parse(e)}catch(e){return{error:`Not valid JSON: ${e instanceof Error?e.message:String(e)}`}}if("object"!=typeof t||null===t)return{error:"File does not contain a method object."};const r=t;if("autocore-method"!==r.format){return{error:Array.isArray(t?.steps)?"This is a sequence file, not a whole method. Import it from a method export, or create the method first and edit its sequence on the Method screen.":'Not an autocore method export (missing "format": "autocore-method").'}}return"number"!=typeof r.version||r.version>1?{error:`This file was written by a newer version (v${r.version}); this machine understands up to v1.`}:"string"==typeof r.method_id&&METHOD_ID_RE.test(r.method_id)?"object"!=typeof r.schema||null===r.schema?{error:"File has no method schema."}:"sequence"!==r.schema.procedure||Array.isArray(r.sequence?.steps)?{file:r}:{error:"This method declares a sequence procedure but the file carries no sequence. Re-export it from the machine it came from."}:{error:`File has no usable method id. ${METHOD_ID_RULE}`}}export function downloadTransfer(e){const t=new Blob([JSON.stringify(e,null,2)],{type:"application/json"}),r=URL.createObjectURL(t),o=document.createElement("a");o.href=r,o.download=`${e.method_id}.method.json`,o.click(),setTimeout(()=>URL.revokeObjectURL(r),0)}
|
|
@@ -150,3 +150,34 @@
|
|
|
150
150
|
border-bottom: 1px solid var(--surface-d, #e2e8f0);
|
|
151
151
|
}
|
|
152
152
|
}
|
|
153
|
+
|
|
154
|
+
/*
|
|
155
|
+
* The three-step method deletion. Numbered because the steps are ordered and
|
|
156
|
+
* gated: the archive download unlocks the confirmation phrase, which unlocks
|
|
157
|
+
* the button. See DeleteMethodDialog for why deleting a method earns this.
|
|
158
|
+
*/
|
|
159
|
+
.tis-editor__delete-steps {
|
|
160
|
+
margin: 0 0 1rem;
|
|
161
|
+
padding-left: 1.4rem;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.tis-editor__delete-steps > li {
|
|
165
|
+
margin-bottom: 1rem;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.tis-editor__delete-steps p {
|
|
169
|
+
margin: 0.35rem 0 0.5rem;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.tis-editor__delete-steps ul {
|
|
173
|
+
margin: 0.35rem 0 0;
|
|
174
|
+
padding-left: 1.1rem;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
.tis-editor__delete-steps code {
|
|
178
|
+
padding: 0.1rem 0.35rem;
|
|
179
|
+
border-radius: 3px;
|
|
180
|
+
background: var(--surface-ground);
|
|
181
|
+
font-family: var(--font-family-mono, monospace);
|
|
182
|
+
letter-spacing: 0.04em;
|
|
183
|
+
}
|
|
@@ -4,7 +4,15 @@
|
|
|
4
4
|
* Left: PrimeReact DataTable listing methods (method_id + label).
|
|
5
5
|
* Right: tabbed editor for the selected method. Phase 1 ships a single
|
|
6
6
|
* JSON-via-Monaco tab; Phase 2 layers form editors on top of it.
|
|
7
|
-
* Action bar: New / Duplicate / Delete / Apply / Save / Revert.
|
|
7
|
+
* Action bar: New / Duplicate / Delete / Import / Export / Apply / Save / Revert.
|
|
8
|
+
*
|
|
9
|
+
* ## A method is two files
|
|
10
|
+
*
|
|
11
|
+
* A method whose `procedure` is `"sequence"` also owns
|
|
12
|
+
* `methods/<method_id>.seq.json`. This editor is the only place a method is
|
|
13
|
+
* created, copied, deleted or moved between machines, so it is the only place
|
|
14
|
+
* that can keep the two halves together — see `useMethodSequence` for what goes
|
|
15
|
+
* wrong when they drift. Every lifecycle action below therefore moves both.
|
|
8
16
|
*
|
|
9
17
|
* "Apply" pushes the local Monaco buffer to the server-side stage
|
|
10
18
|
* (`tis.put_method`). "Save" persists the entire stage to test_methods.json
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TisConfigEditor.d.ts","sourceRoot":"","sources":["../../../src/components/tis-editor/TisConfigEditor.tsx"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"TisConfigEditor.d.ts","sourceRoot":"","sources":["../../../src/components/tis-editor/TisConfigEditor.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAaH,OAAO,EAAgB,KAAK,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAY5E,OAAO,uBAAuB,CAAC;AAM/B,MAAM,WAAW,oBAAoB;IACjC;+EAC2E;IAC3E,SAAS,EAAE,MAAM,CAAC;IAClB,wEAAwE;IACxE,OAAO,CAAC,EAAE,aAAa,CAAC;CAC3B;AAmBD,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CA8jB1D,CAAC;AAEF,eAAe,eAAe,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as _jsx,jsxs as _jsxs,Fragment as _Fragment}from"react/jsx-runtime";import{useEffect,useMemo,useState}from"react";import{DataTable}from"primereact/datatable";import{Column}from"primereact/column";import{Button}from"primereact/button";import{InputText}from"primereact/inputtext";import{Dialog}from"primereact/dialog";import{useContext}from"react";import{EventEmitterContext}from"../../core/EventEmitterContext";import{MessageType}from"../../hub/CommandMessage";import{useTisConfig}from"../../hooks/useTisConfig";import{useAmsAssetTypes}from"../../hooks/useAmsAssetTypes";import{MethodFormEditor}from"./editor/MethodFormEditor";import{SaveDiffDialog}from"./editor/SaveDiffDialog";import"./TisConfigEditor.css";import{useGmVariables}from"../../hooks/useGmVariables";import{useSequenceProducers}from"../../hooks/useSequenceProducers";import{AuthoringContext}from"./editor/AuthoringContext";import{AutoCoreTagContext}from"../../core/AutoCoreTagContext";const EMPTY_METHOD={label:"",description:"",project_fields:[],config_fields:[],cycle_config_fields:[],cycle_fields:[],results_fields:[],views:{},asset_refs:[]};export const TisConfigEditor=({projectId:e,invoker:t})=>{const s=useContext(EventEmitterContext),i=useMemo(()=>t??(async(e,t)=>await s.invoke(e,MessageType.Request,t)),[t,s]),o=useTisConfig(e,{invoker:i}),{tags:a}=useContext(AutoCoreTagContext),r=useGmVariables({invoker:i,fallbackTags:a}),n=useAmsAssetTypes({invoker:i}),[l,d]=useState(null),[c,m]=useState(null),[u,f]=useState(!1),[p,h]=useState(!1),[g,_]=useState(!1),[x,y]=useState(""),b=useMemo(()=>o.config?Object.entries(o.config.methods).map(([e,t])=>({id:e,label:t?.label??""})):[],[o.config]);useEffect(()=>{if(!l&&o.config){const e=o.config.defaultMethodId||Object.keys(o.config.methods)[0]||null;d(e)}},[o.config,l]),useEffect(()=>{m(null)},[l]);const{producedNames:v}=useSequenceProducers(l),j=useMemo(()=>({variables:r.variables,producedNames:v,partial:r.partial}),[r.variables,v,r.partial]);return _jsx(AuthoringContext.Provider,{value:j,children:_jsxs("div",{className:"tis-editor",children:[_jsxs("header",{className:"tis-editor__header",children:[_jsxs("h2",{children:["Test Methods"," ",o.config?.dirty&&_jsx("span",{className:"tis-editor__dirty-pill",children:"unsaved"})]}),_jsxs("div",{className:"tis-editor__header-actions",children:[_jsx(Button,{label:"Save…",icon:"pi pi-save",disabled:u||!o.config?.dirty,onClick:()=>h(!0)}),_jsx(Button,{label:"Revert",icon:"pi pi-undo",className:"p-button-secondary",disabled:u||!o.config?.dirty,onClick:async()=>{if(window.confirm("Discard all in-progress edits? This cannot be undone.")){f(!0);try{await o.revert()}catch(e){m(String(e?.message??e))}finally{f(!1)}}}})]})]}),o.error&&_jsxs("div",{className:"tis-editor__error",children:[_jsx("strong",{children:"Error:"})," ",_jsx("pre",{children:o.error})]}),r.partial&&_jsx("div",{className:"tis-editor__notice",children:"This server cannot describe its own variables, so the pickers are listing only the variables published to this HMI, without descriptions. Update autocore_server to get the full list."}),_jsxs("div",{className:"tis-editor__body",children:[_jsxs("aside",{className:"tis-editor__sidebar",children:[_jsxs("div",{className:"tis-editor__sidebar-actions",children:[_jsx(Button,{label:"New",icon:"pi pi-plus",disabled:u,onClick:()=>_(!0)}),_jsx(Button,{label:"Duplicate",icon:"pi pi-clone",className:"p-button-secondary",disabled:u||!l,onClick:async()=>{if(!l||!o.config)return;const e=o.config.methods[l];if(!e)return;let t=`${l}_copy`,s=2;for(;o.config.methods[t];)t=`${l}_copy_${s++}`;f(!0);try{await o.putMethod(t,JSON.parse(JSON.stringify(e))),d(t)}catch(e){m(String(e?.message??e))}finally{f(!1)}}}),_jsx(Button,{label:"Delete",icon:"pi pi-trash",className:"p-button-danger",disabled:u||!l,onClick:async()=>{if(l&&window.confirm(`Remove method "${l}"? This is staged — Save persists it.`)){f(!0);try{await o.removeMethod(l),d(null)}catch(e){m(String(e?.message??e))}finally{f(!1)}}}})]}),_jsxs(DataTable,{value:b,selection:b.find(e=>e.id===l)??null,onSelectionChange:e=>d(e.value?.id??null),selectionMode:"single",dataKey:"id",scrollable:!0,scrollHeight:"flex",emptyMessage:o.loading?"Loading…":"No test methods defined.",children:[_jsx(Column,{field:"id",header:"Method ID"}),_jsx(Column,{field:"label",header:"Label"})]})]}),_jsx("section",{className:"tis-editor__detail",children:l&&o.config?.methods[l]?_jsxs(_Fragment,{children:[c&&_jsx("div",{className:"tis-editor__error",children:_jsx("pre",{children:c})}),_jsx(MethodFormEditor,{methodId:l,method:o.config.methods[l],onApply:async e=>{if(l){f(!0);try{await o.putMethod(l,e),m(null)}catch(e){m(String(e?.message??e))}finally{f(!1)}}},busy:u,knownAssetTypes:n.types})]}):_jsx("div",{className:"tis-editor__empty",children:"Select a test method on the left, or create a new one."})})]}),_jsxs(Dialog,{header:"New Test Method",visible:g,onHide:()=>_(!1),style:{width:"24rem"},children:[_jsxs("label",{className:"tis-editor__new-method-label",children:["Method ID",_jsx(InputText,{value:x,onChange:e=>y(e.target.value),placeholder:"e.g. translational_traction",autoFocus:!0})]}),_jsx("small",{children:"Canonical key — appears in wire payloads, on-disk paths, and generated code."}),_jsxs("div",{style:{display:"flex",gap:"0.5rem",justifyContent:"flex-end",marginTop:"1rem"},children:[_jsx(Button,{label:"Cancel",className:"p-button-text",onClick:()=>_(!1)}),_jsx(Button,{label:"Create",disabled:!x.trim()||u,onClick:async()=>{const e=x.trim();if(e)if(o.config?.methods[e])m(`A method named "${e}" already exists.`);else{f(!0);try{await o.putMethod(e,EMPTY_METHOD),d(e),_(!1),y("")}catch(e){m(String(e?.message??e))}finally{f(!1)}}}})]})]}),_jsx(SaveDiffDialog,{visible:p,staged:o.config?.methods??{},invoker:i,onConfirm:async()=>{f(!0);try{await o.save(),h(!1)}catch(e){m(String(e?.message??e))}finally{f(!1)}},onCancel:()=>h(!1)})]})})};export default TisConfigEditor;
|
|
1
|
+
import{jsx as _jsx,jsxs as _jsxs,Fragment as _Fragment}from"react/jsx-runtime";import{useEffect,useMemo,useRef,useState}from"react";import{DataTable}from"primereact/datatable";import{Column}from"primereact/column";import{Button}from"primereact/button";import{InputText}from"primereact/inputtext";import{Dialog}from"primereact/dialog";import{Message}from"primereact/message";import{SelectButton}from"primereact/selectbutton";import{useContext}from"react";import{EventEmitterContext}from"../../core/EventEmitterContext";import{MessageType}from"../../hub/CommandMessage";import{useTisConfig}from"../../hooks/useTisConfig";import{useAmsAssetTypes}from"../../hooks/useAmsAssetTypes";import{MethodFormEditor}from"./editor/MethodFormEditor";import{SaveDiffDialog}from"./editor/SaveDiffDialog";import{DeleteMethodDialog}from"./DeleteMethodDialog";import{buildTransfer,downloadTransfer,METHOD_ID_RE,METHOD_ID_RULE,parseTransfer}from"./MethodTransfer";import{useMethodSequence,emptySequence}from"../../hooks/useMethodSequence";import"./TisConfigEditor.css";import{useGmVariables}from"../../hooks/useGmVariables";import{useSequenceProducers}from"../../hooks/useSequenceProducers";import{AuthoringContext}from"./editor/AuthoringContext";import{AutoCoreTagContext}from"../../core/AutoCoreTagContext";const EMPTY_METHOD={label:"",description:"",project_fields:[],config_fields:[],cycle_config_fields:[],cycle_fields:[],results_fields:[],views:{},asset_refs:[]};export const TisConfigEditor=({projectId:e,invoker:t})=>{const s=useContext(EventEmitterContext),i=useMemo(()=>t??(async(e,t)=>await s.invoke(e,MessageType.Request,t)),[t,s]),o=useTisConfig(e,{invoker:i}),{tags:a}=useContext(AutoCoreTagContext),r=useGmVariables({invoker:i,fallbackTags:a}),n=useAmsAssetTypes({invoker:i}),[l,d]=useState(null),[c,m]=useState(null),[u,h]=useState(!1),[p,_]=useState(!1),[f,g]=useState(!1),[x,y]=useState(""),[b,j]=useState("sequence"),[v,T]=useState(!1),C=useRef(null),[w,M]=useState(null),[E,D]=useState(""),[S,k]=useState(null),N=useMethodSequence(),I=useMemo(()=>o.config?Object.entries(o.config.methods).map(([e,t])=>({id:e,label:t?.label??""})):[],[o.config]);useEffect(()=>{if(!l&&o.config){const e=o.config.defaultMethodId||Object.keys(o.config.methods)[0]||null;d(e)}},[o.config,l]),useEffect(()=>{m(null)},[l]);const{producedNames:q}=useSequenceProducers(l),A=useMemo(()=>({variables:r.variables,producedNames:q,partial:r.partial}),[r.variables,q,r.partial]),H=async()=>{if(!w)return;const e=E.trim();if(METHOD_ID_RE.test(e)){h(!0);try{w.sequence&&await N.write(e,w.sequence),await o.putMethod(e,w.schema),d(e),M(null),k(null)}catch(e){k(String(e?.message??e))}finally{h(!1)}}else k(`"${e}" is not a valid method id. ${METHOD_ID_RULE}`)};return _jsx(AuthoringContext.Provider,{value:A,children:_jsxs("div",{className:"tis-editor",children:[_jsxs("header",{className:"tis-editor__header",children:[_jsxs("h2",{children:["Test Methods"," ",o.config?.dirty&&_jsx("span",{className:"tis-editor__dirty-pill",children:"unsaved"})]}),_jsxs("div",{className:"tis-editor__header-actions",children:[_jsx(Button,{label:"Save…",icon:"pi pi-save",disabled:u||!o.config?.dirty,onClick:()=>_(!0)}),_jsx(Button,{label:"Revert",icon:"pi pi-undo",className:"p-button-secondary",disabled:u||!o.config?.dirty,onClick:async()=>{if(window.confirm("Discard all in-progress edits? This cannot be undone.")){h(!0);try{await o.revert()}catch(e){m(String(e?.message??e))}finally{h(!1)}}}})]})]}),o.error&&_jsxs("div",{className:"tis-editor__error",children:[_jsx("strong",{children:"Error:"})," ",_jsx("pre",{children:o.error})]}),r.partial&&_jsx("div",{className:"tis-editor__notice",children:"This server cannot describe its own variables, so the pickers are listing only the variables published to this HMI, without descriptions. Update autocore_server to get the full list."}),_jsxs("div",{className:"tis-editor__body",children:[_jsxs("aside",{className:"tis-editor__sidebar",children:[_jsxs("div",{className:"tis-editor__sidebar-actions",children:[_jsx(Button,{label:"New",icon:"pi pi-plus",disabled:u,onClick:()=>g(!0)}),_jsx(Button,{label:"Duplicate",icon:"pi pi-clone",className:"p-button-secondary",disabled:u||!l,onClick:async()=>{if(!l||!o.config)return;const e=o.config.methods[l];if(!e)return;let t=`${l}_copy`,s=2;for(;o.config.methods[t];)t=`${l}_copy_${s++}`;h(!0);try{await N.copy(l,t),await o.putMethod(t,JSON.parse(JSON.stringify(e))),d(t)}catch(e){m(String(e?.message??e))}finally{h(!1)}}}),_jsx(Button,{label:"Delete",icon:"pi pi-trash",className:"p-button-danger",disabled:u||!l,onClick:()=>T(!0)})]}),_jsxs("div",{className:"tis-editor__sidebar-actions",children:[_jsx(Button,{label:"Import",icon:"pi pi-upload",className:"p-button-secondary",disabled:u,onClick:()=>C.current?.click()}),_jsx(Button,{label:"Export",icon:"pi pi-download",className:"p-button-secondary",disabled:u||!l,onClick:async()=>{if(!l||!o.config)return;const e=o.config.methods[l];if(e){h(!0);try{const t="sequence"===e.procedure?await N.read(l):null;downloadTransfer(buildTransfer(l,e,t))}catch(e){m(String(e?.message??e))}finally{h(!1)}}}})]}),S&&_jsx("div",{className:"tis-editor__error",children:_jsx("pre",{children:S})}),_jsx("input",{ref:C,type:"file",accept:".json,.method.json,application/json",style:{display:"none"},onChange:e=>{const t=e.target.files?.[0];e.target.value="",t&&(async e=>{const t=parseTransfer(await e.text());if("error"in t)return k(`${e.name}: ${t.error}`),void M(null);k(null),M(t.file),D(t.file.method_id)})(t)}}),_jsxs(DataTable,{value:I,selection:I.find(e=>e.id===l)??null,onSelectionChange:e=>d(e.value?.id??null),selectionMode:"single",dataKey:"id",scrollable:!0,scrollHeight:"flex",emptyMessage:o.loading?"Loading…":"No test methods defined.",children:[_jsx(Column,{field:"id",header:"Method ID"}),_jsx(Column,{field:"label",header:"Label"})]})]}),_jsx("section",{className:"tis-editor__detail",children:l&&o.config?.methods[l]?_jsxs(_Fragment,{children:[c&&_jsx("div",{className:"tis-editor__error",children:_jsx("pre",{children:c})}),_jsx(MethodFormEditor,{methodId:l,method:o.config.methods[l],onApply:async e=>{if(l){h(!0);try{await o.putMethod(l,e),m(null)}catch(e){m(String(e?.message??e))}finally{h(!1)}}},busy:u,knownAssetTypes:n.types})]}):_jsx("div",{className:"tis-editor__empty",children:"Select a test method on the left, or create a new one."})})]}),_jsxs(Dialog,{header:"New Test Method",visible:f,onHide:()=>g(!1),style:{width:"24rem"},children:[_jsxs("label",{className:"tis-editor__new-method-label",children:["Method ID",_jsx(InputText,{value:x,onChange:e=>y(e.target.value),placeholder:"e.g. translational_traction",autoFocus:!0})]}),_jsx("small",{children:"Canonical key — appears in wire payloads, on-disk paths, and generated code."}),""!==x.trim()&&!METHOD_ID_RE.test(x.trim())&&_jsx(Message,{severity:"warn",text:METHOD_ID_RULE,style:{width:"100%",marginTop:"0.5rem"}}),_jsxs("label",{className:"tis-editor__new-method-label",style:{marginTop:"1rem"},children:["Procedure",_jsx(SelectButton,{value:b,options:[{label:"Sequence",value:"sequence"},{label:"Control program",value:"control"}],allowEmpty:!1,onChange:e=>e.value&&j(e.value)})]}),_jsx("small",{children:"sequence"===b?"The steps are a file you edit on the Method screen. Creating this method also creates an empty sequence.":"The steps are compiled into the control program. A new method of this kind needs a rebuild and redeploy before it will run."}),_jsxs("div",{style:{display:"flex",gap:"0.5rem",justifyContent:"flex-end",marginTop:"1rem"},children:[_jsx(Button,{label:"Cancel",className:"p-button-text",onClick:()=>g(!1)}),_jsx(Button,{label:"Create",disabled:!METHOD_ID_RE.test(x.trim())||u,onClick:async()=>{const e=x.trim();if(e)if(METHOD_ID_RE.test(e))if(o.config?.methods[e])m(`A method named "${e}" already exists.`);else{h(!0);try{const t="sequence"===b?{...EMPTY_METHOD,procedure:"sequence"}:{...EMPTY_METHOD};"sequence"===b&&await N.write(e,emptySequence(e)),await o.putMethod(e,t),d(e),g(!1),y("")}catch(e){m(String(e?.message??e))}finally{h(!1)}}else m(`"${e}" is not a valid method id. ${METHOD_ID_RULE}`)}})]})]}),_jsx(Dialog,{header:"Import Test Method",visible:null!==w,onHide:()=>{M(null),k(null)},style:{width:"28rem"},children:w&&(()=>{const e=!!o.config?.methods[E.trim()],t=METHOD_ID_RE.test(E.trim());return _jsxs(_Fragment,{children:[_jsxs("p",{style:{marginTop:0},children:[_jsx("strong",{children:w.method_id}),w.schema.label?` — ${w.schema.label}`:"",_jsx("br",{}),_jsx("small",{children:w.sequence?"Includes a sequence procedure.":"Control-program method — no sequence in this file."})]}),_jsxs("label",{className:"tis-editor__new-method-label",children:["Import as",_jsx(InputText,{value:E,onChange:e=>D(e.target.value),autoFocus:!0})]}),!t&&""!==E.trim()&&_jsx(Message,{severity:"warn",text:METHOD_ID_RULE,style:{width:"100%"}}),e&&t&&_jsx(Message,{severity:"warn",text:`"${E.trim()}" already exists. Importing will REPLACE it, including its sequence. Change the name above to keep both.`,style:{width:"100%"}}),S&&_jsx(Message,{severity:"error",text:S,style:{width:"100%"}}),_jsxs("div",{style:{display:"flex",gap:"0.5rem",justifyContent:"flex-end",marginTop:"1rem"},children:[_jsx(Button,{label:"Cancel",className:"p-button-text",onClick:()=>{M(null),k(null)}}),_jsx(Button,{label:e?"Replace":"Import",className:e?"p-button-danger":void 0,disabled:!t||u,onClick:H})]})]})})()}),_jsx(DeleteMethodDialog,{visible:v,methodId:l,hasSequence:!!l&&"sequence"===o.config?.methods[l]?.procedure,onDownloadArchive:async t=>{const s=await i("tis.export_method_zip",{project_id:e,method_id:t});if(!s?.success)throw new Error(s?.error_message??"export_method_zip failed");const o="string"==typeof s.data?.download_url?s.data.download_url:"";if(!o)throw new Error("the server returned no download URL");const a=document.createElement("a");return a.href=o,a.download="string"==typeof s.data?.filename&&s.data.filename?s.data.filename:`${t}_method_archive.zip`,a.click(),!0},onConfirm:async()=>{if(l){h(!0);try{await o.removeMethod(l),await N.remove(l),d(null),T(!1)}catch(e){m(String(e?.message??e))}finally{h(!1)}}},onCancel:()=>T(!1),busy:u}),_jsx(SaveDiffDialog,{visible:p,staged:o.config?.methods??{},invoker:i,onConfirm:async()=>{h(!0);try{await o.save(),_(!1)}catch(e){m(String(e?.message??e))}finally{h(!1)}},onCancel:()=>_(!1)})]})})};export default TisConfigEditor;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IdentitySection.d.ts","sourceRoot":"","sources":["../../../../src/components/tis-editor/editor/IdentitySection.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"IdentitySection.d.ts","sourceRoot":"","sources":["../../../../src/components/tis-editor/editor/IdentitySection.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAE3C,MAAM,WAAW,oBAAoB;IACjC,MAAM,EAAE,UAAU,CAAC;IACnB,QAAQ,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,CAAC;CACxC;AAED,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAuD1D,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import{InputText}from"primereact/inputtext";import{InputTextarea}from"primereact/inputtextarea";import{FormSection}from"../../forms/FormSection";import{FormRow}from"../../forms/FormRow";export const IdentitySection=({method:e,onChange:t})=>_jsxs(FormSection,{title:"Identity",description:"Display label
|
|
1
|
+
import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import{InputText}from"primereact/inputtext";import{InputTextarea}from"primereact/inputtextarea";import{SelectButton}from"primereact/selectbutton";import{FormSection}from"../../forms/FormSection";import{FormRow}from"../../forms/FormRow";export const IdentitySection=({method:e,onChange:t})=>_jsxs(FormSection,{title:"Identity",description:"Display label, operator-facing description, and which engine runs the steps.",children:[_jsx(FormRow,{label:"Label",hint:"Pretty name shown in the Test Method picker.",children:_jsx(InputText,{value:e.label??"",onChange:o=>t({...e,label:o.target.value})})}),_jsx(FormRow,{label:"Description",hint:"Long-form guidance shown beneath the picker when this method is selected.",children:_jsx(InputTextarea,{rows:3,value:e.description??"",onChange:o=>t({...e,description:o.target.value})})}),_jsx(FormRow,{label:"Procedure",hint:"Sequence: the steps are a file you edit on the Method screen. Control program: compiled Rust, requires a rebuild to add or change a method.",children:_jsx(SelectButton,{value:e.procedure??"control",options:[{label:"Control program",value:"control"},{label:"Sequence",value:"sequence"}],allowEmpty:!1,onChange:o=>{const r={...e};"sequence"===o.value?r.procedure="sequence":delete r.procedure,t(r)}})})]});
|
|
@@ -166,6 +166,17 @@ export interface TestMethod {
|
|
|
166
166
|
asset_refs?: AssetRef[];
|
|
167
167
|
analysis?: AnalysisShape | null;
|
|
168
168
|
configurations?: TestConfiguration[];
|
|
169
|
+
/**
|
|
170
|
+
* Which engine runs this method's steps.
|
|
171
|
+
*
|
|
172
|
+
* `"sequence"` means the procedure is data at
|
|
173
|
+
* `methods/<method_id>.seq.json`, authored in the sequence workbench and
|
|
174
|
+
* executed by autocore-seq — so a method can be created on the machine and
|
|
175
|
+
* run without regenerating and rebuilding the control program.
|
|
176
|
+
* `"control"` (the default) means compiled Rust, which is every method that
|
|
177
|
+
* predates this field.
|
|
178
|
+
*/
|
|
179
|
+
procedure?: 'control' | 'sequence';
|
|
169
180
|
[key: string]: unknown;
|
|
170
181
|
}
|
|
171
182
|
export type FieldArrayKey = 'project_fields' | 'config_fields' | 'cycle_config_fields' | 'cycle_fields' | 'results_fields';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/components/tis-editor/types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/components/tis-editor/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,MAAM,SAAS,GACf,QAAQ,GACR,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAC7B,KAAK,GAAG,KAAK,GACb,MAAM,CAAC;AAEb,MAAM,WAAW,SAAS;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,SAAS,GAAG,MAAM,CAAC;IACzB;;;kDAG8C;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;6DAEyD;IACzD;;;8DAG0D;IAC1D,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB;;2EAEuE;IACvE,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B;;yDAEqD;IACrD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;wBAGoB;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,MAAM,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,QAAQ,GAAG,OAAO,CAAC;AAC/D,MAAM,MAAM,OAAO,GAAG,cAAc,GAAG,SAAS,CAAC;AAEjD;;;;;;;;;GASG;AACH,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,SAAS,CAAC;AAE1C,MAAM,WAAW,aAAa;IAC1B,oDAAoD;IACpD,EAAE,EAAE,KAAK,CAAC;IACV;mEAC+D;IAC/D,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,2EAA2E;IAC3E,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,0DAA0D;IAC1D,KAAK,CAAC,EAAE,QAAQ,CAAC;CACpB;AAED,MAAM,WAAW,SAAS;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CAC7B;AAED,MAAM,MAAM,aAAa,GAAG,eAAe,GAAG,WAAW,CAAC;AAE1D,MAAM,WAAW,SAAS;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,aAAa,GAAG,MAAM,CAAC;IAC7B,CAAC,EAAE,SAAS,CAAC;IACb,CAAC,EAAE,WAAW,EAAE,CAAC;IACjB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC;AAE1D,MAAM,WAAW,SAAS;IACtB,MAAM,EAAE,eAAe,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,MAAM,MAAM,cAAc,GAAG,aAAa,GAAG,aAAa,CAAC;AAC3D,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,CAAC;AAE9D,MAAM,WAAW,QAAQ;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,cAAc,GAAG,MAAM,CAAC;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oBAAoB,CAAC,EAAE,iBAAiB,GAAG,MAAM,CAAC;IAClD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,gBAAgB,GAAG,KAAK,GAAG,OAAO,CAAC;AAE/C,MAAM,WAAW,UAAU;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,SAAS,EAAE,CAAC;IAC7B,aAAa,CAAC,EAAE,SAAS,EAAE,CAAC;IAC5B;uCACmC;IACnC,mBAAmB,CAAC,EAAE,SAAS,EAAE,CAAC;IAClC,iEAAiE;IACjE,kBAAkB,CAAC,EAAE,gBAAgB,CAAC;IACtC;+DAC2D;IAC3D,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,YAAY,CAAC,EAAE,SAAS,EAAE,CAAC;IAC3B,cAAc,CAAC,EAAE,SAAS,EAAE,CAAC;IAC7B,QAAQ,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAClC,UAAU,CAAC,EAAE,QAAQ,EAAE,CAAC;IACxB,QAAQ,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC;IAChC,cAAc,CAAC,EAAE,iBAAiB,EAAE,CAAC;IACrC;;;;;;;;;OASG;IACH,SAAS,CAAC,EAAE,SAAS,GAAG,UAAU,CAAC;IACnC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B;AAED,MAAM,MAAM,aAAa,GACnB,gBAAgB,GAChB,eAAe,GACf,qBAAqB,GACrB,cAAc,GACd,gBAAgB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VariablePicker.d.ts","sourceRoot":"","sources":["../../../src/components/varpick/VariablePicker.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,OAAO,EAGH,KAAK,OAAO,EACZ,KAAK,aAAa,EACrB,MAAM,0BAA0B,CAAC;AAClC,OAAO,eAAe,CAAC;AAEvB,MAAM,WAAW,mBAAmB;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,sBAAsB;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yDAAyD;IACzD,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,wEAAwE;IACxE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,MAAM,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;CAC1C;AAED,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,
|
|
1
|
+
{"version":3,"file":"VariablePicker.d.ts","sourceRoot":"","sources":["../../../src/components/varpick/VariablePicker.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,OAAO,EAGH,KAAK,OAAO,EACZ,KAAK,aAAa,EACrB,MAAM,0BAA0B,CAAC;AAClC,OAAO,eAAe,CAAC;AAEvB,MAAM,WAAW,mBAAmB;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,sBAAsB;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yDAAyD;IACzD,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,wEAAwE;IACxE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,MAAM,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;CAC1C;AAED,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CAoHxD,CAAC;AAEF,eAAe,cAAc,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import*as React from"react";import{Dialog}from"primereact/dialog";import{Button}from"primereact/button";import{InputText}from"primereact/inputtext";import{firstChoosable,searchCatalog}from"@adcops/autocore-varpick";import"./varpick.css";export const VariablePicker=({visible:a,catalog:e,title:i,hint:s,initialQuery:c,onCancel:t,onPick:r})=>{const[l,n]=React.useState(c??""),[o,p]=React.useState(null);React.useEffect(()=>{a&&n(c??"")},[a,c]);const d=React.useMemo(()=>searchCatalog(e,l),[e,l]);React.useEffect(()=>{p(firstChoosable(d)?.id??null)},[d]);const _=a=>null===a?void 0:d.flatMap(a=>a.entries).find(e=>e.id===a),m=a=>{const e=a??_(o);e&&!e.disabled&&r(e)},h=_jsxs("div",{className:"ac-varpick__foot",children:[_jsx(Button,{label:"Cancel",className:"p-button-text",onClick:t}),_jsx(Button,{label:"Insert",disabled:void 0===_(o),onClick:()=>m()})]});return _jsxs(Dialog,{header:i??"Insert a variable",visible:a,onHide:t,footer:h,style:{width:"44rem",maxWidth:"95vw"},children:[s&&_jsx("div",{className:"ac-varpick__hint",children:s}),_jsx(InputText,{className:"ac-varpick__search",value:l,autoFocus:!0,placeholder:"name, or what it means — try “load” or “EL3356”",onChange:a=>n(a.target.value),onKeyDown:a=>{"Enter"===a.key&&(a.preventDefault(),m())}}),0===d.length?_jsx("div",{className:"ac-varpick__empty",children:0===e.length?"Nothing to pick from. The machine published no variables — the server may be an older build without gm.get_variables.":`No variable matches “${l}”.`}):_jsx("div",{className:"ac-varpick__list",children:d.map(a=>_jsxs("div",{className:"ac-varpick__group",children:[_jsxs("div",{className:"ac-varpick__grouphead",children:[_jsx("span",{className:"ac-varpick__grouptitle",children:a.title}),a.hint&&_jsx("span",{className:"ac-varpick__grouphint",children:a.hint})]}),a.entries.map(a=>_jsxs("button",{type:"button",className:"ac-varpick__row"+(a.id===o?" ac-varpick__row--on":"")+(a.disabled?" ac-varpick__row--off":""),"aria-pressed":a.id===o,disabled:!!a.disabled,onClick:()=>p(a.id),onDoubleClick:()=>m(a),children:[_jsxs("span",{className:"ac-varpick__line",children:[_jsx("code",{className:"ac-varpick__name",children:a.name}),a.label&&_jsx("span",{className:"ac-varpick__label",children:a.label}),a.unit&&_jsx("span",{className:"ac-varpick__chip",children:a.unit}),a.type&&_jsx("span",{className:"ac-varpick__chip",children:a.type}),void 0!==a.live&&_jsxs("span",{className:"ac-varpick__live",children:["now ",a.live]})]}),a.description&&_jsx("span",{className:"ac-varpick__desc",children:a.description}),a.disabled&&_jsx("span",{className:"ac-varpick__why",children:a.disabled}),a.note&&_jsx("span",{className:"ac-varpick__note",children:a.note})]},a.id))]},a.id))})]})};export default VariablePicker;
|
|
1
|
+
import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import*as React from"react";import{Dialog}from"primereact/dialog";import{Button}from"primereact/button";import{InputText}from"primereact/inputtext";import{firstChoosable,searchCatalog}from"@adcops/autocore-varpick";import"./varpick.css";export const VariablePicker=({visible:a,catalog:e,title:i,hint:s,initialQuery:c,onCancel:t,onPick:r})=>{const[l,n]=React.useState(c??""),[o,p]=React.useState(null);React.useEffect(()=>{a&&n(c??"")},[a,c]);const d=React.useMemo(()=>searchCatalog(e,l),[e,l]);React.useEffect(()=>{p(firstChoosable(d)?.id??null)},[d]);const _=a=>null===a?void 0:d.flatMap(a=>a.entries).find(e=>e.id===a),m=a=>{const e=a??_(o);e&&!e.disabled&&r(e)},h=_jsxs("div",{className:"ac-varpick__foot",children:[_jsx(Button,{label:"Cancel",className:"p-button-text",onClick:t}),_jsx(Button,{label:"Insert",disabled:void 0===_(o),onClick:()=>m()})]});return _jsxs(Dialog,{header:i??"Insert a variable",visible:a,onHide:t,footer:h,className:"ac-varpick",style:{width:"44rem",maxWidth:"95vw"},children:[s&&_jsx("div",{className:"ac-varpick__hint",children:s}),_jsx(InputText,{className:"ac-varpick__search",value:l,autoFocus:!0,placeholder:"name, or what it means — try “load” or “EL3356”",onChange:a=>n(a.target.value),onKeyDown:a=>{"Enter"===a.key&&(a.preventDefault(),m())}}),0===d.length?_jsx("div",{className:"ac-varpick__empty",children:0===e.length?"Nothing to pick from. The machine published no variables — the server may be an older build without gm.get_variables.":`No variable matches “${l}”.`}):_jsx("div",{className:"ac-varpick__list",children:d.map(a=>_jsxs("div",{className:"ac-varpick__group",children:[_jsxs("div",{className:"ac-varpick__grouphead",children:[_jsx("span",{className:"ac-varpick__grouptitle",children:a.title}),a.hint&&_jsx("span",{className:"ac-varpick__grouphint",children:a.hint})]}),a.entries.map(a=>_jsxs("button",{type:"button",className:"ac-varpick__row"+(a.id===o?" ac-varpick__row--on":"")+(a.disabled?" ac-varpick__row--off":""),"aria-pressed":a.id===o,disabled:!!a.disabled,onClick:()=>p(a.id),onDoubleClick:()=>m(a),children:[_jsxs("span",{className:"ac-varpick__line",children:[_jsx("code",{className:"ac-varpick__name",children:a.name}),a.label&&_jsx("span",{className:"ac-varpick__label",children:a.label}),a.unit&&_jsx("span",{className:"ac-varpick__chip",children:a.unit}),a.type&&_jsx("span",{className:"ac-varpick__chip",children:a.type}),void 0!==a.live&&_jsxs("span",{className:"ac-varpick__live",children:["now ",a.live]})]}),a.description&&_jsx("span",{className:"ac-varpick__desc",children:a.description}),a.disabled&&_jsx("span",{className:"ac-varpick__why",children:a.disabled}),a.note&&_jsx("span",{className:"ac-varpick__note",children:a.note})]},a.id))]},a.id))})]})};export default VariablePicker;
|
|
@@ -1,12 +1,66 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* Variable picker.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* ## The token bridge
|
|
5
|
+
*
|
|
6
|
+
* Every colour resolves `--ac-*` first, then the PrimeReact theme variable,
|
|
7
|
+
* then a literal. That ordering is the whole point:
|
|
8
|
+
*
|
|
9
|
+
* - **`--ac-*`** is autocore's own design-token layer, which 4.0 supplies.
|
|
10
|
+
* When it exists, this file needs no edit to follow it.
|
|
11
|
+
* - **PrimeReact's `--surface-*` / `--text-color`** is what 3.5 actually
|
|
12
|
+
* defines today, so the picker matches whatever theme the machine runs,
|
|
13
|
+
* light or dark.
|
|
14
|
+
* - **The literal** keeps an un-themed host legible — the playground, the
|
|
15
|
+
* jsdom test harness — rather than rendering black on black.
|
|
16
|
+
*
|
|
17
|
+
* The token NAMES and their fallbacks are copied deliberately from
|
|
18
|
+
* `@adcops/autocore-seq-react`'s `styles.css`. The sequence editor's picker and
|
|
19
|
+
* this one sit one tab apart doing the identical thing; if they read different
|
|
20
|
+
* token names, 4.0 would have to satisfy two sets and the two panels could
|
|
21
|
+
* drift to different colours while both looked "correct".
|
|
22
|
+
*
|
|
23
|
+
* ## Why the tokens are declared twice
|
|
24
|
+
*
|
|
25
|
+
* The field lives inside the TIS editor's form, but PrimeReact renders the
|
|
26
|
+
* Dialog through a PORTAL to `<body>` — so the two halves are not in one
|
|
27
|
+
* subtree and a single scoping root cannot cover both. Hence the declaration on
|
|
28
|
+
* `.ac-varpick` (the dialog, which passes that className) and on
|
|
29
|
+
* `.ac-varpick__input` (the field). Declaring them on `:root` instead would
|
|
30
|
+
* push a dozen names into every consuming application's global scope for the
|
|
31
|
+
* benefit of one component.
|
|
8
32
|
*/
|
|
9
33
|
|
|
34
|
+
.ac-varpick,
|
|
35
|
+
.ac-varpick__input {
|
|
36
|
+
/* -- surfaces ---------------------------------------------------- */
|
|
37
|
+
--vp-sunk: var(--ac-surface-sunk, var(--surface-50, #f8f9fa));
|
|
38
|
+
--vp-overlay: var(--ac-surface-overlay, var(--surface-overlay,#ffffff));
|
|
39
|
+
--vp-hover: var(--ac-hover, var(--surface-hover, rgba(127, 127, 127, 0.08)));
|
|
40
|
+
|
|
41
|
+
/* -- ink --------------------------------------------------------- */
|
|
42
|
+
--vp-ink: var(--ac-on-surface, var(--text-color, #111827));
|
|
43
|
+
--vp-ink-muted: var(--ac-on-surface-muted, var(--text-color-secondary, #6b7280));
|
|
44
|
+
--vp-ink-subtle: var(--ac-on-surface-subtle, var(--text-color-secondary, #8b95a1));
|
|
45
|
+
|
|
46
|
+
/* -- lines ------------------------------------------------------- */
|
|
47
|
+
--vp-border: var(--ac-border, var(--surface-border, rgba(127, 127, 127, 0.25)));
|
|
48
|
+
--vp-divider: var(--ac-divider, var(--surface-border, rgba(127, 127, 127, 0.18)));
|
|
49
|
+
|
|
50
|
+
/* -- accents ----------------------------------------------------- */
|
|
51
|
+
--vp-primary: var(--ac-primary, var(--primary-color, #2563eb));
|
|
52
|
+
--vp-primary-subtle: var(--ac-primary-subtle, var(--highlight-bg, rgba(37, 99, 235, 0.14)));
|
|
53
|
+
--vp-success: var(--ac-success, var(--green-500, #15803d));
|
|
54
|
+
--vp-warning: var(--ac-warning, var(--orange-500, #b45309));
|
|
55
|
+
--vp-info: var(--ac-info, var(--blue-500, #0369a1));
|
|
56
|
+
--vp-focus-ring: var(--ac-focus-ring, rgba(37, 99, 235, 0.45));
|
|
57
|
+
|
|
58
|
+
/* -- type -------------------------------------------------------- */
|
|
59
|
+
--vp-mono: var(--ac-font-mono, ui-monospace, "Cascadia Mono", Menlo, Consolas, monospace);
|
|
60
|
+
--vp-font-sm: var(--ac-text-sm, 0.8125rem);
|
|
61
|
+
--vp-font-xs: var(--ac-text-xs, 0.75rem);
|
|
62
|
+
}
|
|
63
|
+
|
|
10
64
|
.ac-varpick__input {
|
|
11
65
|
display: flex;
|
|
12
66
|
align-items: stretch;
|
|
@@ -31,8 +85,8 @@
|
|
|
31
85
|
}
|
|
32
86
|
|
|
33
87
|
.ac-varpick__hint {
|
|
34
|
-
font-size:
|
|
35
|
-
color: var(--
|
|
88
|
+
font-size: var(--vp-font-sm);
|
|
89
|
+
color: var(--vp-ink-muted);
|
|
36
90
|
margin-bottom: 0.75rem;
|
|
37
91
|
line-height: 1.4;
|
|
38
92
|
}
|
|
@@ -41,7 +95,7 @@
|
|
|
41
95
|
|
|
42
96
|
.ac-varpick__empty {
|
|
43
97
|
padding: 1.5rem 0.25rem;
|
|
44
|
-
color: var(--
|
|
98
|
+
color: var(--vp-ink-muted);
|
|
45
99
|
font-size: 0.875rem;
|
|
46
100
|
}
|
|
47
101
|
|
|
@@ -64,24 +118,24 @@
|
|
|
64
118
|
gap: 0.5rem;
|
|
65
119
|
padding-bottom: 0.25rem;
|
|
66
120
|
margin-bottom: 0.25rem;
|
|
67
|
-
border-bottom: 1px solid var(--
|
|
121
|
+
border-bottom: 1px solid var(--vp-divider);
|
|
68
122
|
position: sticky;
|
|
69
123
|
top: 0;
|
|
70
|
-
background: var(--
|
|
124
|
+
background: var(--vp-overlay);
|
|
71
125
|
z-index: 1;
|
|
72
126
|
}
|
|
73
127
|
|
|
74
128
|
.ac-varpick__grouptitle {
|
|
75
|
-
font-size:
|
|
129
|
+
font-size: var(--vp-font-xs);
|
|
76
130
|
font-weight: 700;
|
|
77
131
|
letter-spacing: 0.04em;
|
|
78
132
|
text-transform: uppercase;
|
|
79
|
-
color: var(--
|
|
133
|
+
color: var(--vp-ink-muted);
|
|
80
134
|
}
|
|
81
135
|
|
|
82
136
|
.ac-varpick__grouphint {
|
|
83
|
-
font-size:
|
|
84
|
-
color: var(--
|
|
137
|
+
font-size: var(--vp-font-xs);
|
|
138
|
+
color: var(--vp-ink-subtle);
|
|
85
139
|
}
|
|
86
140
|
|
|
87
141
|
/*
|
|
@@ -102,21 +156,21 @@
|
|
|
102
156
|
border: 1px solid transparent;
|
|
103
157
|
border-radius: 3px;
|
|
104
158
|
background: transparent;
|
|
105
|
-
color: var(--
|
|
159
|
+
color: var(--vp-ink);
|
|
106
160
|
font: inherit;
|
|
107
161
|
cursor: pointer;
|
|
108
162
|
}
|
|
109
163
|
|
|
110
|
-
.ac-varpick__row:hover { background: var(--
|
|
164
|
+
.ac-varpick__row:hover { background: var(--vp-hover); }
|
|
111
165
|
|
|
112
166
|
.ac-varpick__row:focus-visible {
|
|
113
|
-
outline: 2px solid var(--
|
|
167
|
+
outline: 2px solid var(--vp-focus-ring);
|
|
114
168
|
outline-offset: -2px;
|
|
115
169
|
}
|
|
116
170
|
|
|
117
171
|
.ac-varpick__row--on {
|
|
118
|
-
background: var(--
|
|
119
|
-
border-color: var(--primary
|
|
172
|
+
background: var(--vp-primary-subtle);
|
|
173
|
+
border-color: var(--vp-primary);
|
|
120
174
|
}
|
|
121
175
|
|
|
122
176
|
.ac-varpick__row--off { opacity: 0.55; cursor: default; }
|
|
@@ -130,19 +184,19 @@
|
|
|
130
184
|
}
|
|
131
185
|
|
|
132
186
|
.ac-varpick__name {
|
|
133
|
-
font-family: var(--
|
|
187
|
+
font-family: var(--vp-mono);
|
|
134
188
|
font-weight: 600;
|
|
135
189
|
}
|
|
136
190
|
|
|
137
191
|
.ac-varpick__label { font-size: 0.875rem; }
|
|
138
192
|
|
|
139
193
|
.ac-varpick__chip {
|
|
140
|
-
font-size:
|
|
194
|
+
font-size: var(--vp-font-xs);
|
|
141
195
|
padding: 0 6px;
|
|
142
196
|
border-radius: 999px;
|
|
143
|
-
background: var(--
|
|
144
|
-
border: 1px solid var(--
|
|
145
|
-
color: var(--
|
|
197
|
+
background: var(--vp-sunk);
|
|
198
|
+
border: 1px solid var(--vp-border);
|
|
199
|
+
color: var(--vp-ink-muted);
|
|
146
200
|
/* A unit symbol's case is meaningful: "mm/s", "N", "MPa". */
|
|
147
201
|
text-transform: none;
|
|
148
202
|
}
|
|
@@ -150,18 +204,18 @@
|
|
|
150
204
|
/* The current reading. Nothing turns an unfamiliar name into an obvious one
|
|
151
205
|
* faster than seeing what it says right now. */
|
|
152
206
|
.ac-varpick__live {
|
|
153
|
-
font-family: var(--
|
|
154
|
-
font-size:
|
|
155
|
-
color: var(--
|
|
207
|
+
font-family: var(--vp-mono);
|
|
208
|
+
font-size: var(--vp-font-xs);
|
|
209
|
+
color: var(--vp-success);
|
|
156
210
|
}
|
|
157
211
|
|
|
158
212
|
.ac-varpick__desc {
|
|
159
|
-
font-size:
|
|
160
|
-
color: var(--
|
|
213
|
+
font-size: var(--vp-font-sm);
|
|
214
|
+
color: var(--vp-ink-muted);
|
|
161
215
|
line-height: 1.35;
|
|
162
216
|
}
|
|
163
217
|
|
|
164
|
-
.ac-varpick__why { font-size:
|
|
165
|
-
.ac-varpick__note { font-size:
|
|
218
|
+
.ac-varpick__why { font-size: var(--vp-font-sm); color: var(--vp-warning); }
|
|
219
|
+
.ac-varpick__note { font-size: var(--vp-font-sm); color: var(--vp-info); }
|
|
166
220
|
|
|
167
221
|
.ac-varpick__foot { display: flex; justify-content: flex-end; gap: 0.5rem; }
|
package/dist/hooks/index.d.ts
CHANGED
|
@@ -5,4 +5,6 @@ export { useGmVariables } from './useGmVariables';
|
|
|
5
5
|
export type { UseGmVariablesResult, UseGmVariablesOptions, GmIpcInvoker } from './useGmVariables';
|
|
6
6
|
export { useSequenceProducers, collectStoredNames } from './useSequenceProducers';
|
|
7
7
|
export type { UseSequenceProducersResult, UseSequenceProducersOptions } from './useSequenceProducers';
|
|
8
|
+
export { useMethodSequence, sequenceTopic, emptySequence, isSequenceShaped, } from './useMethodSequence';
|
|
9
|
+
export type { MethodSequenceIo, UseMethodSequenceOptions } from './useMethodSequence';
|
|
8
10
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAUA,OAAO,EAAC,qBAAqB,EAAE,gBAAgB,EAAE,cAAc,EAAC,MAAM,YAAY,CAAC;AACnF,OAAO,EAAC,cAAc,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACtE,cAAc,mBAAmB,CAAC;AAKlC,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,YAAY,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAIlG,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAClF,YAAY,EAAE,0BAA0B,EAAE,2BAA2B,EAAE,MAAM,wBAAwB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAUA,OAAO,EAAC,qBAAqB,EAAE,gBAAgB,EAAE,cAAc,EAAC,MAAM,YAAY,CAAC;AACnF,OAAO,EAAC,cAAc,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACtE,cAAc,mBAAmB,CAAC;AAKlC,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,YAAY,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAIlG,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAClF,YAAY,EAAE,0BAA0B,EAAE,2BAA2B,EAAE,MAAM,wBAAwB,CAAC;AACtG,OAAO,EACH,iBAAiB,EAAE,aAAa,EAAE,aAAa,EAAE,gBAAgB,GACpE,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EAAE,gBAAgB,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC"}
|
package/dist/hooks/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export{useAdsRegisterSymbols,useAdsWriteValue,useAdsTapValue}from"./adsHooks";export{useScaledValue,kMillimeters2Inches}from"./useScaledValue";export*from"./useServeletData";export{useGmVariables}from"./useGmVariables";export{useSequenceProducers,collectStoredNames}from"./useSequenceProducers";
|
|
1
|
+
export{useAdsRegisterSymbols,useAdsWriteValue,useAdsTapValue}from"./adsHooks";export{useScaledValue,kMillimeters2Inches}from"./useScaledValue";export*from"./useServeletData";export{useGmVariables}from"./useGmVariables";export{useSequenceProducers,collectStoredNames}from"./useSequenceProducers";export{useMethodSequence,sequenceTopic,emptySequence,isSequenceShaped}from"./useMethodSequence";
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useMethodSequence — read, write and delete the `.seq.json` half of a test
|
|
3
|
+
* method.
|
|
4
|
+
*
|
|
5
|
+
* ## One method, two files
|
|
6
|
+
*
|
|
7
|
+
* A sequence-backed test method is its `test_methods.json` schema entry PLUS
|
|
8
|
+
* `methods/<method_id>.seq.json`, the procedure the sequence engine runs. The
|
|
9
|
+
* filename is DERIVED from the method id and never stored, so the two halves
|
|
10
|
+
* cannot point at different things — see `autocore_tis::config::sequence_file`
|
|
11
|
+
* and `method_path()` in gen4_ac's `process_main.rs`, which spell the same
|
|
12
|
+
* derivation.
|
|
13
|
+
*
|
|
14
|
+
* Every method-lifecycle action therefore has to move both halves together:
|
|
15
|
+
*
|
|
16
|
+
* New — scaffold a blank procedure, or the method is unrunnable and
|
|
17
|
+
* Start refuses with "has no sequence on this machine".
|
|
18
|
+
* Duplicate — copy the procedure under the new id, or the copy silently runs
|
|
19
|
+
* nothing.
|
|
20
|
+
* Delete — remove the procedure, or an orphan file is left behind that a
|
|
21
|
+
* later method of the same name would inherit.
|
|
22
|
+
* Im/Export — carry the procedure, because a schema whose cycle columns
|
|
23
|
+
* nothing produces records blank rows forever.
|
|
24
|
+
*
|
|
25
|
+
* That last one is why import/export is a METHOD operation and not a sequence
|
|
26
|
+
* operation: half a method is not portable.
|
|
27
|
+
*
|
|
28
|
+
* The control program has no filesystem access, so all of this rides the
|
|
29
|
+
* datastore servelet over IPC, exactly as {@link useSequenceProducers} reads it.
|
|
30
|
+
*/
|
|
31
|
+
/** The datastore topic for a method's procedure. */
|
|
32
|
+
export declare function sequenceTopic(methodId: string): string;
|
|
33
|
+
/** A blank procedure, shaped so `validateMethod` and the editor accept it. */
|
|
34
|
+
export declare function emptySequence(methodId: string): Record<string, unknown>;
|
|
35
|
+
/** Is this datastore payload plausibly a `.seq.json` method? */
|
|
36
|
+
export declare function isSequenceShaped(v: any): boolean;
|
|
37
|
+
export interface UseMethodSequenceOptions {
|
|
38
|
+
/** Override the IPC layer (tests, playground). */
|
|
39
|
+
invoker?: (topic: string, messageType: number, payload: object) => Promise<any>;
|
|
40
|
+
}
|
|
41
|
+
export interface MethodSequenceIo {
|
|
42
|
+
/** The procedure for `methodId`, or null when there is none. */
|
|
43
|
+
read: (methodId: string) => Promise<any | null>;
|
|
44
|
+
/**
|
|
45
|
+
* Write `sequence` as the procedure for `methodId`.
|
|
46
|
+
*
|
|
47
|
+
* `name` is rewritten to `methodId` on the way out, unconditionally. The
|
|
48
|
+
* method id owns the identity; the `name` inside the file is a leftover
|
|
49
|
+
* from when the sequence library named itself, and a copy that keeps its
|
|
50
|
+
* source's name is a file claiming to be a method it is not.
|
|
51
|
+
*/
|
|
52
|
+
write: (methodId: string, sequence: any) => Promise<void>;
|
|
53
|
+
/** Remove the procedure for `methodId`. Resolves even if there was none. */
|
|
54
|
+
remove: (methodId: string) => Promise<void>;
|
|
55
|
+
/** Copy `from`'s procedure to `to`. No-op when `from` has none. */
|
|
56
|
+
copy: (from: string, to: string) => Promise<void>;
|
|
57
|
+
}
|
|
58
|
+
export declare function useMethodSequence(options?: UseMethodSequenceOptions): MethodSequenceIo;
|
|
59
|
+
export default useMethodSequence;
|
|
60
|
+
//# sourceMappingURL=useMethodSequence.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useMethodSequence.d.ts","sourceRoot":"","sources":["../../src/hooks/useMethodSequence.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAYH,oDAAoD;AACpD,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED,8EAA8E;AAC9E,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEvE;AAED,gEAAgE;AAChE,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,GAAG,GAAG,OAAO,CAEhD;AAED,MAAM,WAAW,wBAAwB;IACrC,kDAAkD;IAClD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;CACnF;AAED,MAAM,WAAW,gBAAgB;IAC7B,gEAAgE;IAChE,IAAI,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC;IAChD;;;;;;;OAOG;IACH,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1D,4EAA4E;IAC5E,MAAM,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,mEAAmE;IACnE,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACrD;AAED,wBAAgB,iBAAiB,CAAC,OAAO,CAAC,EAAE,wBAAwB,GAAG,gBAAgB,CA8CtF;AAED,eAAe,iBAAiB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{useCallback,useContext,useMemo}from"react";import{EventEmitterContext}from"../core/EventEmitterContext";import{MessageType}from"../hub/CommandMessage";const METHOD_DIR="methods",METHOD_EXT=".seq.json";export function sequenceTopic(e){return`datastore.methods/${e}${METHOD_EXT}`}export function emptySequence(e){return{name:e,format_version:1,steps:[]}}export function isSequenceShaped(e){return!!e&&Array.isArray(e.steps)}export function useMethodSequence(e){const t=useContext(EventEmitterContext),n=e?.invoker??((e,n,s)=>t.invoke(e,n,s)),s=useCallback(async e=>{if(!e)return null;try{const t=await n(sequenceTopic(e),MessageType.Read,{});if(!1===t?.success)return null;const s=t?.data??t;return isSequenceShaped(s)?s:null}catch{return null}},[t]),o=useCallback(async(e,t)=>{const s={...t??{},name:e};await n(sequenceTopic(e),MessageType.Write,{value:s,options:{create_dirs:!0}})},[t]),a=useCallback(async e=>{try{await n(sequenceTopic(e),MessageType.Control,{action:"delete"})}catch{}},[t]),r=useCallback(async(e,t)=>{const n=await s(e);n&&await o(t,n)},[s,o]);return useMemo(()=>({read:s,write:o,remove:a,copy:r}),[s,o,a,r])}export default useMethodSequence;
|