go.charczuk.com@v0.0.0-20240327042549-bc490516bd1a/projects/nodes/static/_nextjs/src/components/editNode.tsx (about) 1 /** 2 * Copyright (c) 2024 - Present. Will Charczuk. All rights reserved. 3 * Use of this source code is governed by a MIT license that can be found in the LICENSE file at the root of the repository. 4 */ 5 import { FormGroup, InputGroup } from "@blueprintjs/core"; 6 import { ReactElement, useEffect, useState } from "react"; 7 import { nodeTypes, valueScalarNumberTypes, valueTypes } from "../refdata/nodeTypes"; 8 import * as api from "../api/nodes"; 9 import { SelectStrings } from "./selectStrings"; 10 import { EditValue } from "./editValue"; 11 import Editor from "@monaco-editor/react"; 12 import * as monaco from "@monaco-editor/react"; 13 14 monaco.loader.config({ 15 paths: { 16 vs: '/public/vs', 17 }, 18 }) 19 20 export interface EditNodeProps { 21 node: api.Node; 22 value?: any; 23 isCreate?: boolean; 24 autoFocus?: boolean; 25 onNodeChanged: (n: api.Node) => void; 26 onValueChanged: (v: api.NativeValueType) => void; 27 } 28 29 const numbers = new Set(valueScalarNumberTypes) 30 31 export function EditNode(props: EditNodeProps) { 32 const [label, setLabel] = useState<string>(props.node.label) 33 const [inputType, setInputType] = useState<string | undefined>(props.node.metadata.input_type) 34 const [outputType, setOutputType] = useState<string | undefined>(props.node.metadata.output_type) 35 const [expression, setExpression] = useState<string | undefined>(props.node.metadata.expression) 36 const [value, setValue] = useState<any | undefined>(props.value); 37 38 useEffect(() => { setLabel(props.node.label) }, [props.node.label]) 39 useEffect(() => { setValue(props.value) }, [props.value]) 40 useEffect(() => { setInputType(props.node.metadata.input_type) }, [props.node.metadata.input_type]) 41 useEffect(() => { setOutputType(props.node.metadata.output_type) }, [props.node.metadata.output_type]) 42 useEffect(() => { setExpression(props.node.metadata.expression) }, [props.node.metadata.expression]) 43 44 const nodeTypeName = props.node.metadata.node_type; 45 const nodeType = nodeTypes[nodeTypeName]; 46 47 const onLabelChange = (e: any) => { 48 setLabel(e.target.value); 49 props.onNodeChanged({ 50 ...props.node, 51 label: e.target.value, 52 }) 53 } 54 const onInputTypeChange = (inputType: string) => { 55 setInputType(inputType); 56 if (nodeType.outputTypeSameAsInput) { 57 setOutputType(inputType); 58 } 59 60 props.onNodeChanged({ 61 ...props.node, 62 metadata: { 63 ...props.node.metadata, 64 input_type: inputType, 65 output_type: nodeType.outputTypeSameAsInput ? inputType : outputType, 66 }, 67 }) 68 } 69 const onOutputTypeChange = (outputType: string) => { 70 setOutputType(outputType); 71 if (numbers.has(outputType)) { 72 setValue(0) 73 props.onValueChanged(0) 74 } 75 props.onNodeChanged({ 76 ...props.node, 77 metadata: { 78 ...props.node.metadata, 79 output_type: outputType, 80 }, 81 }) 82 } 83 const onExpressionChange = (e: string) => { 84 setExpression(e); 85 props.onNodeChanged({ 86 ...props.node, 87 metadata: { 88 ...props.node.metadata, 89 expression: e, 90 } 91 }) 92 } 93 const onValueChanged = (v) => { 94 setValue(v); 95 props.onValueChanged(v); 96 } 97 98 let valueControl: ReactElement | null = null; 99 if (nodeType.showValue && nodeType.canSetValue) { 100 valueControl = (<EditValue tabIndex={0} value={value} valueType={outputType} onValueChanged={onValueChanged} />) 101 } 102 103 return ( 104 <div className="edit-node"> 105 <FormGroup label={"Label"} inline={true} labelFor={"label-value"}> 106 <InputGroup autoFocus={props.autoFocus} tabIndex={0} id="label-value" name={"label"} value={label} onChange={onLabelChange} fill={true} /> 107 </FormGroup> 108 {nodeType.canSetInputType && ( 109 <FormGroup label={"Input Type"} inline={true} labelFor={"input-type-value"}> 110 <SelectStrings tabIndex={0} id="input-type-value" items={nodeType.inputTypes || valueTypes} value={inputType} onItemSelect={onInputTypeChange} disabled={props.isCreate !== true} fill={true} /> 111 </FormGroup> 112 )} 113 {nodeType.canSetOutputType && ( 114 <FormGroup label={"Output Type"} inline={true} labelFor={"output-type-value"}> 115 <SelectStrings tabIndex={0} id="output-type-value" items={nodeType.outputTypes || valueTypes} value={outputType} onItemSelect={onOutputTypeChange} disabled={props.isCreate !== true} fill={true} /> 116 </FormGroup> 117 )} 118 {valueControl} 119 {nodeType.showExpression && nodeType.canSetExpression && ( 120 <FormGroup label={"Expression"} labelInfo={nodeType.expressionRequired ? "(required)" : ""} helperText={nodeType.expressionHelpText}> 121 <Editor 122 height="200px" 123 width="720px" 124 language={nodeType.expressionLanguage || "python"} 125 theme="bp5" 126 onChange={onExpressionChange} 127 value={expression || nodeType.expressionDefault} 128 options={{ 129 formatOnType: true, 130 autoIndent: 'full', 131 renderLineHighlight: 'none', 132 minimap: { 133 enabled: false, 134 }, 135 }} 136 /> 137 </FormGroup> 138 )} 139 </div> 140 ) 141 }