// imports
import dynamic from 'next/dynamic';
import { ErrorBoundary } from 'react-error-boundary';
import React, { useMemo } from 'react';
// locals
import Image from '../components/Image';
import Input from '../components/Input';
import Button from '../components/Button';
import Loading from '../components/Loading';
import NodeBase from '../components/Node/Base';
import ApiSignal from './Api';
import NodeChoose from '../components/Node/Choose';
import ButtonIcon from '../components/Button/Icon';
import Signal, { effect } from '../signal';
import { current as TeamSignal } from './Teams';
// components
import NodeComponents from '../components/Node/Components/index';
// dynamic editor
const Editor = dynamic(() => import('@monaco-editor/react'), {
loading: () =>
,
});
// refreshing
export let refreshing = false;
// uuid
import shortid from 'short-unique-id';
const uid = new shortid({
length : 10,
dictionary : 'hex',
});
// create signal
const NodesSignal = new Signal.State({});
export const ComponentsSignal = new Signal.State({});
// refresh
export const refresh = async () => {
// refreshing
if (refreshing) return;
// refreshing
refreshing = true;
// try
try {
// nodes
const { nodes } = await ApiSignal.get().Node.list({
team : TeamSignal.get()?.id,
limit : 1000,
});
// set nodes
NodesSignal.set(nodes.reduce((accum, node) => {
// set to accum
accum[node.id] = node;
// return accum
return accum;
}, {}));
// set components signal
ComponentsSignal.set([
...(Object.keys(NodesSignal.get()) || []),
'choose',
].reduce((accum, key) => {
// if choose
if (key === 'choose') {
// set accum
accum[key] = (props = {}) => {
// choose node
return (
);
};
} else {
// set accum
accum[key] = (props = {}) => {
// item
const inputs = Object.values([
...(NodesSignal.get()[key].inputs || []),
...(props.data?.inputs || []),
].reduce((accum, input) => {
// set accum
accum[input.id] = input;
// return accum
return accum;
}, {}));
const outputs = Object.values([
...(NodesSignal.get()[key].outputs || []),
...(props.data?.outputs || []),
].reduce((accum, output) => {
// set accum
accum[output.id] = output;
// return accum
return accum;
}, {}));
// string
const ChildComponent = useMemo(() => {
// component
const actualComponent = `(props) => {
const { inputs, outputs, onInputs, onOutputs, variant } = props;
const { uid, Editor, Image, Input, Button, ButtonIcon, Loading, item, node, spec, output, input, onSpec } = props;
const { ${Object.keys(NodeComponents).join(', ')} } = props.Components;
${NodesSignal.get()[key].display}
}`;
// try/catch
try {
// create react element from string
return new Function('React', 'return ' + actualComponent)(React);
} catch (e) {
// log
console.log(e);
// return error
return () => Error
;
}
}, [NodesSignal.get()[key].display]);
// element
const NodeElement = useMemo(() => {
// return new component
return (renderProps = {}) => {
// return jsx
return (
error}>
{
// message
if (renderProps.variant === 'message') return;
// check diff
if (JSON.stringify(renderProps.data?.spec?.[key] || '') === JSON.stringify(value)) return;
// on change
renderProps.data.onChange('spec', {
...(renderProps.data?.spec || {}),
[key] : value,
});
}}
onInputs={(newInputs) => {
// message
if (renderProps.variant === 'message') return;
// on change
renderProps.data.onChange('inputs', [...newInputs]);
}}
onOutputs={(newOutputs) => {
// message
if (renderProps.variant === 'message') return;
// on change
renderProps.data.onChange('outputs', [...newOutputs]);
}}
Components={NodeComponents}
// other elements
uid={uid}
Input={Input}
Image={Image}
Editor={Editor}
Button={Button}
Loading={Loading}
ButtonIcon={ButtonIcon}
/>
);
};
}, [props.id]);
// choose node
return (
);
};
}
// return accum
return accum;
}, {}));
} catch (e) {
// log
console.log(e);
} finally {
// refreshing
refreshing = false;
}
};
// create effect
effect(() => {
// check user id
if (!ApiSignal.get()) return;
if (!TeamSignal.get()?.id) return;
if (typeof window === 'undefined') return;
// refresh
refresh();
});
// export default
export default NodesSignal;