@adcops/autocore-react 3.3.115 → 3.3.118
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/index.d.ts +10 -2
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +1 -1
- package/dist/components/tis/CycleConfigDialog.d.ts +39 -0
- package/dist/components/tis/CycleConfigDialog.d.ts.map +1 -0
- package/dist/components/tis/CycleConfigDialog.js +1 -0
- package/dist/components/tis/CycleConfigForm.d.ts +22 -0
- package/dist/components/tis/CycleConfigForm.d.ts.map +1 -0
- package/dist/components/tis/CycleConfigForm.js +1 -0
- package/dist/components/tis/CycleStatusStrip.d.ts +10 -0
- package/dist/components/tis/CycleStatusStrip.d.ts.map +1 -0
- package/dist/components/tis/CycleStatusStrip.js +1 -0
- package/dist/components/tis/TestDataView.d.ts +4 -0
- package/dist/components/tis/TestDataView.d.ts.map +1 -1
- package/dist/components/tis/TestDataView.js +1 -1
- package/dist/components/tis/TestFieldRow.d.ts +151 -0
- package/dist/components/tis/TestFieldRow.d.ts.map +1 -0
- package/dist/components/tis/TestFieldRow.js +1 -0
- package/dist/components/tis/TestSetupForm.d.ts +15 -51
- package/dist/components/tis/TestSetupForm.d.ts.map +1 -1
- package/dist/components/tis/TestSetupForm.js +1 -1
- package/dist/components/tis/TestSetupView.d.ts.map +1 -1
- package/dist/components/tis/TestSetupView.js +1 -1
- package/dist/components/tis/TisProvider.d.ts +80 -0
- package/dist/components/tis/TisProvider.d.ts.map +1 -1
- package/dist/components/tis/TisProvider.js +1 -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/CycleConfigSection.d.ts +19 -0
- package/dist/components/tis-editor/editor/CycleConfigSection.d.ts.map +1 -0
- package/dist/components/tis-editor/editor/CycleConfigSection.js +1 -0
- package/dist/components/tis-editor/editor/FieldArrayEditor.d.ts.map +1 -1
- package/dist/components/tis-editor/editor/FieldArrayEditor.js +1 -1
- package/dist/components/tis-editor/editor/MethodFormEditor.d.ts.map +1 -1
- package/dist/components/tis-editor/editor/MethodFormEditor.js +1 -1
- package/dist/components/tis-editor/editor/TestFieldDialog.d.ts +3 -0
- package/dist/components/tis-editor/editor/TestFieldDialog.d.ts.map +1 -1
- package/dist/components/tis-editor/editor/TestFieldDialog.js +1 -1
- package/dist/components/tis-editor/editor/ViewsEditor.d.ts.map +1 -1
- package/dist/components/tis-editor/editor/ViewsEditor.js +1 -1
- package/dist/components/tis-editor/types.d.ts +28 -1
- package/dist/components/tis-editor/types.d.ts.map +1 -1
- package/dist/components/tis-editor/validation.d.ts.map +1 -1
- package/dist/components/tis-editor/validation.js +1 -1
- package/package.json +1 -1
- package/src/components/index.ts +14 -0
- package/src/components/tis/CycleConfigDialog.tsx +173 -0
- package/src/components/tis/CycleConfigForm.tsx +192 -0
- package/src/components/tis/CycleStatusStrip.tsx +84 -0
- package/src/components/tis/TestDataView.tsx +19 -3
- package/src/components/tis/TestFieldRow.tsx +297 -0
- package/src/components/tis/TestSetupForm.tsx +52 -212
- package/src/components/tis/TestSetupView.tsx +60 -3
- package/src/components/tis/TisProvider.tsx +191 -0
- package/src/components/tis-editor/TisConfigEditor.tsx +1 -0
- package/src/components/tis-editor/editor/CycleConfigSection.tsx +93 -0
- package/src/components/tis-editor/editor/FieldArrayEditor.tsx +10 -0
- package/src/components/tis-editor/editor/MethodFormEditor.tsx +38 -6
- package/src/components/tis-editor/editor/TestFieldDialog.tsx +22 -2
- package/src/components/tis-editor/editor/ViewsEditor.tsx +7 -0
- package/src/components/tis-editor/types.ts +34 -1
- package/src/components/tis-editor/validation.ts +34 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as _jsx,jsxs as _jsxs,Fragment as _Fragment}from"react/jsx-runtime";import React,{useState,useEffect,useContext,useMemo}from"react";import{Button}from"primereact/button";import{InputText}from"primereact/inputtext";import{Dropdown}from"primereact/dropdown";import{Dialog}from"primereact/dialog";import{EventEmitterContext}from"../../core/EventEmitterContext";import{AutoCoreTagContext}from"../../core/AutoCoreTagContext";import{MessageType}from"../../hub/CommandMessage";import{ValueInput}from"../ValueInput";import{TextInput}from"../TextInput";import{useTis}from"./TisProvider";import{useAmsAssets,useAmsRoles}from"../ams/AmsProvider";import{TestMethodDialog}from"./TestMethodDialog";import{ConfigurationDialog,configLabelOf}from"./ConfigurationDialog";const labelOf=e=>{const t=e.label&&e.label.length>0?e.label:e.name;return e.units?`${t} [${e.units}]`:t},rawToDisplay=(e,t)=>t&&1!==t&&"number"==typeof e&&Number.isFinite(e)?e*t:e,displayToRaw=(e,t)=>t&&1!==t&&"number"==typeof e&&Number.isFinite(e)?e/t:e,hasDescription=e=>"string"==typeof e.description&&e.description.length>0,DEFAULT_TOKEN_RE=/^\$\{\s*([^}]+?)\s*\}$/,resolveDefaultRaw=(e,t,s)=>{const i=e.default;if("string"==typeof i){const e=i.match(DEFAULT_TOKEN_RE);if(e){const i=t(e[1]),n=i?s[i.tagName]:void 0;return null==n?{raw:void 0,ok:!1}:{raw:n,ok:!0}}}return{raw:displayToRaw(i,e.scale),ok:!0}},rangeIssue=(e,t)=>{if(void 0===t||""===t||null===t)return null;if(null==e.min&&null==e.max)return null;const s=Number(rawToDisplay(Number(t),e.scale));if(!Number.isFinite(s))return null;const i=null!=e.min&&null!=e.max?Math.min(e.min,e.max):e.min,n=null!=e.min&&null!=e.max?Math.max(e.min,e.max):e.max;return null!=i&&s<i?`must be ≥ ${i}`:null!=n&&s>n?`must be ≤ ${n}`:null},normalizeOptions=e=>(e??[]).map(e=>null!==e&&"object"==typeof e?{label:String(e.label??e.value),value:e.value}:{label:String(e),value:e}),methodLabelOf=(e,t)=>t?.label&&t.label.length>0?t.label:e,AssetIdPicker=({assetType:e,value:t,onChange:s,invalid:i})=>{const n=useAmsAssets(),a=useAmsRoles(),o=useMemo(()=>n.filter(t=>t.asset_type===e&&"active"===t.status).map(e=>{const t=a[e.asset_type]?.find(t=>t.location===e.location)?.label,s=[e.asset_id];return t?s.push(`— ${t}`):e.location&&s.push(`— ${e.location}`),e.serial&&s.push(`(s/n ${e.serial})`),{label:s.join(" "),value:e.asset_id}}),[n,a,e]);return _jsx(Dropdown,{value:t,options:o,onChange:e=>s(e.value??""),placeholder:0===o.length?`No active ${e} assets registered — add one in Settings → Assets`:`Select ${e}…`,className:"ac-dropdown-clearable"+(i?" p-invalid":""),filter:!0,showClear:!0,disabled:0===o.length})};export const TestSetupForm=({schema:e,defaultMethodId:t,onMethodChange:s,onValidationChange:i})=>{const n=useTis(),{invoke:a,write:o}=useContext(EventEmitterContext),{rawValues:l,findTagByFqdn:r}=useContext(AutoCoreTagContext),c=useMemo(()=>Object.keys(n.schemas),[n.schemas]),d=n.selection.projectId,m=""!==d.trim()&&n.projectKnown(d.trim()),[u,p]=useState(n.selection.methodId||t||n.defaultMethodId||""),[f,h]=useState(n.selection.sampleId||""),g=n.stagedConfig,x=e=>{const t="function"==typeof e?e(n.stagedConfig):e;t!==n.stagedConfig&&n.setStagedConfig(t)},_=e??(u?n.schemas[u]:void 0),j=(e,t)=>{for(const[s,i]of Object.entries(e.defaults??{})){if("sample_id"===s)continue;const e=_?.config_fields.find(e=>e.name===s),n=displayToRaw(i,e?.scale);t[s]=n,e?.source&&Promise.resolve().then(()=>o(e.source,n)).catch(e=>{})}return t};useEffect(()=>{n.selection.methodId!==u&&u&&n.setSelection({methodId:u}),s&&s(u)},[u]),useEffect(()=>{n.selection.sampleId!==f&&n.setSelection({sampleId:f})},[f]),useEffect(()=>{n.state.stagedSampleId&&n.state.stagedSampleId!==f&&h(n.state.stagedSampleId)},[n.state.stagedSampleId]),useEffect(()=>{n.selection.methodId&&n.selection.methodId!==u&&p(n.selection.methodId)},[n.selection.methodId]);const[b,v]=useState(!1),[y,N]=useState(!1),[C,I]=useState(!1),T=_?.configurations??[],S=T.find(e=>e.name===n.configurationName),[w,k]=useState({open:!1,title:"",body:null});useEffect(()=>{if(!_||!u)return;if(n.defaultsAppliedForMethod===u)return;n.markDefaultsAppliedForMethod(u);const e=_.configurations&&_.configurations.length>0?_.configurations[0]:void 0;x(t=>{let s=t;for(const e of _.config_fields){if("sample_id"===e.name)continue;if(void 0===e.default||null===e.default)continue;if(e.source){const t=r(e.source),s=t?l[t.tagName]:void 0;if(null!=s)continue}const{raw:i,ok:n}=resolveDefaultRaw(e,r,l);n&&(s===t&&(s={...t}),s[e.name]=i,e.source&&Promise.resolve().then(()=>o(e.source,i)).catch(e=>{}))}return e&&(s===t&&(s={...t}),s=j(e,s)),s}),n.setConfigurationName(e?e.name:"")},[_,u,o,l,r,n.defaultsAppliedForMethod,n.markDefaultsAppliedForMethod,n.setConfigurationName]),useEffect(()=>{_&&x(e=>{let t=e;for(const s of _.config_fields){if("sample_id"===s.name)continue;if(!s.source)continue;const i=r(s.source);if(!i)continue;const n=l[i.tagName];null!=n&&(t[s.name]!==n&&(t===e&&(t={...e}),t[s.name]=n))}return t})},[_,l,r]),useEffect(()=>{if(!_)return void v(!1);let e=!0;m||(e=!1),u.trim()||(e=!1),f.trim()||(e=!1),e&&!n.projectFieldsLoaded&&(e=!1);for(const t of _.config_fields){if("sample_id"===t.name)continue;const s=g[t.name],i=void 0===s||""===s||null===s;if(t.required&&i){e=!1;break}if(rangeIssue(t,s)){e=!1;break}}if(v(e),i&&i(e,g),e){const{sample_id:e,...t}=g??{},s={...n.projectFields,...t};a("tis.stage_test",MessageType.Request,{project_id:d,method_id:u,sample_id:f,config:s}).catch(e=>{})}},[g,_,d,u,f,m,n.projectFields,n.projectFieldsLoaded,i,a]);const A=async(e,t)=>{const s=displayToRaw(t,e.scale);if(x({...g,[e.name]:s}),e.source)try{await o(e.source,s)}catch(e){}};if(!_)return _jsx("div",{className:"ac-form-grid",style:{padding:"1.25rem"},children:_jsx("h3",{className:"ac-form-section",children:n.schemasLoaded?"No Test Method Selected":"Loading test methods…"})});if(!m)return _jsxs("div",{style:{padding:"1.25rem",maxWidth:"600px"},children:[_jsx("h3",{className:"ac-form-section",children:"No project selected"}),_jsxs("p",{style:{color:"var(--text-secondary-color)",marginTop:"0.5rem"},children:["Pick a project on the ",_jsx("strong",{children:"Project"})," tab first",""!==d.trim()&&` (or click + there to create "${d.trim()}")`,"."]})]});const D={padding:"1.25rem",gridTemplateColumns:"auto 1fr 1.75rem 1.75rem"},F=b&&!n.state.lastStartError;return _jsxs("div",{className:"ac-test-setup-form",children:[_jsxs("div",{className:"ac-form-grid ac-test-setup-form__head",style:D,children:[_jsxs("h3",{className:"ac-form-section",style:{display:"flex",alignItems:"center",gap:"10px"},children:["Test Setup",_jsx(Button,{icon:F?"pi pi-check-circle":"pi pi-exclamation-circle",severity:F?"success":"danger",text:!0,rounded:!0,"aria-label":"Test Setup status",onClick:()=>{const e=(()=>{const e=[];if(m||e.push("No project is selected. Pick or create one on the Project tab."),n.projectFieldsLoaded||e.push("Project fields are still loading."),u.trim()||e.push("No test method selected."),f.trim()||e.push("Sample ID is required."),_)for(const t of _.config_fields){if("sample_id"===t.name)continue;const s=g[t.name],i=void 0===s||""===s||null===s;if(t.required&&i){e.push(`Required field "${labelOf(t)}" is empty.`);continue}const n=rangeIssue(t,s);n&&e.push(`"${labelOf(t)}" ${n}.`)}return e})(),t=n.state.lastStartError?.trim()??"";let s;s=0!==e.length||t?_jsxs("div",{children:[e.length>0&&_jsxs(_Fragment,{children:[_jsx("p",{style:{margin:"0 0 0.5rem 0"},children:"The form is incomplete:"}),_jsx("ul",{style:{margin:"0 0 1rem 1.25rem"},children:e.map((e,t)=>_jsx("li",{children:e},t))})]}),t&&_jsxs(_Fragment,{children:[_jsx("p",{style:{margin:"0 0 0.25rem 0",fontWeight:600},children:"Last start_test error from the server:"}),_jsx("pre",{style:{margin:0,padding:"0.5rem",background:"rgba(0,0,0,0.25)",borderRadius:"4px",whiteSpace:"pre-wrap",fontSize:"0.875rem"},children:t})]})]}):_jsx("p",{style:{margin:0},children:"All required fields are complete. The test is staged and ready to start."}),k({open:!0,title:"Test Setup Status",body:s})}}),_jsxs("span",{style:{fontSize:"0.85em",color:"var(--text-secondary-color)",fontWeight:"normal",marginLeft:"0.25rem"},children:["project: ",_jsx("strong",{children:d})]})]}),_jsx("span",{className:"ac-form-label",children:"Sample ID"}),_jsx(TextInput,{label:void 0,value:f,onValueChanged:e=>{h(e)},className:f.trim()?"":"p-invalid"}),_jsx("span",{"aria-hidden":"true"}),_jsx("span",{style:{color:f.trim()?"var(--green-500)":"var(--red-500)",display:"flex",alignItems:"center"},children:_jsx("i",{className:f.trim()?"pi pi-check":"pi pi-times"})}),c.length>0&&_jsxs(_Fragment,{children:[_jsx("span",{className:"ac-form-label",children:"Test Method"}),_jsxs("div",{className:"p-inputgroup",style:{flex:1},children:[_jsx(InputText,{value:methodLabelOf(u,_),readOnly:!0,style:{flex:1},tabIndex:-1}),_jsx(Button,{icon:"pi pi-folder",type:"button",onClick:()=>N(!0),tooltip:c.length>1?"Change test method":"View test method details",tooltipOptions:{position:"top"}})]}),_jsx("span",{"aria-hidden":"true"}),_jsx("span",{style:{color:u?"var(--green-500)":"var(--red-500)",display:"flex",alignItems:"center"},children:_jsx("i",{className:u?"pi pi-check":"pi pi-times"})})]}),T.length>0&&_jsxs(_Fragment,{children:[_jsx("span",{className:"ac-form-label",children:"Configuration"}),_jsxs("div",{className:"p-inputgroup",style:{flex:1},children:[_jsx(InputText,{value:S?configLabelOf(S):"",placeholder:"No configuration selected",readOnly:!0,style:{flex:1},tabIndex:-1}),_jsx(Button,{icon:"pi pi-folder",type:"button",onClick:()=>I(!0),tooltip:"Change configuration",tooltipOptions:{position:"top"}})]}),_jsx("span",{"aria-hidden":"true"}),_jsx("span",{style:{color:S?"var(--green-500)":"var(--text-secondary-color)",display:"flex",alignItems:"center"},children:_jsx("i",{className:S?"pi pi-check":"pi pi-minus"})})]})]}),_jsx("div",{className:"ac-test-setup-form__body",children:_jsxs("div",{className:"ac-form-grid",style:D,children:[_jsx("h3",{className:"ac-form-section",children:"Test Configuration"}),_.config_fields.map(e=>{if("sample_id"===e.name)return null;const t=(e=>{const t=g[e.name],s=void 0===t||""===t||null===t;return!(e.required&&s||rangeIssue(e,t))})(e),s=(e=>{const t=_?.asset_refs??[],s=n.projectAssetRefs??[],i=`config.${e.name}`,a=t.find(e=>"by_id_field"===e.select&&e.from===i);if(a)return a.asset_type;const o=s.find(e=>"by_id_field"===e.select&&e.from===i);return o?o.asset_type:null})(e),i=!s&&Array.isArray(e.options)&&e.options.length>0?normalizeOptions(e.options):null,a=!s&&!i&&"string"!==e.type&&"bool"!==e.type;return _jsxs(React.Fragment,{children:[_jsx("span",{className:"ac-form-label",children:labelOf(e)}),s?_jsx(AssetIdPicker,{assetType:s,value:null!=g[e.name]?String(g[e.name]):"",onChange:t=>A(e,t),invalid:!t}):i?_jsx(Dropdown,{value:g[e.name]??null,options:i,onChange:t=>A(e,t.value),placeholder:`Select ${e.label??e.name}…`,className:"ac-dropdown-clearable"+(t?"":" p-invalid"),showClear:!e.required}):a?_jsx(ValueInput,{label:void 0,value:null!=g[e.name]?Number(rawToDisplay(Number(g[e.name]),e.scale)):null,min:e.min,max:e.max,onValueChanged:t=>A(e,t),className:t?"":"p-invalid"}):_jsx(TextInput,{label:void 0,value:null!=g[e.name]?String(g[e.name]):"",onValueChanged:t=>A(e,t),className:t?"":"p-invalid"}),hasDescription(e)?_jsx(Button,{icon:"pi pi-info-circle",text:!0,rounded:!0,"aria-label":`About ${labelOf(e)}`,onClick:()=>k({open:!0,title:labelOf(e),body:_jsx("p",{style:{margin:0,whiteSpace:"pre-wrap"},children:e.description})})}):_jsx("span",{"aria-hidden":"true"}),_jsx("span",{style:{color:t?"var(--green-500)":"var(--red-500)",display:"flex",alignItems:"center"},children:_jsx("i",{className:t?"pi pi-check":"pi pi-times"})})]},e.name)})]})}),_jsx(TestMethodDialog,{visible:y,onHide:()=>N(!1),currentMethodId:u,onSelected:e=>p(e)}),_jsx(ConfigurationDialog,{visible:C,onHide:()=>I(!1),configurations:T,currentConfigName:n.configurationName,onSelected:e=>{const t=T.find(t=>t.name===e);t&&(x(e=>j(t,{...e})),n.setConfigurationName(e))}}),_jsx(Dialog,{header:w.title,visible:w.open,onHide:()=>k({open:!1,title:"",body:null}),style:{width:"32rem",maxWidth:"90vw"},modal:!0,dismissableMask:!0,children:w.body})]})};
|
|
1
|
+
import{jsx as _jsx,jsxs as _jsxs,Fragment as _Fragment}from"react/jsx-runtime";import React,{useState,useEffect,useContext,useMemo}from"react";import{Button}from"primereact/button";import{InputText}from"primereact/inputtext";import{Dropdown}from"primereact/dropdown";import{Dialog}from"primereact/dialog";import{EventEmitterContext}from"../../core/EventEmitterContext";import{AutoCoreTagContext}from"../../core/AutoCoreTagContext";import{MessageType}from"../../hub/CommandMessage";import{TextInput}from"../TextInput";import{useTis}from"./TisProvider";import{useAmsAssets,useAmsRoles}from"../ams/AmsProvider";import{TestMethodDialog}from"./TestMethodDialog";import{ConfigurationDialog,configLabelOf}from"./ConfigurationDialog";import{TestFieldRow,displayToRaw,fieldIsValid,fieldIssue,labelOf}from"./TestFieldRow";const DEFAULT_TOKEN_RE=/^\$\{\s*([^}]+?)\s*\}$/,resolveDefaultRaw=(e,t,s)=>{const o=e.default;if("string"==typeof o){const e=o.match(DEFAULT_TOKEN_RE);if(e){const o=t(e[1]),i=o?s[o.tagName]:void 0;return null==i?{raw:void 0,ok:!1}:{raw:i,ok:!0}}}return{raw:displayToRaw(o,e.scale),ok:!0}},methodLabelOf=(e,t)=>t?.label&&t.label.length>0?t.label:e,AssetIdPicker=({assetType:e,value:t,onChange:s,invalid:o})=>{const i=useAmsAssets(),a=useAmsRoles(),n=useMemo(()=>i.filter(t=>t.asset_type===e&&"active"===t.status).map(e=>{const t=a[e.asset_type]?.find(t=>t.location===e.location)?.label,s=[e.asset_id];return t?s.push(`— ${t}`):e.location&&s.push(`— ${e.location}`),e.serial&&s.push(`(s/n ${e.serial})`),{label:s.join(" "),value:e.asset_id}}),[i,a,e]);return _jsx(Dropdown,{value:t,options:n,onChange:e=>s(e.value??""),placeholder:0===n.length?`No active ${e} assets registered — add one in Settings → Assets`:`Select ${e}…`,className:"ac-dropdown-clearable"+(o?" p-invalid":""),filter:!0,showClear:!0,disabled:0===n.length})};export const TestSetupForm=({schema:e,defaultMethodId:t,onMethodChange:s,onValidationChange:o})=>{const i=useTis(),{invoke:a,write:n}=useContext(EventEmitterContext),{rawValues:r,findTagByFqdn:l}=useContext(AutoCoreTagContext),c=useMemo(()=>Object.keys(i.schemas),[i.schemas]),d=i.selection.projectId,m=""!==d.trim()&&i.projectKnown(d.trim()),[p,f]=useState(i.selection.methodId||t||i.defaultMethodId||""),[u,h]=useState(i.selection.sampleId||""),g=i.stagedConfig,_=e=>{const t="function"==typeof e?e(i.stagedConfig):e;t!==i.stagedConfig&&i.setStagedConfig(t)},x=e??(p?i.schemas[p]:void 0),j=(e,t)=>{for(const[s,o]of Object.entries(e.defaults??{})){if("sample_id"===s)continue;const e=x?.config_fields.find(e=>e.name===s),i=displayToRaw(o,e?.scale);t[s]=i,e?.source&&Promise.resolve().then(()=>n(e.source,i)).catch(e=>{})}return t};useEffect(()=>{i.selection.methodId!==p&&p&&i.setSelection({methodId:p}),s&&s(p)},[p]),useEffect(()=>{i.selection.sampleId!==u&&i.setSelection({sampleId:u})},[u]),useEffect(()=>{i.state.stagedSampleId&&i.state.stagedSampleId!==u&&h(i.state.stagedSampleId)},[i.state.stagedSampleId]),useEffect(()=>{i.selection.methodId&&i.selection.methodId!==p&&f(i.selection.methodId)},[i.selection.methodId]);const[y,v]=useState(!1),[b,T]=useState(!1),[C,I]=useState(!1),N=x?.configurations??[],S=N.find(e=>e.name===i.configurationName),[w,k]=useState({open:!1,title:"",body:null});useEffect(()=>{if(!x||!p)return;if(i.defaultsAppliedForMethod===p)return;i.markDefaultsAppliedForMethod(p);const e=x.configurations&&x.configurations.length>0?x.configurations[0]:void 0;_(t=>{let s=t;for(const e of x.config_fields){if("sample_id"===e.name)continue;if(void 0===e.default||null===e.default)continue;if(e.source){const t=l(e.source),s=t?r[t.tagName]:void 0;if(null!=s)continue}const{raw:o,ok:i}=resolveDefaultRaw(e,l,r);i&&(s===t&&(s={...t}),s[e.name]=o,e.source&&Promise.resolve().then(()=>n(e.source,o)).catch(e=>{}))}return e&&(s===t&&(s={...t}),s=j(e,s)),s}),i.setConfigurationName(e?e.name:"")},[x,p,n,r,l,i.defaultsAppliedForMethod,i.markDefaultsAppliedForMethod,i.setConfigurationName]),useEffect(()=>{x&&_(e=>{let t=e;for(const s of x.config_fields){if("sample_id"===s.name)continue;if(!s.source)continue;const o=l(s.source);if(!o)continue;const i=r[o.tagName];null!=i&&(t[s.name]!==i&&(t===e&&(t={...e}),t[s.name]=i))}return t})},[x,r,l]),useEffect(()=>{if(!x)return void v(!1);let e=!0;m||(e=!1),p.trim()||(e=!1),u.trim()||(e=!1),e&&!i.projectFieldsLoaded&&(e=!1);for(const t of x.config_fields)if("sample_id"!==t.name&&fieldIssue(t,g[t.name])){e=!1;break}if(v(e),o&&o(e,g),e){const{sample_id:e,...t}=g??{},s={...i.projectFields,...t};a("tis.stage_test",MessageType.Request,{project_id:d,method_id:p,sample_id:u,config:s}).catch(e=>{})}},[g,x,d,p,u,m,i.projectFields,i.projectFieldsLoaded,o,a]);const E=async(e,t)=>{if(_({...g,[e.name]:t}),e.source)try{await n(e.source,t)}catch(e){}};if(!x)return _jsx("div",{className:"ac-form-grid",style:{padding:"1.25rem"},children:_jsx("h3",{className:"ac-form-section",children:i.schemasLoaded?"No Test Method Selected":"Loading test methods…"})});if(!m)return _jsxs("div",{style:{padding:"1.25rem",maxWidth:"600px"},children:[_jsx("h3",{className:"ac-form-section",children:"No project selected"}),_jsxs("p",{style:{color:"var(--text-secondary-color)",marginTop:"0.5rem"},children:["Pick a project on the ",_jsx("strong",{children:"Project"})," tab first",""!==d.trim()&&` (or click + there to create "${d.trim()}")`,"."]})]});const F={padding:"1.25rem",gridTemplateColumns:"auto 1fr 1.75rem 1.75rem"},A=y&&!i.state.lastStartError;return _jsxs("div",{className:"ac-test-setup-form",children:[_jsxs("div",{className:"ac-form-grid ac-test-setup-form__head",style:F,children:[_jsxs("h3",{className:"ac-form-section",style:{display:"flex",alignItems:"center",gap:"10px"},children:["Test Setup",_jsx(Button,{icon:A?"pi pi-check-circle":"pi pi-exclamation-circle",severity:A?"success":"danger",text:!0,rounded:!0,"aria-label":"Test Setup status",onClick:()=>{const e=(()=>{const e=[];if(m||e.push("No project is selected. Pick or create one on the Project tab."),i.projectFieldsLoaded||e.push("Project fields are still loading."),p.trim()||e.push("No test method selected."),u.trim()||e.push("Sample ID is required."),x)for(const t of x.config_fields){if("sample_id"===t.name)continue;const s=fieldIssue(t,g[t.name]);s&&e.push(`"${labelOf(t)}" ${s}.`)}return e})(),t=i.state.lastStartError?.trim()??"";let s;s=0!==e.length||t?_jsxs("div",{children:[e.length>0&&_jsxs(_Fragment,{children:[_jsx("p",{style:{margin:"0 0 0.5rem 0"},children:"The form is incomplete:"}),_jsx("ul",{style:{margin:"0 0 1rem 1.25rem"},children:e.map((e,t)=>_jsx("li",{children:e},t))})]}),t&&_jsxs(_Fragment,{children:[_jsx("p",{style:{margin:"0 0 0.25rem 0",fontWeight:600},children:"Last start_test error from the server:"}),_jsx("pre",{style:{margin:0,padding:"0.5rem",background:"rgba(0,0,0,0.25)",borderRadius:"4px",whiteSpace:"pre-wrap",fontSize:"0.875rem"},children:t})]})]}):_jsx("p",{style:{margin:0},children:"All required fields are complete. The test is staged and ready to start."}),k({open:!0,title:"Test Setup Status",body:s})}}),_jsxs("span",{style:{fontSize:"0.85em",color:"var(--text-secondary-color)",fontWeight:"normal",marginLeft:"0.25rem"},children:["project: ",_jsx("strong",{children:d})]})]}),_jsx("span",{className:"ac-form-label",children:"Sample ID"}),_jsx(TextInput,{label:void 0,value:u,onValueChanged:e=>{h(e)},className:u.trim()?"":"p-invalid"}),_jsx("span",{"aria-hidden":"true"}),_jsx("span",{style:{color:u.trim()?"var(--green-500)":"var(--red-500)",display:"flex",alignItems:"center"},children:_jsx("i",{className:u.trim()?"pi pi-check":"pi pi-times"})}),c.length>0&&_jsxs(_Fragment,{children:[_jsx("span",{className:"ac-form-label",children:"Test Method"}),_jsxs("div",{className:"p-inputgroup",style:{flex:1},children:[_jsx(InputText,{value:methodLabelOf(p,x),readOnly:!0,style:{flex:1},tabIndex:-1}),_jsx(Button,{icon:"pi pi-folder",type:"button",onClick:()=>T(!0),tooltip:c.length>1?"Change test method":"View test method details",tooltipOptions:{position:"top"}})]}),_jsx("span",{"aria-hidden":"true"}),_jsx("span",{style:{color:p?"var(--green-500)":"var(--red-500)",display:"flex",alignItems:"center"},children:_jsx("i",{className:p?"pi pi-check":"pi pi-times"})})]}),N.length>0&&_jsxs(_Fragment,{children:[_jsx("span",{className:"ac-form-label",children:"Configuration"}),_jsxs("div",{className:"p-inputgroup",style:{flex:1},children:[_jsx(InputText,{value:S?configLabelOf(S):"",placeholder:"No configuration selected",readOnly:!0,style:{flex:1},tabIndex:-1}),_jsx(Button,{icon:"pi pi-folder",type:"button",onClick:()=>I(!0),tooltip:"Change configuration",tooltipOptions:{position:"top"}})]}),_jsx("span",{"aria-hidden":"true"}),_jsx("span",{style:{color:S?"var(--green-500)":"var(--text-secondary-color)",display:"flex",alignItems:"center"},children:_jsx("i",{className:S?"pi pi-check":"pi pi-minus"})})]})]}),_jsx("div",{className:"ac-test-setup-form__body",children:_jsxs("div",{className:"ac-form-grid",style:F,children:[_jsx("h3",{className:"ac-form-section",children:"Test Configuration"}),x.config_fields.map(e=>{if("sample_id"===e.name)return null;const t=(e=>fieldIsValid(e,g[e.name]))(e),s=(e=>{const t=x?.asset_refs??[],s=i.projectAssetRefs??[],o=`config.${e.name}`,a=t.find(e=>"by_id_field"===e.select&&e.from===o);if(a)return a.asset_type;const n=s.find(e=>"by_id_field"===e.select&&e.from===o);return n?n.asset_type:null})(e);return _jsx(TestFieldRow,{field:e,value:g[e.name],valid:t,onChange:t=>E(e,t),onInfo:e=>k({open:!0,title:labelOf(e),body:_jsx("p",{style:{margin:0,whiteSpace:"pre-wrap"},children:e.description})}),control:s?_jsx(AssetIdPicker,{assetType:s,value:null!=g[e.name]?String(g[e.name]):"",onChange:t=>E(e,t),invalid:!t}):void 0},e.name)})]})}),_jsx(TestMethodDialog,{visible:b,onHide:()=>T(!1),currentMethodId:p,onSelected:e=>f(e)}),_jsx(ConfigurationDialog,{visible:C,onHide:()=>I(!1),configurations:N,currentConfigName:i.configurationName,onSelected:e=>{const t=N.find(t=>t.name===e);t&&(_(e=>j(t,{...e})),i.setConfigurationName(e))}}),_jsx(Dialog,{header:w.title,visible:w.open,onHide:()=>k({open:!1,title:"",body:null}),style:{width:"32rem",maxWidth:"90vw"},modal:!0,dismissableMask:!0,children:w.body})]})};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TestSetupView.d.ts","sourceRoot":"","sources":["../../../src/components/tis/TestSetupView.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"TestSetupView.d.ts","sourceRoot":"","sources":["../../../src/components/tis/TestSetupView.tsx"],"names":[],"mappings":"AAkCA,OAAO,KAAsC,MAAM,OAAO,CAAC;AAQ3D,MAAM,WAAW,kBAAkB;IAC/B,qDAAqD;IACrD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iDAAiD;IACjD,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;CAC/B;AAED,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CA+EtD,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import React
|
|
1
|
+
import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import React,{useEffect,useRef,useState}from"react";import{TabView,TabPanel}from"primereact/tabview";import{ProjectSelector}from"./ProjectSelector";import{ResultHistoryTable}from"./ResultHistoryTable";import{TestSetupForm}from"./TestSetupForm";import{CycleConfigForm}from"./CycleConfigForm";import{useTis}from"./TisProvider";export const TestSetupView=({className:e,style:s})=>{const t=e?`ac-test-setup-view ${e}`:"ac-test-setup-view",a=useTis(),r=a.cycleConfigFields.length>0,i=r&&!a.cycleConfig.ready,[c,l]=useState(0),o=useRef(!1);return useEffect(()=>{a.state.active&&!o.current&&r&&l(2),o.current=a.state.active},[a.state.active,r]),_jsx("div",{className:t,style:s,children:_jsxs(TabView,{activeIndex:c,onTabChange:e=>l(e.index),children:[_jsx(TabPanel,{header:"Project",children:_jsxs("div",{className:"ac-test-setup-view__tab",children:[_jsx("div",{className:"ac-test-setup-view__fixed",children:_jsx(ProjectSelector,{})}),_jsx("div",{className:"ac-test-setup-view__scroll",children:_jsx(ResultHistoryTable,{})})]})}),_jsx(TabPanel,{header:"Test",children:_jsx(TestSetupForm,{})}),r&&_jsx(TabPanel,{header:_jsxs("span",{style:{display:"inline-flex",alignItems:"center",gap:"0.4rem"},children:["Cycle",i&&_jsx("i",{className:"pi pi-exclamation-circle",style:{color:"var(--red-500)"},"aria-label":"Cycle Configuration incomplete"})]}),children:_jsx("div",{className:"ac-test-setup-view__tab",children:_jsx("div",{className:"ac-test-setup-view__scroll",children:_jsx(CycleConfigForm,{})})})})]})})};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React, { type ReactNode } from 'react';
|
|
2
|
+
import type { CycleConfigScope, TestFieldDef } from './TestFieldRow';
|
|
2
3
|
/**
|
|
3
4
|
* One slot in the schema registry. Kept as an opaque object so the
|
|
4
5
|
* provider doesn't have to mirror every schema field — components that
|
|
@@ -30,6 +31,36 @@ export interface TisLiveState {
|
|
|
30
31
|
*/
|
|
31
32
|
lastStartError: string;
|
|
32
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* Live Cycle Configuration state for the selected (project, method) —
|
|
36
|
+
* the operator's per-row annotation. Mirrors the server's
|
|
37
|
+
* `tis.cycle_config` payload one-for-one; the server owns every rule
|
|
38
|
+
* (which boundary latches, when autoclear fires, whether the gate is
|
|
39
|
+
* satisfied) so the HMI never has to re-derive them and can never
|
|
40
|
+
* disagree with the `tis.cycle_ready` scalar the machine gates on.
|
|
41
|
+
*/
|
|
42
|
+
export interface TisCycleConfigState {
|
|
43
|
+
projectId: string;
|
|
44
|
+
methodId: string;
|
|
45
|
+
/** `'run'` = one latch per Start; `'cycle'` = one per cycle. */
|
|
46
|
+
scope: CycleConfigScope;
|
|
47
|
+
/** Method asks for the entry dialog at each boundary. */
|
|
48
|
+
promptBeforeCycle: boolean;
|
|
49
|
+
/** What the operator has entered but no row has consumed yet (RAW). */
|
|
50
|
+
values: Record<string, any>;
|
|
51
|
+
/** The snapshot the cycle now running will be stamped with, or null
|
|
52
|
+
* when nothing is latched. Non-null means the fields are locked for
|
|
53
|
+
* the row in flight — editing them targets the *next* row. */
|
|
54
|
+
latched: Record<string, any> | null;
|
|
55
|
+
/** False while any `required` field is empty. The same condition
|
|
56
|
+
* drives `tis.cycle_ready`, which gates the machine. */
|
|
57
|
+
ready: boolean;
|
|
58
|
+
/** Names of the required-but-empty fields, in declared order. */
|
|
59
|
+
missing: string[];
|
|
60
|
+
/** A `prompt_before_cycle` method has reached a boundary with nothing
|
|
61
|
+
* latched — the edge on which <CycleConfigDialog> opens. */
|
|
62
|
+
promptDue: boolean;
|
|
63
|
+
}
|
|
33
64
|
export interface TisSelection {
|
|
34
65
|
projectId: string;
|
|
35
66
|
methodId: string;
|
|
@@ -151,6 +182,23 @@ export interface TisContextValue {
|
|
|
151
182
|
* seeding effect auto-applies the first configuration and when the
|
|
152
183
|
* operator accepts a different one in the picker dialog. */
|
|
153
184
|
setConfigurationName: (name: string) => void;
|
|
185
|
+
/** Live state for the selected method. Server-owned; every mutation
|
|
186
|
+
* round-trips so the HMI and the `tis.cycle_ready` gate agree. */
|
|
187
|
+
cycleConfig: TisCycleConfigState;
|
|
188
|
+
/** The selected method's `cycle_config_fields`, in declared order.
|
|
189
|
+
* Empty when the method doesn't use the feature — which is the
|
|
190
|
+
* signal to hide the Cycle tab entirely. */
|
|
191
|
+
cycleConfigFields: TestFieldDef[];
|
|
192
|
+
/** Merge a sparse patch of RAW values into the operator's pending
|
|
193
|
+
* entry. An explicit null/'' clears a field. Resolves once the
|
|
194
|
+
* server has applied it and the state has been refreshed. */
|
|
195
|
+
setCycleConfigValues: (patch: Record<string, any>) => Promise<void>;
|
|
196
|
+
/** Wipe every pending value regardless of `autoclear`. Leaves the
|
|
197
|
+
* latch alone — a cycle already running keeps its label. */
|
|
198
|
+
clearCycleConfig: () => Promise<void>;
|
|
199
|
+
/** Re-read Cycle Configuration state from the server. Called on
|
|
200
|
+
* selection change; broadcasts keep it fresh after that. */
|
|
201
|
+
refreshCycleConfig: () => Promise<void>;
|
|
154
202
|
/** Fetch the run list for a (project, method?) pair. Method may be
|
|
155
203
|
* omitted to aggregate runs across every method in the project —
|
|
156
204
|
* the History tab uses this. */
|
|
@@ -176,6 +224,38 @@ export declare const TisProvider: React.FC<TisProviderProps>;
|
|
|
176
224
|
export declare const useTis: () => TisContextValue;
|
|
177
225
|
export declare const useTisSchemas: () => SchemaRegistry;
|
|
178
226
|
export declare const useTisState: () => TisLiveState;
|
|
227
|
+
/**
|
|
228
|
+
* Cycle Configuration for the selected method: the live state, the field
|
|
229
|
+
* declarations, and the two mutators.
|
|
230
|
+
*
|
|
231
|
+
* `fields.length === 0` means the method doesn't use per-row annotation —
|
|
232
|
+
* hide the Cycle tab and the status strip rather than showing an empty one.
|
|
233
|
+
*/
|
|
234
|
+
export declare const useTisCycleConfig: () => {
|
|
235
|
+
fields: TestFieldDef[];
|
|
236
|
+
setValues: (patch: Record<string, any>) => Promise<void>;
|
|
237
|
+
clear: () => Promise<void>;
|
|
238
|
+
projectId: string;
|
|
239
|
+
methodId: string;
|
|
240
|
+
/** `'run'` = one latch per Start; `'cycle'` = one per cycle. */
|
|
241
|
+
scope: CycleConfigScope;
|
|
242
|
+
/** Method asks for the entry dialog at each boundary. */
|
|
243
|
+
promptBeforeCycle: boolean;
|
|
244
|
+
/** What the operator has entered but no row has consumed yet (RAW). */
|
|
245
|
+
values: Record<string, any>;
|
|
246
|
+
/** The snapshot the cycle now running will be stamped with, or null
|
|
247
|
+
* when nothing is latched. Non-null means the fields are locked for
|
|
248
|
+
* the row in flight — editing them targets the *next* row. */
|
|
249
|
+
latched: Record<string, any> | null;
|
|
250
|
+
/** False while any `required` field is empty. The same condition
|
|
251
|
+
* drives `tis.cycle_ready`, which gates the machine. */
|
|
252
|
+
ready: boolean;
|
|
253
|
+
/** Names of the required-but-empty fields, in declared order. */
|
|
254
|
+
missing: string[];
|
|
255
|
+
/** A `prompt_before_cycle` method has reached a boundary with nothing
|
|
256
|
+
* latched — the edge on which <CycleConfigDialog> opens. */
|
|
257
|
+
promptDue: boolean;
|
|
258
|
+
};
|
|
179
259
|
/**
|
|
180
260
|
* Tuple of `[selection, setSelection]`.
|
|
181
261
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TisProvider.d.ts","sourceRoot":"","sources":["../../../src/components/tis/TisProvider.tsx"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,EASV,KAAK,SAAS,EACjB,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"TisProvider.d.ts","sourceRoot":"","sources":["../../../src/components/tis/TisProvider.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as _jsx}from"react/jsx-runtime";import React,{createContext,useCallback,useContext,useEffect,useMemo,useReducer,useRef,useState}from"react";import{EventEmitterContext}from"../../core/EventEmitterContext";import{MessageType}from"../../hub/CommandMessage";const EMPTY_STATE={staged:!1,stagedProjectId:"",stagedMethodId:"",stagedSampleId:"",active:!1,activeProjectId:"",activeMethodId:"",activeSampleId:"",activeRunId:"",lastStartError:""},EMPTY_SELECTION={projectId:"",methodId:"",sampleId:"",runId:""},TisContext=createContext({schemas:{},projectAssetRefs:[],defaultMethodId:"",schemasLoaded:!1,state:EMPTY_STATE,selection:EMPTY_SELECTION,setSelection:()=>{},existingProjects:[],projectKnown:()=>!1,refreshProjects:async()=>{},markProjectJustCreated:()=>{},projectFields:{},projectFieldsLoaded:!1,loadProjectFields:async()=>null,setProjectFields:()=>{},stagedConfig:{},setStagedConfig:()=>{},clearStagedConfig:()=>{},defaultsAppliedForMethod:"",markDefaultsAppliedForMethod:()=>{},configurationName:"",setConfigurationName:()=>{},fetchRuns:async()=>[],fetchRun:async()=>null,runCache:{}});function liveReducer(e,t){switch(t.kind){case"staged":return{...e,staged:t.value};case"staged_project_id":return{...e,stagedProjectId:t.value};case"staged_method_id":return{...e,stagedMethodId:t.value};case"staged_sample_id":return{...e,stagedSampleId:t.value};case"active":return{...e,active:t.value};case"active_project_id":return{...e,activeProjectId:t.value};case"active_method_id":return{...e,activeMethodId:t.value};case"active_sample_id":return{...e,activeSampleId:t.value};case"active_run_id":return{...e,activeRunId:t.value};case"last_start_error":return{...e,lastStartError:t.value}}}export const TisProvider=({children:e,defaultMethodId:t})=>{const{invoke:s,subscribe:a,unsubscribe:r}=useContext(EventEmitterContext),[c,d]=useState({}),[n,u]=useState([]),[o,i]=useState(t??""),[l,p]=useState(!1),[_,f]=useReducer(liveReducer,EMPTY_STATE),[m,I]=useState({projectId:null,methodId:null,sampleId:null,runId:null});useEffect(()=>{let e=!1;return(async()=>{try{const a=await s("tis.list_schemas",MessageType.Request,{});if(e)return;if(a?.success&&a.data){const e=a.data.test_methods??{},s=a.data.default_method_id??"",r=Array.isArray(a.data.asset_refs)?a.data.asset_refs:[];d(e),u(r),!t&&s&&i(s),p(!0)}}catch(e){}})(),()=>{e=!0}},[]),useEffect(()=>{let e=!1;return(async()=>{try{const t=await s("gnv.ux.selected_project_id",MessageType.Read,{});if(e)return;const a=t?.success?t.data??"":"";"string"==typeof a&&a.length>0&&I(e=>null===e.projectId?{...e,projectId:a}:e)}catch{}})(),()=>{e=!0}},[]),useEffect(()=>{const e=[a("tis.staged",e=>f({kind:"staged",value:!!e})),a("tis.staged_project_id",e=>f({kind:"staged_project_id",value:String(e??"")})),a("tis.staged_method_id",e=>f({kind:"staged_method_id",value:String(e??"")})),a("tis.staged_sample_id",e=>f({kind:"staged_sample_id",value:String(e??"")})),a("tis.active",e=>f({kind:"active",value:!!e})),a("tis.active_project_id",e=>f({kind:"active_project_id",value:String(e??"")})),a("tis.active_method_id",e=>f({kind:"active_method_id",value:String(e??"")})),a("tis.active_sample_id",e=>f({kind:"active_sample_id",value:String(e??"")})),a("tis.active_run_id",e=>f({kind:"active_run_id",value:String(e??"")})),a("tis.last_start_error",e=>f({kind:"last_start_error",value:String(e??"")}))];return()=>{e.forEach(r)}},[a,r]);const v=useRef({}),[h,j]=useState(0),g=useCallback(()=>j(e=>e+1),[]),C=useCallback((e,t)=>{if(!e)return;const s=v.current[e]??{meta:null,cycles:[],results:{},rawData:{}};v.current[e]={...s,cycles:[...s.cycles,t]},g()},[g]),S=useCallback((e,t)=>{if(!e)return;const s=v.current[e]??{meta:null,cycles:[],results:{},rawData:{}};v.current[e]={...s,results:t},g()},[g]);useEffect(()=>{const e=a("tis.cycle_added",e=>{e?.run_id&&e.cycle&&C(e.run_id,e.cycle)}),t=a("tis.results_updated",e=>{e?.run_id&&S(e.run_id,e.results??{})});return()=>{r(e),r(t)}},[a,r,C,S]);const y=useMemo(()=>({projectId:m.projectId??_.activeProjectId,methodId:m.methodId??(_.activeMethodId||o),sampleId:m.sampleId??_.activeSampleId,runId:m.runId??_.activeRunId}),[m,_,o]),x=useCallback(e=>{I(t=>({projectId:void 0===e.projectId?t.projectId:e.projectId,methodId:void 0===e.methodId?t.methodId:e.methodId,sampleId:void 0===e.sampleId?t.sampleId:e.sampleId,runId:void 0===e.runId?t.runId:e.runId})),void 0!==e.projectId&&s("gnv.ux.selected_project_id",MessageType.Write,e.projectId??"").catch(e=>{})},[s]),T=useRef("");useEffect(()=>{const e=_.activeRunId;e&&e!==T.current&&(T.current=e,I({projectId:null,methodId:null,sampleId:null,runId:null}))},[_.activeRunId]);const k=useCallback(async(e,t)=>{if(!e)return[];const a={project_id:e};t&&(a.method_id=t);try{const e=await s("tis.list_tests",MessageType.Request,a);if(e?.success&&e.data?.tests)return e.data.tests}catch(e){}return[]},[s]),E=useCallback(async(e,t,a)=>{if(!e||!t||!a)return null;try{const r=await s("tis.read_test",MessageType.Request,{project_id:e,method_id:t,run_id:a}),c=await s("tis.read_cycles",MessageType.Request,{project_id:e,method_id:t,run_id:a,offset:0,limit:1e3,order:"asc"});if(!r?.success)return null;const d={meta:r.data??null,cycles:c?.success?c.data?.cycles??[]:[],results:r.data?.results??{},rawData:v.current[a]?.rawData??{}};return v.current[a]=d,g(),d}catch(e){return null}},[s,g]),M=useMemo(()=>({...v.current}),[h]),[R,P]=useState([]),b=useRef(new Set),[w,F]=useState(0),[A,D]=useState({}),q=useCallback(async()=>{try{const e=await s("tis.list_projects",MessageType.Request,{});e?.success&&e.data?.projects&&P(e.data.projects)}catch(e){}},[s]),L=useCallback(e=>{e&&(b.current.has(e)||(b.current.add(e),F(e=>e+1)))},[]),N=useCallback(e=>!!e&&(!!b.current.has(e)||R.includes(e)),[R,w]),Y=useCallback((e,t)=>{e&&D(s=>({...s,[e]:t}))},[]),J=useCallback(async e=>{if(!e)return null;try{const t=await s("tis.read_project",MessageType.Request,{project_id:e});if(t?.success){const s=t.data?.project_fields??{};return D(t=>({...t,[e]:s})),s}}catch(e){}return D(t=>({...t,[e]:{}})),{}},[s]);useEffect(()=>{q()},[q]),useEffect(()=>{const e=a("tis.project_created",()=>{q()}),t=a("tis.project_updated",e=>{const t="string"==typeof e?.project_id?e.project_id:"";t&&J(t)});return()=>{r(e),r(t)}},[a,r,q,J]),useEffect(()=>{const e=y.projectId;e&&N(e)&&void 0===A[e]&&J(e)},[y.projectId,N,A,J]);const K=A[y.projectId]??{},O=void 0!==A[y.projectId],[W,z]=useState({}),B=useCallback(e=>{z(t=>({...t,...e}))},[]),[G,H]=useState(""),Q=useCallback(e=>{H(e)},[]),[U,V]=useState(""),X=useCallback(()=>{z({}),H(""),V("")},[]),Z=useMemo(()=>({schemas:c,projectAssetRefs:n,defaultMethodId:o,schemasLoaded:l,state:_,selection:y,setSelection:x,existingProjects:R,projectKnown:N,refreshProjects:q,markProjectJustCreated:L,projectFields:K,projectFieldsLoaded:O,loadProjectFields:J,setProjectFields:Y,stagedConfig:W,setStagedConfig:B,clearStagedConfig:X,defaultsAppliedForMethod:G,markDefaultsAppliedForMethod:Q,configurationName:U,setConfigurationName:V,fetchRuns:k,fetchRun:E,runCache:M}),[c,n,o,l,_,y,x,R,N,q,L,K,O,J,Y,W,B,X,G,Q,U,V,k,E,M]);return _jsx(TisContext.Provider,{value:Z,children:e})};export const useTis=()=>useContext(TisContext);export const useTisSchemas=()=>useContext(TisContext).schemas;export const useTisState=()=>useContext(TisContext).state;export const useTisSelection=()=>{const{selection:e,setSelection:t}=useContext(TisContext);return[e,t]};export const useTisRuns=(e,t)=>{const{fetchRuns:s}=useContext(TisContext),[a,r]=useState([]),[c,d]=useState(!1),n=useCallback(async()=>{if(e){d(!0);try{r(await s(e,t))}finally{d(!1)}}else r([])},[e,t,s]);return useEffect(()=>{n()},[n]),{runs:a,loading:c,refresh:n}};export const useTisRun=e=>{const{selection:t,fetchRun:s,runCache:a}=useContext(TisContext),[r,c]=useState(!1),d=e??t.runId;useEffect(()=>{if(!d)return;if(a[d]?.meta)return;const e=t.projectId,r=t.methodId;e&&r&&(c(!0),s(e,r,d).finally(()=>c(!1)))},[d,t.projectId,t.methodId,s,a]);const n=d?a[d]:null;return{meta:n?.meta??null,cycles:n?.cycles??[],results:n?.results??{},rawData:n?.rawData??{},loading:r}};export{TisContext};
|
|
1
|
+
import{jsx as _jsx}from"react/jsx-runtime";import React,{createContext,useCallback,useContext,useEffect,useMemo,useReducer,useRef,useState}from"react";import{EventEmitterContext}from"../../core/EventEmitterContext";import{MessageType}from"../../hub/CommandMessage";const EMPTY_STATE={staged:!1,stagedProjectId:"",stagedMethodId:"",stagedSampleId:"",active:!1,activeProjectId:"",activeMethodId:"",activeSampleId:"",activeRunId:"",lastStartError:""},EMPTY_SELECTION={projectId:"",methodId:"",sampleId:"",runId:""},EMPTY_CYCLE_CONFIG={projectId:"",methodId:"",scope:"run",promptBeforeCycle:!1,values:{},latched:null,ready:!0,missing:[],promptDue:!1},cycleConfigFromPayload=e=>({projectId:String(e?.project_id??""),methodId:String(e?.method_id??""),scope:"cycle"===e?.scope?"cycle":"run",promptBeforeCycle:!!e?.prompt_before_cycle,values:e?.values&&"object"==typeof e.values?e.values:{},latched:e?.latched&&"object"==typeof e.latched?e.latched:null,ready:!1!==e?.ready,missing:Array.isArray(e?.missing)?e.missing:[],promptDue:!!e?.prompt_due}),TisContext=createContext({schemas:{},projectAssetRefs:[],defaultMethodId:"",schemasLoaded:!1,state:EMPTY_STATE,selection:EMPTY_SELECTION,setSelection:()=>{},existingProjects:[],projectKnown:()=>!1,refreshProjects:async()=>{},markProjectJustCreated:()=>{},projectFields:{},projectFieldsLoaded:!1,loadProjectFields:async()=>null,setProjectFields:()=>{},stagedConfig:{},setStagedConfig:()=>{},clearStagedConfig:()=>{},defaultsAppliedForMethod:"",markDefaultsAppliedForMethod:()=>{},configurationName:"",setConfigurationName:()=>{},cycleConfig:EMPTY_CYCLE_CONFIG,cycleConfigFields:[],setCycleConfigValues:async()=>{},clearCycleConfig:async()=>{},refreshCycleConfig:async()=>{},fetchRuns:async()=>[],fetchRun:async()=>null,runCache:{}});function liveReducer(e,t){switch(t.kind){case"staged":return{...e,staged:t.value};case"staged_project_id":return{...e,stagedProjectId:t.value};case"staged_method_id":return{...e,stagedMethodId:t.value};case"staged_sample_id":return{...e,stagedSampleId:t.value};case"active":return{...e,active:t.value};case"active_project_id":return{...e,activeProjectId:t.value};case"active_method_id":return{...e,activeMethodId:t.value};case"active_sample_id":return{...e,activeSampleId:t.value};case"active_run_id":return{...e,activeRunId:t.value};case"last_start_error":return{...e,lastStartError:t.value}}}export const TisProvider=({children:e,defaultMethodId:t})=>{const{invoke:s,subscribe:c,unsubscribe:a}=useContext(EventEmitterContext),[r,d]=useState({}),[o,n]=useState([]),[i,u]=useState(t??""),[l,p]=useState(!1),[f,_]=useReducer(liveReducer,EMPTY_STATE),[m,C]=useState({projectId:null,methodId:null,sampleId:null,runId:null});useEffect(()=>{let e=!1;return(async()=>{try{const c=await s("tis.list_schemas",MessageType.Request,{});if(e)return;if(c?.success&&c.data){const e=c.data.test_methods??{},s=c.data.default_method_id??"",a=Array.isArray(c.data.asset_refs)?c.data.asset_refs:[];d(e),n(a),!t&&s&&u(s),p(!0)}}catch(e){}})(),()=>{e=!0}},[]),useEffect(()=>{let e=!1;return(async()=>{try{const t=await s("gnv.ux.selected_project_id",MessageType.Read,{});if(e)return;const c=t?.success?t.data??"":"";"string"==typeof c&&c.length>0&&C(e=>null===e.projectId?{...e,projectId:c}:e)}catch{}})(),()=>{e=!0}},[]),useEffect(()=>{const e=[c("tis.staged",e=>_({kind:"staged",value:!!e})),c("tis.staged_project_id",e=>_({kind:"staged_project_id",value:String(e??"")})),c("tis.staged_method_id",e=>_({kind:"staged_method_id",value:String(e??"")})),c("tis.staged_sample_id",e=>_({kind:"staged_sample_id",value:String(e??"")})),c("tis.active",e=>_({kind:"active",value:!!e})),c("tis.active_project_id",e=>_({kind:"active_project_id",value:String(e??"")})),c("tis.active_method_id",e=>_({kind:"active_method_id",value:String(e??"")})),c("tis.active_sample_id",e=>_({kind:"active_sample_id",value:String(e??"")})),c("tis.active_run_id",e=>_({kind:"active_run_id",value:String(e??"")})),c("tis.last_start_error",e=>_({kind:"last_start_error",value:String(e??"")}))];return()=>{e.forEach(a)}},[c,a]);const I=useRef({}),[y,g]=useState(0),h=useCallback(()=>g(e=>e+1),[]),j=useCallback((e,t)=>{if(!e)return;const s=I.current[e]??{meta:null,cycles:[],results:{},rawData:{}};I.current[e]={...s,cycles:[...s.cycles,t]},h()},[h]),v=useCallback((e,t)=>{if(!e)return;const s=I.current[e]??{meta:null,cycles:[],results:{},rawData:{}};I.current[e]={...s,results:t},h()},[h]);useEffect(()=>{const e=c("tis.cycle_added",e=>{e?.run_id&&e.cycle&&j(e.run_id,e.cycle)}),t=c("tis.results_updated",e=>{e?.run_id&&v(e.run_id,e.results??{})});return()=>{a(e),a(t)}},[c,a,j,v]);const S=useMemo(()=>({projectId:m.projectId??f.activeProjectId,methodId:m.methodId??(f.activeMethodId||i),sampleId:m.sampleId??f.activeSampleId,runId:m.runId??f.activeRunId}),[m,f,i]),T=useCallback(e=>{C(t=>({projectId:void 0===e.projectId?t.projectId:e.projectId,methodId:void 0===e.methodId?t.methodId:e.methodId,sampleId:void 0===e.sampleId?t.sampleId:e.sampleId,runId:void 0===e.runId?t.runId:e.runId})),void 0!==e.projectId&&s("gnv.ux.selected_project_id",MessageType.Write,e.projectId??"").catch(e=>{})},[s]),E=useRef("");useEffect(()=>{const e=f.activeRunId;e&&e!==E.current&&(E.current=e,C({projectId:null,methodId:null,sampleId:null,runId:null}))},[f.activeRunId]);const x=useCallback(async(e,t)=>{if(!e)return[];const c={project_id:e};t&&(c.method_id=t);try{const e=await s("tis.list_tests",MessageType.Request,c);if(e?.success&&e.data?.tests)return e.data.tests}catch(e){}return[]},[s]),M=useCallback(async(e,t,c)=>{if(!e||!t||!c)return null;try{const a=await s("tis.read_test",MessageType.Request,{project_id:e,method_id:t,run_id:c}),r=await s("tis.read_cycles",MessageType.Request,{project_id:e,method_id:t,run_id:c,offset:0,limit:1e3,order:"asc"});if(!a?.success)return null;const d={meta:a.data??null,cycles:r?.success?r.data?.cycles??[]:[],results:a.data?.results??{},rawData:I.current[c]?.rawData??{}};return I.current[c]=d,h(),d}catch(e){return null}},[s,h]),k=useMemo(()=>({...I.current}),[y]),[R,P]=useState([]),b=useRef(new Set),[F,w]=useState(0),[Y,A]=useState({}),L=useCallback(async()=>{try{const e=await s("tis.list_projects",MessageType.Request,{});e?.success&&e.data?.projects&&P(e.data.projects)}catch(e){}},[s]),N=useCallback(e=>{e&&(b.current.has(e)||(b.current.add(e),w(e=>e+1)))},[]),D=useCallback(e=>!!e&&(!!b.current.has(e)||R.includes(e)),[R,F]),q=useCallback((e,t)=>{e&&A(s=>({...s,[e]:t}))},[]),O=useCallback(async e=>{if(!e)return null;try{const t=await s("tis.read_project",MessageType.Request,{project_id:e});if(t?.success){const s=t.data?.project_fields??{};return A(t=>({...t,[e]:s})),s}}catch(e){}return A(t=>({...t,[e]:{}})),{}},[s]);useEffect(()=>{L()},[L]),useEffect(()=>{const e=c("tis.project_created",()=>{L()}),t=c("tis.project_updated",e=>{const t="string"==typeof e?.project_id?e.project_id:"";t&&O(t)});return()=>{a(e),a(t)}},[c,a,L,O]),useEffect(()=>{const e=S.projectId;e&&D(e)&&void 0===Y[e]&&O(e)},[S.projectId,D,Y,O]);const G=Y[S.projectId]??{},V=void 0!==Y[S.projectId],[B,J]=useState({}),K=useCallback(e=>{J(t=>({...t,...e}))},[]),[W,z]=useState(""),H=useCallback(e=>{z(e)},[]),[Q,U]=useState(""),X=useCallback(()=>{J({}),z(""),U("")},[]),[Z,$]=useState(EMPTY_CYCLE_CONFIG),ee=useMemo(()=>{const e=S.methodId?r[S.methodId]?.cycle_config_fields:void 0;return Array.isArray(e)?e:[]},[r,S.methodId]),te=useCallback(async()=>{const e=S.projectId,t=S.methodId;if(t)try{const c=await s("tis.cycle_config",MessageType.Request,{project_id:e,method_id:t});if(c?.success)return void $(cycleConfigFromPayload(c.data));$(EMPTY_CYCLE_CONFIG)}catch(e){$(EMPTY_CYCLE_CONFIG)}else $(EMPTY_CYCLE_CONFIG)},[s,S.projectId,S.methodId]),se=useCallback(async e=>{const t=S.projectId,c=S.methodId;if(c)try{const a=await s("tis.set_cycle_config",MessageType.Request,{project_id:t,method_id:c,values:e});a?.success&&$(cycleConfigFromPayload(a.data))}catch(e){}},[s,S.projectId,S.methodId]),ce=useCallback(async()=>{const e=S.projectId,t=S.methodId;if(t)try{const c=await s("tis.clear_cycle_config",MessageType.Request,{project_id:e,method_id:t});c?.success&&$(cycleConfigFromPayload(c.data))}catch(e){}},[s,S.projectId,S.methodId]);useEffect(()=>{te()},[te]),useEffect(()=>{const e=c("tis.cycle_config",e=>{const t=String(e?.method_id??"");t&&S.methodId&&t!==S.methodId||$(cycleConfigFromPayload(e))});return()=>{a(e)}},[c,a,S.methodId]);const ae=useMemo(()=>({schemas:r,projectAssetRefs:o,defaultMethodId:i,schemasLoaded:l,state:f,selection:S,setSelection:T,existingProjects:R,projectKnown:D,refreshProjects:L,markProjectJustCreated:N,projectFields:G,projectFieldsLoaded:V,loadProjectFields:O,setProjectFields:q,stagedConfig:B,setStagedConfig:K,clearStagedConfig:X,defaultsAppliedForMethod:W,markDefaultsAppliedForMethod:H,configurationName:Q,setConfigurationName:U,cycleConfig:Z,cycleConfigFields:ee,setCycleConfigValues:se,clearCycleConfig:ce,refreshCycleConfig:te,fetchRuns:x,fetchRun:M,runCache:k}),[r,o,i,l,f,S,T,R,D,L,N,G,V,O,q,B,K,X,W,H,Q,U,Z,ee,se,ce,te,x,M,k]);return _jsx(TisContext.Provider,{value:ae,children:e})};export const useTis=()=>useContext(TisContext);export const useTisSchemas=()=>useContext(TisContext).schemas;export const useTisState=()=>useContext(TisContext).state;export const useTisCycleConfig=()=>{const{cycleConfig:e,cycleConfigFields:t,setCycleConfigValues:s,clearCycleConfig:c}=useContext(TisContext);return{...e,fields:t,setValues:s,clear:c}};export const useTisSelection=()=>{const{selection:e,setSelection:t}=useContext(TisContext);return[e,t]};export const useTisRuns=(e,t)=>{const{fetchRuns:s}=useContext(TisContext),[c,a]=useState([]),[r,d]=useState(!1),o=useCallback(async()=>{if(e){d(!0);try{a(await s(e,t))}finally{d(!1)}}else a([])},[e,t,s]);return useEffect(()=>{o()},[o]),{runs:c,loading:r,refresh:o}};export const useTisRun=e=>{const{selection:t,fetchRun:s,runCache:c}=useContext(TisContext),[a,r]=useState(!1),d=e??t.runId;useEffect(()=>{if(!d)return;if(c[d]?.meta)return;const e=t.projectId,a=t.methodId;e&&a&&(r(!0),s(e,a,d).finally(()=>r(!1)))},[d,t.projectId,t.methodId,s,c]);const o=d?c[d]:null;return{meta:o?.meta??null,cycles:o?.cycles??[],results:o?.results??{},rawData:o?.rawData??{},loading:a}};export{TisContext};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TisConfigEditor.d.ts","sourceRoot":"","sources":["../../../src/components/tis-editor/TisConfigEditor.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAWH,OAAO,EAAgB,KAAK,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAM5E,OAAO,uBAAuB,CAAC;AAE/B,MAAM,WAAW,oBAAoB;IACjC;+EAC2E;IAC3E,SAAS,EAAE,MAAM,CAAC;IAClB,wEAAwE;IACxE,OAAO,CAAC,EAAE,aAAa,CAAC;CAC3B;
|
|
1
|
+
{"version":3,"file":"TisConfigEditor.d.ts","sourceRoot":"","sources":["../../../src/components/tis-editor/TisConfigEditor.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAWH,OAAO,EAAgB,KAAK,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAM5E,OAAO,uBAAuB,CAAC;AAE/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,CAyQ1D,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";const EMPTY_METHOD={label:"",description:"",project_fields:[],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}),a=useAmsAssetTypes({invoker:i}),[n,r]=useState(null),[l,d]=useState(null),[c,m]=useState(!1),[f,p]=useState(!1),[h,u]=useState(!1),[_,g]=useState(""),x=useMemo(()=>o.config?Object.entries(o.config.methods).map(([e,t])=>({id:e,label:t?.label??""})):[],[o.config]);useEffect(()=>{if(!n&&o.config){const e=o.config.defaultMethodId||Object.keys(o.config.methods)[0]||null;r(e)}},[o.config,n]),useEffect(()=>{d(null)},[n]);return _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:c||!o.config?.dirty,onClick:()=>p(!0)}),_jsx(Button,{label:"Revert",icon:"pi pi-undo",className:"p-button-secondary",disabled:c||!o.config?.dirty,onClick:async()=>{if(window.confirm("Discard all in-progress edits? This cannot be undone.")){m(!0);try{await o.revert()}catch(e){d(String(e?.message??e))}finally{m(!1)}}}})]})]}),o.error&&_jsxs("div",{className:"tis-editor__error",children:[_jsx("strong",{children:"Error:"})," ",_jsx("pre",{children:o.error})]}),_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:c,onClick:()=>u(!0)}),_jsx(Button,{label:"Duplicate",icon:"pi pi-clone",className:"p-button-secondary",disabled:c||!n,onClick:async()=>{if(!n||!o.config)return;const e=o.config.methods[n];if(!e)return;let t=`${n}_copy`,s=2;for(;o.config.methods[t];)t=`${n}_copy_${s++}`;m(!0);try{await o.putMethod(t,JSON.parse(JSON.stringify(e))),r(t)}catch(e){d(String(e?.message??e))}finally{m(!1)}}}),_jsx(Button,{label:"Delete",icon:"pi pi-trash",className:"p-button-danger",disabled:c||!n,onClick:async()=>{if(n&&window.confirm(`Remove method "${n}"? This is staged — Save persists it.`)){m(!0);try{await o.removeMethod(n),r(null)}catch(e){d(String(e?.message??e))}finally{m(!1)}}}})]}),_jsxs(DataTable,{value:x,selection:x.find(e=>e.id===n)??null,onSelectionChange:e=>r(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:n&&o.config?.methods[n]?_jsxs(_Fragment,{children:[l&&_jsx("div",{className:"tis-editor__error",children:_jsx("pre",{children:l})}),_jsx(MethodFormEditor,{methodId:n,method:o.config.methods[n],onApply:async e=>{if(n){m(!0);try{await o.putMethod(n,e),d(null)}catch(e){d(String(e?.message??e))}finally{m(!1)}}},busy:c,knownAssetTypes:a.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:h,onHide:()=>u(!1),style:{width:"24rem"},children:[_jsxs("label",{className:"tis-editor__new-method-label",children:["Method ID",_jsx(InputText,{value:_,onChange:e=>g(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:()=>u(!1)}),_jsx(Button,{label:"Create",disabled:!_.trim()||c,onClick:async()=>{const e=_.trim();if(e)if(o.config?.methods[e])d(`A method named "${e}" already exists.`);else{m(!0);try{await o.putMethod(e,EMPTY_METHOD),r(e),u(!1),g("")}catch(e){d(String(e?.message??e))}finally{m(!1)}}}})]})]}),_jsx(SaveDiffDialog,{visible:f,staged:o.config?.methods??{},invoker:i,onConfirm:async()=>{m(!0);try{await o.save(),p(!1)}catch(e){d(String(e?.message??e))}finally{m(!1)}},onCancel:()=>p(!1)})]})};export default TisConfigEditor;
|
|
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";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}),a=useAmsAssetTypes({invoker:i}),[n,r]=useState(null),[l,d]=useState(null),[c,m]=useState(!1),[f,p]=useState(!1),[h,u]=useState(!1),[_,g]=useState(""),x=useMemo(()=>o.config?Object.entries(o.config.methods).map(([e,t])=>({id:e,label:t?.label??""})):[],[o.config]);useEffect(()=>{if(!n&&o.config){const e=o.config.defaultMethodId||Object.keys(o.config.methods)[0]||null;r(e)}},[o.config,n]),useEffect(()=>{d(null)},[n]);return _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:c||!o.config?.dirty,onClick:()=>p(!0)}),_jsx(Button,{label:"Revert",icon:"pi pi-undo",className:"p-button-secondary",disabled:c||!o.config?.dirty,onClick:async()=>{if(window.confirm("Discard all in-progress edits? This cannot be undone.")){m(!0);try{await o.revert()}catch(e){d(String(e?.message??e))}finally{m(!1)}}}})]})]}),o.error&&_jsxs("div",{className:"tis-editor__error",children:[_jsx("strong",{children:"Error:"})," ",_jsx("pre",{children:o.error})]}),_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:c,onClick:()=>u(!0)}),_jsx(Button,{label:"Duplicate",icon:"pi pi-clone",className:"p-button-secondary",disabled:c||!n,onClick:async()=>{if(!n||!o.config)return;const e=o.config.methods[n];if(!e)return;let t=`${n}_copy`,s=2;for(;o.config.methods[t];)t=`${n}_copy_${s++}`;m(!0);try{await o.putMethod(t,JSON.parse(JSON.stringify(e))),r(t)}catch(e){d(String(e?.message??e))}finally{m(!1)}}}),_jsx(Button,{label:"Delete",icon:"pi pi-trash",className:"p-button-danger",disabled:c||!n,onClick:async()=>{if(n&&window.confirm(`Remove method "${n}"? This is staged — Save persists it.`)){m(!0);try{await o.removeMethod(n),r(null)}catch(e){d(String(e?.message??e))}finally{m(!1)}}}})]}),_jsxs(DataTable,{value:x,selection:x.find(e=>e.id===n)??null,onSelectionChange:e=>r(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:n&&o.config?.methods[n]?_jsxs(_Fragment,{children:[l&&_jsx("div",{className:"tis-editor__error",children:_jsx("pre",{children:l})}),_jsx(MethodFormEditor,{methodId:n,method:o.config.methods[n],onApply:async e=>{if(n){m(!0);try{await o.putMethod(n,e),d(null)}catch(e){d(String(e?.message??e))}finally{m(!1)}}},busy:c,knownAssetTypes:a.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:h,onHide:()=>u(!1),style:{width:"24rem"},children:[_jsxs("label",{className:"tis-editor__new-method-label",children:["Method ID",_jsx(InputText,{value:_,onChange:e=>g(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:()=>u(!1)}),_jsx(Button,{label:"Create",disabled:!_.trim()||c,onClick:async()=>{const e=_.trim();if(e)if(o.config?.methods[e])d(`A method named "${e}" already exists.`);else{m(!0);try{await o.putMethod(e,EMPTY_METHOD),r(e),u(!1),g("")}catch(e){d(String(e?.message??e))}finally{m(!1)}}}})]})]}),_jsx(SaveDiffDialog,{visible:f,staged:o.config?.methods??{},invoker:i,onConfirm:async()=>{m(!0);try{await o.save(),p(!1)}catch(e){d(String(e?.message??e))}finally{m(!1)}},onCancel:()=>p(!1)})]})};export default TisConfigEditor;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CycleConfigSection — the two method-level settings that decide how the
|
|
3
|
+
* operator's per-row annotation behaves. The columns themselves are
|
|
4
|
+
* authored in the Fields tab; this is the state machine around them.
|
|
5
|
+
*
|
|
6
|
+
* The scope choice is the load-bearing one. A machine that records many
|
|
7
|
+
* cycles from one Start is not pausing for input between them, so its
|
|
8
|
+
* annotation has to latch once per Start ('run'). A machine the operator
|
|
9
|
+
* drives one cycle at a time — the six-position sweep — annotates each row
|
|
10
|
+
* separately ('cycle'), which means the gate re-arms between cycles and
|
|
11
|
+
* the control program must wait on `tis.cycle_ready`.
|
|
12
|
+
*/
|
|
13
|
+
import type { TestMethod } from '../types';
|
|
14
|
+
export interface CycleConfigSectionProps {
|
|
15
|
+
method: TestMethod;
|
|
16
|
+
onChange: (next: TestMethod) => void;
|
|
17
|
+
}
|
|
18
|
+
export declare const CycleConfigSection: React.FC<CycleConfigSectionProps>;
|
|
19
|
+
//# sourceMappingURL=CycleConfigSection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CycleConfigSection.d.ts","sourceRoot":"","sources":["../../../../src/components/tis-editor/editor/CycleConfigSection.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAMH,OAAO,KAAK,EAA+B,UAAU,EAAE,MAAM,UAAU,CAAC;AAOxE,MAAM,WAAW,uBAAuB;IACpC,MAAM,EAAE,UAAU,CAAC;IACnB,QAAQ,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,CAAC;CACxC;AAED,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAAE,CAAC,uBAAuB,CA+DhE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import{Dropdown}from"primereact/dropdown";import{Checkbox}from"primereact/checkbox";import{FormSection}from"../../forms/FormSection";import{FormRow}from"../../forms/FormRow";const SCOPES=[{label:"run — one entry per Start, stamped on every cycle of the run",value:"run"},{label:"cycle — one entry per cycle, re-entered between cycles",value:"cycle"}];export const CycleConfigSection=({method:e,onChange:o})=>{const t=e.cycle_config_fields??[],r="cycle"===e.cycle_config_scope?"cycle":"run",n=(t,r,n)=>{const c={...e};n?delete c[t]:c[t]=r,o(c)};return _jsxs(FormSection,{title:"Cycle Configuration",description:'How the operator-entered annotation columns behave. Add the columns themselves on the Fields tab under "Cycle Configuration Fields".',children:[0===t.length&&_jsx("div",{style:{color:"#6b7280",marginBottom:"0.75rem"},children:"This method declares no Cycle Configuration fields, so these settings have no effect."}),_jsx(FormRow,{label:"Scope",hint:'When the operator\'s entry is latched and cleared. Choose "cycle" only if the machine actually waits between cycles — under "cycle" the gate drops after every row and the control program must hold until tis.cycle_ready comes back true.',children:_jsx(Dropdown,{value:r,options:SCOPES,onChange:e=>n("cycle_config_scope",e.value,"run"===e.value)})}),_jsx(FormRow,{label:"Prompt before cycle",hint:"Open the entry dialog at the boundary instead of relying on the operator having filled the Cycle tab. Costs a confirmation each time — worth it when a mislabelled row means re-running the sample, not worth it for a non-critical note.",children:_jsx(Checkbox,{checked:!!e.prompt_before_cycle,onChange:e=>n("prompt_before_cycle",!!e.checked,!e.checked)})})]})};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FieldArrayEditor.d.ts","sourceRoot":"","sources":["../../../../src/components/tis-editor/editor/FieldArrayEditor.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAa,UAAU,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"FieldArrayEditor.d.ts","sourceRoot":"","sources":["../../../../src/components/tis-editor/editor/FieldArrayEditor.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAa,UAAU,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAyBrE,MAAM,WAAW,qBAAqB;IAClC,QAAQ,EAAE,aAAa,CAAC;IACxB,MAAM,EAAE,UAAU,CAAC;IACnB,QAAQ,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,CAAC;CACxC;AAED,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CAwH5D,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as _jsx,jsxs as _jsxs,Fragment as _Fragment}from"react/jsx-runtime";import{useState}from"react";import{DataTable}from"primereact/datatable";import{Column}from"primereact/column";import{Button}from"primereact/button";import{FormSection}from"../../forms/FormSection";import{TestFieldDialog}from"./TestFieldDialog";const TITLES={project_fields:"Project Fields",config_fields:"Config Fields",cycle_fields:"Cycle Fields",results_fields:"Results Fields"},DESCRIPTIONS={project_fields:"System-level fields (operator, station). Filled by the HMI but not cycled.",config_fields:"Operator-input config (speeds, loads). Snapshotted into test.json on start.",cycle_fields:"Per-cycle capture. One row appended to cycles.jsonl per cycle.",results_fields:"Post-test summary (min/max/avg, pass/fail). Written once at finish. A field can also be a cross-test Aggregate (avg/min/max/stddev/count over tests sharing a sample_id)."},aggregateLabel=e=>{const t=e.aggregate;return t?"count"===t.fn?"count":`${t.fn}(${t.of??"?"})`:""};export const FieldArrayEditor=({arrayKey:e,method:t,onChange:s})=>{const l=t[e]??[],[i
|
|
1
|
+
import{jsx as _jsx,jsxs as _jsxs,Fragment as _Fragment}from"react/jsx-runtime";import{useState}from"react";import{DataTable}from"primereact/datatable";import{Column}from"primereact/column";import{Button}from"primereact/button";import{FormSection}from"../../forms/FormSection";import{TestFieldDialog}from"./TestFieldDialog";const TITLES={project_fields:"Project Fields",config_fields:"Config Fields",cycle_config_fields:"Cycle Configuration Fields",cycle_fields:"Cycle Fields",results_fields:"Results Fields"},DESCRIPTIONS={project_fields:"System-level fields (operator, station). Filled by the HMI but not cycled.",config_fields:"Operator-input config (speeds, loads). Snapshotted into test.json on start.",cycle_config_fields:"Operator-entered annotation recorded onto every cycle row (e.g. which of six positions this is). Shown on the HMI Cycle tab and written as the first Cycle Data columns after the row index. Mark them Required so the machine cannot start unannotated, and Autoclear so the next row cannot inherit a stale value.",cycle_fields:"Per-cycle capture. One row appended to cycles.jsonl per cycle.",results_fields:"Post-test summary (min/max/avg, pass/fail). Written once at finish. A field can also be a cross-test Aggregate (avg/min/max/stddev/count over tests sharing a sample_id)."},aggregateLabel=e=>{const t=e.aggregate;return t?"count"===t.fn?"count":`${t.fn}(${t.of??"?"})`:""};export const FieldArrayEditor=({arrayKey:e,method:t,onChange:s})=>{const l=t[e]??[],[o,i]=useState(!1),[n,a]=useState(null),r=(o,i)=>{const n=o+i;if(n<0||n>=l.length)return;const a=[...l];[a[o],a[n]]=[a[n],a[o]],s({...t,[e]:a})};return _jsxs(_Fragment,{children:[_jsx(FormSection,{title:TITLES[e],description:DESCRIPTIONS[e],actions:_jsx(Button,{label:"Add field",icon:"pi pi-plus",size:"small",onClick:()=>{a(null),i(!0)}}),children:_jsxs(DataTable,{value:l,dataKey:"name",emptyMessage:"No fields defined.",children:[_jsx(Column,{field:"name",header:"Name"}),_jsx(Column,{field:"type",header:"Type",style:{width:"6rem"}}),_jsx(Column,{field:"units",header:"Units",style:{width:"6rem"}}),_jsx(Column,{header:"Req",body:e=>e.required?"✓":"",style:{width:"4rem"}}),_jsx(Column,{field:"label",header:"Label"}),"results_fields"===e&&_jsx(Column,{header:"Aggregate",body:e=>aggregateLabel(e),style:{width:"8rem"}}),"cycle_config_fields"===e&&_jsx(Column,{header:"Autoclear",body:e=>e.autoclear?"✓":"",style:{width:"6rem"}}),_jsx(Column,{header:"",body:(o,n)=>_jsxs("div",{style:{display:"flex",gap:"0.25rem"},children:[_jsx(Button,{icon:"pi pi-arrow-up",className:"p-button-text p-button-sm",disabled:0===n.rowIndex,onClick:()=>r(n.rowIndex,-1),"aria-label":"Move up"}),_jsx(Button,{icon:"pi pi-arrow-down",className:"p-button-text p-button-sm",disabled:n.rowIndex===l.length-1,onClick:()=>r(n.rowIndex,1),"aria-label":"Move down"}),_jsx(Button,{icon:"pi pi-pencil",className:"p-button-text p-button-sm",onClick:()=>{return e=n.rowIndex,a(e),void i(!0);var e},"aria-label":"Edit"}),_jsx(Button,{icon:"pi pi-trash",className:"p-button-text p-button-danger p-button-sm",onClick:()=>(o=>{const i=l[o];if(!i)return;if(!window.confirm(`Remove field "${i.name}"?`))return;const n=l.filter((e,t)=>t!==o);s({...t,[e]:n})})(n.rowIndex),"aria-label":"Remove"})]}),style:{width:"10rem"}})]})}),_jsx(TestFieldDialog,{visible:o,initial:null!==n?l[n]??null:null,siblingNames:l.map(e=>e.name),isResultsField:"results_fields"===e,isCycleConfigField:"cycle_config_fields"===e,cycleFieldNames:(t.cycle_fields??[]).map(e=>e.name).filter(Boolean),resultsFieldNames:(t.results_fields??[]).map(e=>e.name).filter(Boolean),onCancel:()=>i(!1),onSave:o=>{const a=[...l];null===n?a.push(o):a[n]=o,s({...t,[e]:a}),i(!1)}})]})};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MethodFormEditor.d.ts","sourceRoot":"","sources":["../../../../src/components/tis-editor/editor/MethodFormEditor.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;
|
|
1
|
+
{"version":3,"file":"MethodFormEditor.d.ts","sourceRoot":"","sources":["../../../../src/components/tis-editor/editor/MethodFormEditor.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAeH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAE3C,MAAM,WAAW,qBAAqB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,UAAU,CAAC;IACnB,6EAA6E;IAC7E,OAAO,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACpD,4EAA4E;IAC5E,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,IAAI,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CAiL5D,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import{useEffect,useMemo,useState}from"react";import{TabView,TabPanel}from"primereact/tabview";import{Button}from"primereact/button";import{CodeEditor}from"../../CodeEditor";import{IdentitySection}from"./IdentitySection";import{FieldArrayEditor}from"./FieldArrayEditor";import{ConfigurationsEditor}from"./ConfigurationsEditor";import{ViewsEditor}from"./ViewsEditor";import{RawDataEditor}from"./RawDataEditor";import{AssetRefsEditor}from"./AssetRefsEditor";import{AnalysisEditor}from"./AnalysisEditor";import{validateMethod}from"../validation";export const MethodFormEditor=({methodId:e,method:
|
|
1
|
+
import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";import{useEffect,useMemo,useState}from"react";import{TabView,TabPanel}from"primereact/tabview";import{Button}from"primereact/button";import{CodeEditor}from"../../CodeEditor";import{IdentitySection}from"./IdentitySection";import{FieldArrayEditor}from"./FieldArrayEditor";import{CycleConfigSection}from"./CycleConfigSection";import{ConfigurationsEditor}from"./ConfigurationsEditor";import{ViewsEditor}from"./ViewsEditor";import{RawDataEditor}from"./RawDataEditor";import{AssetRefsEditor}from"./AssetRefsEditor";import{AnalysisEditor}from"./AnalysisEditor";import{validateMethod}from"../validation";export const MethodFormEditor=({methodId:e,method:r,onApply:t,knownAssetTypes:i=[],busy:o})=>{const[s,n]=useState(r),[a,d]=useState(""),[l,h]=useState(null),[c,m]=useState(0);useEffect(()=>{n(r),d(JSON.stringify(r,null,2)),h(null)},[r,e]);const f=useMemo(()=>{try{return JSON.stringify(s)!==JSON.stringify(r)}catch{return!0}},[s,r]),y=useMemo(()=>validateMethod(e,s),[s,e]),g=e=>{n(e),d(JSON.stringify(e,null,2))};return _jsxs("div",{style:{display:"flex",flexDirection:"column",height:"100%",minHeight:0},children:[_jsxs("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"center",padding:"0.5rem 1rem",borderBottom:"1px solid var(--surface-d, #e2e8f0)",background:"var(--surface-b, #f8fafc)"},children:[_jsxs("strong",{children:[e,f&&_jsx("span",{style:{marginLeft:"0.5rem",color:"#ea580c"},children:"•"}),y.length>0&&_jsxs("span",{style:{marginLeft:"0.5rem",background:"#fef2f2",color:"#991b1b",padding:"0.1rem 0.5rem",borderRadius:4,fontSize:"0.75rem",fontWeight:600},children:[y.length," issue",1===y.length?"":"s"]})]}),_jsx("div",{style:{display:"flex",gap:"0.5rem"},children:_jsx(Button,{label:"Apply",icon:"pi pi-check",disabled:o||!f||!!l||y.length>0,onClick:async()=>{l||await t(s)}})})]}),y.length>0&&_jsxs("div",{style:{padding:"0.5rem 1rem",background:"#fef2f2",color:"#991b1b",borderBottom:"1px solid #fecaca",fontSize:"0.85rem"},children:[_jsxs("strong",{children:["Fix ",1===y.length?"this issue":"these issues"," before applying:"]}),_jsx("ul",{style:{margin:"0.25rem 0 0 1.25rem"},children:y.map((e,r)=>_jsx("li",{children:e.message},r))})]}),_jsx("div",{style:{flex:1,minHeight:0,overflow:"auto"},children:_jsxs(TabView,{activeIndex:c,onTabChange:e=>m(e.index),children:[_jsx(TabPanel,{header:"Identity",children:_jsx(IdentitySection,{method:s,onChange:g})}),_jsxs(TabPanel,{header:"Fields",children:[_jsx(FieldArrayEditor,{arrayKey:"project_fields",method:s,onChange:g}),_jsx(FieldArrayEditor,{arrayKey:"config_fields",method:s,onChange:g}),_jsx(FieldArrayEditor,{arrayKey:"cycle_config_fields",method:s,onChange:g}),_jsx(CycleConfigSection,{method:s,onChange:g}),_jsx(FieldArrayEditor,{arrayKey:"cycle_fields",method:s,onChange:g}),_jsx(FieldArrayEditor,{arrayKey:"results_fields",method:s,onChange:g})]}),_jsx(TabPanel,{header:"Configurations",children:_jsx(ConfigurationsEditor,{method:s,onChange:g})}),_jsx(TabPanel,{header:"Views",children:_jsx(ViewsEditor,{method:s,onChange:g})}),_jsx(TabPanel,{header:"Raw Data",children:_jsx(RawDataEditor,{method:s,onChange:g})}),_jsx(TabPanel,{header:"Assets",children:_jsx(AssetRefsEditor,{method:s,onChange:g,knownAssetTypes:i})}),_jsx(TabPanel,{header:"Analysis",children:_jsx(AnalysisEditor,{method:s,onChange:g})}),_jsxs(TabPanel,{header:"JSON",children:[l&&_jsx("div",{style:{color:"#dc2626",marginBottom:"0.5rem",fontFamily:"monospace"},children:l}),_jsx("div",{style:{height:"60vh"},children:_jsx(CodeEditor,{code:a,language:"json",theme:"vs-dark",readOnly:!1,cursorStyle:"line",onCodeChanged:e=>{const r=e??"";d(r);try{const e=JSON.parse(r);n(e),h(null)}catch(e){h(String(e?.message??e))}}})})]})]})})]})};
|
|
@@ -9,6 +9,9 @@ export interface TestFieldDialogProps {
|
|
|
9
9
|
/** True when this field belongs to `results_fields` — only then is the
|
|
10
10
|
* cross-test Aggregate section shown. */
|
|
11
11
|
isResultsField?: boolean;
|
|
12
|
+
/** True when this field belongs to `cycle_config_fields` — only then is
|
|
13
|
+
* the Autoclear option shown, and only there does it do anything. */
|
|
14
|
+
isCycleConfigField?: boolean;
|
|
12
15
|
/** Candidate target field names for an aggregate's `of`, by source. */
|
|
13
16
|
cycleFieldNames?: string[];
|
|
14
17
|
resultsFieldNames?: string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TestFieldDialog.d.ts","sourceRoot":"","sources":["../../../../src/components/tis-editor/editor/TestFieldDialog.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,SAAS,EAAiC,MAAM,UAAU,CAAC;AA4BzE,MAAM,WAAW,oBAAoB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,SAAS,GAAG,IAAI,CAAC;IAC1B,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,MAAM,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;IACnC,8EAA8E;IAC9E,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB;8CAC0C;IAC1C,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,uEAAuE;IACvE,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;CAChC;AAID,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,
|
|
1
|
+
{"version":3,"file":"TestFieldDialog.d.ts","sourceRoot":"","sources":["../../../../src/components/tis-editor/editor/TestFieldDialog.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,SAAS,EAAiC,MAAM,UAAU,CAAC;AA4BzE,MAAM,WAAW,oBAAoB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,SAAS,GAAG,IAAI,CAAC;IAC1B,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,MAAM,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;IACnC,8EAA8E;IAC9E,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB;8CAC0C;IAC1C,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;0EACsE;IACtE,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,uEAAuE;IACvE,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;CAChC;AAID,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAwO1D,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as _jsx,Fragment as _Fragment,jsxs as _jsxs}from"react/jsx-runtime";import{useEffect,useState}from"react";import{Dialog}from"primereact/dialog";import{Button}from"primereact/button";import{InputText}from"primereact/inputtext";import{InputTextarea}from"primereact/inputtextarea";import{Dropdown}from"primereact/dropdown";import{Checkbox}from"primereact/checkbox";import{InputNumber}from"primereact/inputnumber";import{FormRow}from"../../forms/FormRow";const FIELD_TYPES=[{label:"string",value:"string"},{label:"i32",value:"i32"},{label:"i64",value:"i64"},{label:"u32",value:"u32"},{label:"u64",value:"u64"},{label:"f32",value:"f32"},{label:"f64",value:"f64"},{label:"bool",value:"bool"}],AGG_FNS=[{label:"— none (analysis-fed) —",value:""},{label:"avg",value:"avg"},{label:"min",value:"min"},{label:"max",value:"max"},{label:"stddev",value:"stddev"},{label:"count (# included tests)",value:"count"}],AGG_FROMS=[{label:"cycle field (every cycle, every test)",value:"cycle_fields"},{label:"result (one value per test)",value:"results"}],blank={name:"",type:"f32"};export const TestFieldDialog=({visible:e,initial:a,onCancel:t,onSave:l,siblingNames:r,isResultsField:n=!1,cycleFieldNames:
|
|
1
|
+
import{jsx as _jsx,Fragment as _Fragment,jsxs as _jsxs}from"react/jsx-runtime";import{useEffect,useState}from"react";import{Dialog}from"primereact/dialog";import{Button}from"primereact/button";import{InputText}from"primereact/inputtext";import{InputTextarea}from"primereact/inputtextarea";import{Dropdown}from"primereact/dropdown";import{Checkbox}from"primereact/checkbox";import{InputNumber}from"primereact/inputnumber";import{FormRow}from"../../forms/FormRow";const FIELD_TYPES=[{label:"string",value:"string"},{label:"i32",value:"i32"},{label:"i64",value:"i64"},{label:"u32",value:"u32"},{label:"u64",value:"u64"},{label:"f32",value:"f32"},{label:"f64",value:"f64"},{label:"bool",value:"bool"}],AGG_FNS=[{label:"— none (analysis-fed) —",value:""},{label:"avg",value:"avg"},{label:"min",value:"min"},{label:"max",value:"max"},{label:"stddev",value:"stddev"},{label:"count (# included tests)",value:"count"}],AGG_FROMS=[{label:"cycle field (every cycle, every test)",value:"cycle_fields"},{label:"result (one value per test)",value:"results"}],blank={name:"",type:"f32"};export const TestFieldDialog=({visible:e,initial:a,onCancel:t,onSave:l,siblingNames:r,isResultsField:n=!1,isCycleConfigField:i=!1,cycleFieldNames:o=[],resultsFieldNames:s=[]})=>{const[u,d]=useState(blank),[m,c]=useState(""),[g,h]=useState(null);useEffect(()=>{e&&(d(a?{...a}:{...blank}),c(null==a?.default?"":String(a.default)),h(null))},[e,a]);const p=u.aggregate,f=p?.from??"cycle_fields",v=("results"===f?s:o).filter(e=>e&&e!==u.name).map(e=>({label:e,value:e}));return _jsxs(Dialog,{header:a?`Edit field: ${a.name}`:"New field",visible:e,onHide:t,style:{width:"36rem"},children:[g&&_jsx("div",{style:{color:"#dc2626",marginBottom:"0.75rem"},children:g}),_jsx(FormRow,{label:"Name",required:!0,hint:"Wire-format key. Also the column name in CSV exports.",children:_jsx(InputText,{value:u.name,onChange:e=>d({...u,name:e.target.value})})}),_jsx(FormRow,{label:"Type",required:!0,children:_jsx(Dropdown,{value:u.type,options:FIELD_TYPES,onChange:e=>d({...u,type:e.value}),editable:!0})}),_jsx(FormRow,{label:"Units",hint:"Display label, appended to form labels (e.g. m/s).",children:_jsx(InputText,{value:u.units??"",onChange:e=>d({...u,units:e.target.value||void 0})})}),_jsx(FormRow,{label:"Label",hint:"Pretty form label. Falls back to name when empty.",children:_jsx(InputText,{value:u.label??"",onChange:e=>d({...u,label:e.target.value||void 0})})}),_jsx(FormRow,{label:"Required",hint:i?"Blocks the machine until the operator fills this in — tis.cycle_ready stays false and start_test is refused. This is what stops an unannotated row from being recorded.":void 0,children:_jsx(Checkbox,{checked:!!u.required,onChange:e=>d({...u,required:!!e.checked})})}),i&&_jsx(FormRow,{label:"Autoclear",hint:"Clear the operator's entry once a row has recorded it, so the next row can't inherit a stale value. Fires after each cycle under 'cycle' scope, at the end of the run under 'run' scope. Pair with Required — on its own it turns stale data into silently missing data.",children:_jsx(Checkbox,{checked:!!u.autoclear,onChange:e=>d({...u,autoclear:!!e.checked})})}),_jsx(FormRow,{label:"Source",hint:"Optional gm.* variable to bind this field to.",children:_jsx(InputText,{value:u.source??"",onChange:e=>d({...u,source:e.target.value||void 0}),placeholder:"gm.<variable_name>"})}),_jsx(FormRow,{label:"Scale",hint:"display = raw × scale. Leave blank for 1.0 (no conversion).",children:_jsx(InputNumber,{value:u.scale??null,onValueChange:e=>d({...u,scale:"number"==typeof e.value?e.value:void 0}),mode:"decimal",minFractionDigits:0,maxFractionDigits:9})}),_jsx(FormRow,{label:"Min",hint:"Optional lower bound the operator can enter (display units). Blank = no minimum.",children:_jsx(InputNumber,{value:u.min??null,onValueChange:e=>d({...u,min:"number"==typeof e.value?e.value:void 0}),mode:"decimal",minFractionDigits:0,maxFractionDigits:9})}),_jsx(FormRow,{label:"Max",hint:"Optional upper bound the operator can enter (display units). Blank = no maximum.",children:_jsx(InputNumber,{value:u.max??null,onValueChange:e=>d({...u,max:"number"==typeof e.value?e.value:void 0}),mode:"decimal",minFractionDigits:0,maxFractionDigits:9})}),_jsx(FormRow,{label:"Default",hint:"Applied every time the method loads (operator can override). A literal (display units) like 5, or an FQDN token like ${gm.safe_speed} that snapshots that value on load.",children:_jsx(InputText,{value:m,onChange:e=>c(e.target.value),placeholder:"e.g. 5 or ${gm.safe_speed}"})}),n&&_jsxs(_Fragment,{children:[_jsx("div",{style:{borderTop:"1px solid #e5e7eb",margin:"0.75rem 0 0.25rem"}}),_jsx(FormRow,{label:"Aggregate",hint:"Cross-test rollup. When set, this result is derived server-side over the non-excluded tests sharing the same sample_id — the analysis script does not supply it.",children:_jsx(Dropdown,{value:p?.fn??"",options:AGG_FNS,onChange:e=>(e=>{if(""===e)return void d({...u,aggregate:void 0});if("count"===e)return void d({...u,aggregate:{fn:"count"}});const a={fn:e,of:u.aggregate?.of,from:u.aggregate?.from??"cycle_fields"};d({...u,aggregate:a})})(e.value)})}),p&&"count"!==p.fn&&_jsxs(_Fragment,{children:[_jsx(FormRow,{label:"Aggregate from",hint:"Which per-test source the target field is read from.",children:_jsx(Dropdown,{value:f,options:AGG_FROMS,onChange:e=>d({...u,aggregate:{...p,from:e.value}})})}),_jsx(FormRow,{label:"Aggregate of",required:!0,hint:"The field to reduce across tests.",children:_jsx(Dropdown,{value:p.of??null,options:v,onChange:e=>d({...u,aggregate:{...p,of:e.value||void 0}}),editable:!0,placeholder:v.length?"Select a field":`No ${f} defined yet`})})]})]}),_jsx(FormRow,{label:"Description",hint:"Hover tooltip in the form.",children:_jsx(InputTextarea,{rows:2,value:u.description??"",onChange:e=>d({...u,description:e.target.value||void 0})})}),_jsxs("div",{style:{display:"flex",justifyContent:"flex-end",gap:"0.5rem",marginTop:"1rem"},children:[_jsx(Button,{label:"Cancel",className:"p-button-text",onClick:t}),_jsx(Button,{label:"Save",onClick:()=>{const e={...u},t=(e=>{const a=e.trim();if(""!==a){if(a.startsWith("${"))return a;if("true"===a)return!0;if("false"===a)return!1;if(/^-?\d*\.?\d+$/.test(a)){const e=Number(a);if(Number.isFinite(e))return e}return a}})(m);void 0===t?delete e.default:e.default=t;const n=(i=e).name.trim()?/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(i.name)?r.some(e=>e===i.name&&e!==a?.name)?`A field named "${i.name}" already exists in this array.`:"number"==typeof i.min&&"number"==typeof i.max&&i.min>i.max?`Min (${i.min}) cannot be greater than Max (${i.max}).`:i.aggregate&&"count"!==i.aggregate.fn&&!i.aggregate.of?.trim()?`Aggregate "${i.aggregate.fn}" needs a target field (the field to ${i.aggregate.fn} across tests).`:null:"Name must be a valid identifier (letters, digits, underscore; cannot start with a digit).":"Field name is required.";var i;n?h(n):l(e)}})]})]})};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ViewsEditor.d.ts","sourceRoot":"","sources":["../../../../src/components/tis-editor/editor/ViewsEditor.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAwB,UAAU,EAAE,MAAM,UAAU,CAAC;AAEjE,MAAM,WAAW,gBAAgB;IAC7B,MAAM,EAAE,UAAU,CAAC;IACnB,QAAQ,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,CAAC;CACxC;AAQD,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,
|
|
1
|
+
{"version":3,"file":"ViewsEditor.d.ts","sourceRoot":"","sources":["../../../../src/components/tis-editor/editor/ViewsEditor.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAwB,UAAU,EAAE,MAAM,UAAU,CAAC;AAEjE,MAAM,WAAW,gBAAgB;IAC7B,MAAM,EAAE,UAAU,CAAC;IACnB,QAAQ,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,CAAC;CACxC;AAQD,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CAwFlD,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as _jsx,jsxs as _jsxs,Fragment as _Fragment}from"react/jsx-runtime";import{useState}from"react";import{DataTable}from"primereact/datatable";import{Column}from"primereact/column";import{Button}from"primereact/button";import{FormSection}from"../../forms/FormSection";import{ChartViewDialog}from"./ChartViewDialog";export const ViewsEditor=({method:e,onChange:t})=>{const i=e.views??{},a=Object.entries(i).map(([e,t])=>({id:e,title:t.title??"",type:t.type??""})),[s,n]=useState(!1),[o,r]=useState(null),l=[...(e.project_fields??[]).map(e=>e.name),...(e.config_fields??[]).map(e=>e.name),...(e.cycle_fields??[]).map(e=>e.name),...(e.results_fields??[]).map(e=>e.name),...Object.keys(e.raw_data?.columns??{})];return _jsxs(_Fragment,{children:[_jsx(FormSection,{title:"Views",description:"Named chart definitions rendered by <TestDataView> (cycle_scatter) and <TestRawDataView> (raw_trace).",actions:_jsx(Button,{label:"Add view",icon:"pi pi-plus",size:"small",onClick:()=>{r(null),n(!0)}}),children:_jsxs(DataTable,{value:a,dataKey:"id",emptyMessage:"No views defined.",children:[_jsx(Column,{field:"id",header:"View ID"}),_jsx(Column,{field:"title",header:"Title"}),_jsx(Column,{field:"type",header:"Type",style:{width:"8rem"}}),_jsx(Column,{header:"",body:a=>_jsxs("div",{style:{display:"flex",gap:"0.25rem"},children:[_jsx(Button,{icon:"pi pi-pencil",className:"p-button-text p-button-sm",onClick:()=>{return e=a.id,r(e),void n(!0);var e},"aria-label":"Edit"}),_jsx(Button,{icon:"pi pi-trash",className:"p-button-text p-button-danger p-button-sm",onClick:()=>(a=>{if(!window.confirm(`Remove view "${a}"?`))return;const s={...i};delete s[a],t({...e,views:s})})(a.id),"aria-label":"Remove"})]}),style:{width:"6rem"}})]})}),_jsx(ChartViewDialog,{visible:s,initial:o?{viewId:o,view:i[o]}:null,knownKeys:l,siblingIds:Object.keys(i),onCancel:()=>n(!1),onSave:(a,s)=>{const r={...i};o&&o!==a&&delete r[o],r[a]=s,t({...e,views:r}),n(!1)}})]})};
|
|
1
|
+
import{jsx as _jsx,jsxs as _jsxs,Fragment as _Fragment}from"react/jsx-runtime";import{useState}from"react";import{DataTable}from"primereact/datatable";import{Column}from"primereact/column";import{Button}from"primereact/button";import{FormSection}from"../../forms/FormSection";import{ChartViewDialog}from"./ChartViewDialog";export const ViewsEditor=({method:e,onChange:t})=>{const i=e.views??{},a=Object.entries(i).map(([e,t])=>({id:e,title:t.title??"",type:t.type??""})),[s,n]=useState(!1),[o,r]=useState(null),l=[...(e.project_fields??[]).map(e=>e.name),...(e.config_fields??[]).map(e=>e.name),...(e.cycle_config_fields??[]).map(e=>e.name),...(e.cycle_fields??[]).map(e=>e.name),...(e.results_fields??[]).map(e=>e.name),...Object.keys(e.raw_data?.columns??{}),"cycle_index","timestamp"];return _jsxs(_Fragment,{children:[_jsx(FormSection,{title:"Views",description:"Named chart definitions rendered by <TestDataView> (cycle_scatter) and <TestRawDataView> (raw_trace).",actions:_jsx(Button,{label:"Add view",icon:"pi pi-plus",size:"small",onClick:()=>{r(null),n(!0)}}),children:_jsxs(DataTable,{value:a,dataKey:"id",emptyMessage:"No views defined.",children:[_jsx(Column,{field:"id",header:"View ID"}),_jsx(Column,{field:"title",header:"Title"}),_jsx(Column,{field:"type",header:"Type",style:{width:"8rem"}}),_jsx(Column,{header:"",body:a=>_jsxs("div",{style:{display:"flex",gap:"0.25rem"},children:[_jsx(Button,{icon:"pi pi-pencil",className:"p-button-text p-button-sm",onClick:()=>{return e=a.id,r(e),void n(!0);var e},"aria-label":"Edit"}),_jsx(Button,{icon:"pi pi-trash",className:"p-button-text p-button-danger p-button-sm",onClick:()=>(a=>{if(!window.confirm(`Remove view "${a}"?`))return;const s={...i};delete s[a],t({...e,views:s})})(a.id),"aria-label":"Remove"})]}),style:{width:"6rem"}})]})}),_jsx(ChartViewDialog,{visible:s,initial:o?{viewId:o,view:i[o]}:null,knownKeys:l,siblingIds:Object.keys(i),onCancel:()=>n(!1),onSave:(a,s)=>{const r={...i};o&&o!==a&&delete r[o],r[a]=s,t({...e,views:r}),n(!1)}})]})};
|
|
@@ -25,6 +25,15 @@ export interface TestField {
|
|
|
25
25
|
* non-excluded runs sharing this test's sample_id. When set, the field
|
|
26
26
|
* is NOT supplied by the analysis script — the server computes it. */
|
|
27
27
|
aggregate?: AggregateSpec;
|
|
28
|
+
/** cycle_fields only: operator-correctable after recording. Measured
|
|
29
|
+
* columns must stay unflagged. cycle_config_fields don't need it —
|
|
30
|
+
* they're annotation and are always correctable. */
|
|
31
|
+
editable?: boolean;
|
|
32
|
+
/** cycle_config_fields only: clear the operator's entry once a row has
|
|
33
|
+
* recorded it, so the next row can't inherit a stale annotation. Pair
|
|
34
|
+
* it with `required` — on its own it turns stale data into silently
|
|
35
|
+
* missing data. */
|
|
36
|
+
autoclear?: boolean;
|
|
28
37
|
}
|
|
29
38
|
export type AggFn = 'avg' | 'min' | 'max' | 'stddev' | 'count';
|
|
30
39
|
export type AggFrom = 'cycle_fields' | 'results';
|
|
@@ -93,11 +102,29 @@ export interface TestConfiguration {
|
|
|
93
102
|
description?: string;
|
|
94
103
|
defaults?: Record<string, unknown>;
|
|
95
104
|
}
|
|
105
|
+
/**
|
|
106
|
+
* Which boundary an operator annotates `cycle_config_fields` at.
|
|
107
|
+
*
|
|
108
|
+
* 'run' one latch per Start — the same values stamp every cycle of the
|
|
109
|
+
* run and clear when it closes. Default; correct for a machine
|
|
110
|
+
* that records many cycles from one Start.
|
|
111
|
+
* 'cycle' one latch per cycle — values clear after each recorded row and
|
|
112
|
+
* the gate re-arms, so every row is annotated separately.
|
|
113
|
+
*/
|
|
114
|
+
export type CycleConfigScope = 'run' | 'cycle';
|
|
96
115
|
export interface TestMethod {
|
|
97
116
|
label?: string;
|
|
98
117
|
description?: string;
|
|
99
118
|
project_fields?: TestField[];
|
|
100
119
|
config_fields?: TestField[];
|
|
120
|
+
/** Operator-entered per-row annotation, recorded as the first Cycle Data
|
|
121
|
+
* columns after the row index. */
|
|
122
|
+
cycle_config_fields?: TestField[];
|
|
123
|
+
/** Boundary at which cycle_config_fields latch and autoclear. */
|
|
124
|
+
cycle_config_scope?: CycleConfigScope;
|
|
125
|
+
/** Open the Cycle Configuration dialog at the boundary rather than
|
|
126
|
+
* relying on the operator having filled the Cycle tab. */
|
|
127
|
+
prompt_before_cycle?: boolean;
|
|
101
128
|
cycle_fields?: TestField[];
|
|
102
129
|
results_fields?: TestField[];
|
|
103
130
|
raw_data?: RawDataShape | null;
|
|
@@ -107,5 +134,5 @@ export interface TestMethod {
|
|
|
107
134
|
configurations?: TestConfiguration[];
|
|
108
135
|
[key: string]: unknown;
|
|
109
136
|
}
|
|
110
|
-
export type FieldArrayKey = 'project_fields' | 'config_fields' | 'cycle_fields' | 'results_fields';
|
|
137
|
+
export type FieldArrayKey = 'project_fields' | 'config_fields' | 'cycle_config_fields' | 'cycle_fields' | 'results_fields';
|
|
111
138
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
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,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,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;2EAEuE;IACvE,SAAS,CAAC,EAAE,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/components/tis-editor/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../../src/components/tis-editor/validation.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EACG,UAAU,EACxB,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../../src/components/tis-editor/validation.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EACG,UAAU,EACxB,MAAM,SAAS,CAAC;AAmBjB,MAAM,WAAW,eAAe;IAC5B,yEAAyE;IACzE,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,CAAC,EAAE,UAAU,GAAG,eAAe,EAAE,CA0JjF;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,eAAe,EAAE,CAAC,CAOtG"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const FIELD_ARRAY_KEYS=["project_fields","config_fields","cycle_fields","results_fields"];export function validateMethod(e,a){const s=[];for(const
|
|
1
|
+
const FIELD_ARRAY_KEYS=["project_fields","config_fields","cycle_config_fields","cycle_fields","results_fields"],SERVER_ASSIGNED_CYCLE_COLUMNS=["cycle_index","timestamp","checksum"];export function validateMethod(e,a){const s=[];for(const n of FIELD_ARRAY_KEYS){const t=a[n]??[],o=new Set;t.forEach((a,t)=>{a.name&&""!==a.name.trim()?o.has(a.name)?s.push({path:`${n}.${t}.name`,message:`${e}.${n}: duplicate field name "${a.name}"`}):o.add(a.name):s.push({path:`${n}.${t}.name`,message:`${e}.${n}: empty field name`}),"number"==typeof a.min&&"number"==typeof a.max&&a.min>a.max&&s.push({path:`${n}.${t}.min`,message:`${e}.${n}.${a.name}: min (${a.min}) is greater than max (${a.max})`})})}const n=new Set(["i32","i64","u32","u64","f32","f64"]),t=new Map((a.cycle_fields??[]).map(e=>[e.name,String(e.type)])),o=new Map((a.results_fields??[]).map(e=>[e.name,String(e.type)]));for(const n of["project_fields","config_fields","cycle_config_fields","cycle_fields"])(a[n]??[]).forEach((a,t)=>{a.aggregate&&s.push({path:`${n}.${t}.aggregate`,message:`${e}.${n}.${a.name}: aggregate is only valid on results_fields`})});(a.results_fields??[]).forEach((a,i)=>{const c=a.aggregate;if(!c||"count"===c.fn)return;const f=c.of?.trim();if(!f)return void s.push({path:`results_fields.${i}.aggregate`,message:`${e}.results_fields.${a.name}: aggregate "${c.fn}" requires a target field (of)`});const r="results"===(c.from??"cycle_fields")?o:t,l="results"===(c.from??"cycle_fields")?"results_fields":"cycle_fields",m=r.get(f);void 0===m?s.push({path:`results_fields.${i}.aggregate`,message:`${e}.results_fields.${a.name}: aggregate "of" references "${f}" which is not a ${l} of this method`}):n.has(m)||s.push({path:`results_fields.${i}.aggregate`,message:`${e}.results_fields.${a.name}: aggregate target "${f}" has non-numeric type "${m}"`})});const i=new Set((a.cycle_fields??[]).map(e=>e.name).filter(Boolean));(a.cycle_config_fields??[]).forEach((a,n)=>{a.name&&i.has(a.name)&&s.push({path:`cycle_config_fields.${n}.name`,message:`${e}: "${a.name}" is declared as both a cycle_config_field and a cycle_field. They share one row namespace; rename one.`})});const c=new Set;for(const e of FIELD_ARRAY_KEYS){(a[e]??[]).forEach(e=>e.name&&c.add(e.name))}for(const e of SERVER_ASSIGNED_CYCLE_COLUMNS)c.add(e);const f=new Set(Object.keys(a.raw_data?.columns??{})),r=e=>e.field&&e.field.trim()?{key:e.field,ok:c.has(e.field)}:e.column&&e.column.trim()?{key:e.column,ok:f.has(e.column)}:null,l=a.views??{};for(const[a,n]of Object.entries(l)){if(n?.x){const t=r(n.x);t&&!t.ok&&s.push({path:`views.${a}.x`,message:`${e}.views.${a}: x.field/column "${t.key}" does not match any field or raw_data column`})}(n?.y??[]).forEach((n,t)=>{const o=r(n);o&&!o.ok&&s.push({path:`views.${a}.y.${t}`,message:`${e}.views.${a}.y[${t}]: field/column "${o.key}" does not match any field or raw_data column`})})}const m=a.raw_data;m&&(m.blob_name&&""!==String(m.blob_name).trim()||s.push({path:"raw_data.blob_name",message:`${e}.raw_data: blob_name is empty`}));const d=new Set((a.config_fields??[]).map(e=>e.name).filter(Boolean)),g=a.configurations??[],u=new Set;return g.forEach((a,n)=>{const t="string"==typeof a?.name?a.name.trim():"";t?u.has(t)?s.push({path:`configurations.${n}.name`,message:`${e}.configurations: duplicate configuration name "${t}"`}):u.add(t):s.push({path:`configurations.${n}.name`,message:`${e}.configurations[${n}]: empty configuration name`});const o=a?.defaults??{};for(const a of Object.keys(o))d.has(a)||s.push({path:`configurations.${n}.defaults.${a}`,message:`${e}.configurations.${t||n}: override "${a}" does not match any config_field`})}),s}export function validateMethods(e){const a={};for(const[s,n]of Object.entries(e)){const e=validateMethod(s,n);e.length>0&&(a[s]=e)}return a}
|