diff --git a/libs/renderer/src/components/block-defaults/index.ts b/libs/renderer/src/components/block-defaults/index.ts index 0912ebdbac..204a427a33 100644 --- a/libs/renderer/src/components/block-defaults/index.ts +++ b/libs/renderer/src/components/block-defaults/index.ts @@ -38,7 +38,10 @@ import { config as IconBlockConfig, IconBlockDef } from "./Icon_block"; import { config as IframeBlockConfig, IframeBlockDef } from "./iframe-block"; import { config as ImageBlockConfig, ImageBlockDef } from "./image-block"; import { config as InputBlockConfig, InputBlockDef } from "./input-block"; -import { config as IterationBlockConfig, IterationBlockDef } from './iteration-block'; +import { + config as IterationBlockConfig, + IterationBlockDef, +} from "./iteration-block"; import { config as LinkBlockConfig, LinkBlockDef } from "./link-block"; import { config as LogsBlockConfig, LogsBlockDef } from "./logs-block"; diff --git a/libs/renderer/src/components/block-defaults/iteration-block/IterationBlock.tsx b/libs/renderer/src/components/block-defaults/iteration-block/IterationBlock.tsx index 5fff2e6a71..505745b9a3 100644 --- a/libs/renderer/src/components/block-defaults/iteration-block/IterationBlock.tsx +++ b/libs/renderer/src/components/block-defaults/iteration-block/IterationBlock.tsx @@ -46,12 +46,12 @@ export const IterationBlock: BlockComponent = observer(({ id }) => { const [blocksToRemove, setBlocksToRemove] = useState([]); - let list + let list; if (typeof data.source === "string") { try { list = JSON.parse(data.source); } catch { - list = data.source + list = data.source; } } @@ -70,10 +70,10 @@ export const IterationBlock: BlockComponent = observer(({ id }) => { message: ActionMessages.REMOVE_BLOCK, payload: { id: b, - keep: false - } - }) - }) + keep: false, + }, + }); + }); list.forEach(async (j, i) => { // Skip the first @@ -118,10 +118,10 @@ export const IterationBlock: BlockComponent = observer(({ id }) => { }, }); - newIds.push(newBlockId) + newIds.push(newBlockId); }); - setBlocksToRemove(newIds) + setBlocksToRemove(newIds); } } // TODO: FIx Dependency array diff --git a/libs/renderer/src/components/block-defaults/iteration-block/config.tsx b/libs/renderer/src/components/block-defaults/iteration-block/config.tsx index fc60bd0d2f..e4575fc272 100644 --- a/libs/renderer/src/components/block-defaults/iteration-block/config.tsx +++ b/libs/renderer/src/components/block-defaults/iteration-block/config.tsx @@ -1,14 +1,16 @@ -import { CSSProperties } from "react"; -import { BlockConfig } from "../../../store"; -import { ChildBlockSettings, InputSettings, QueryInputSettings, QuerySelectionSettings } from "../../block-settings"; -import { IterationBlockDef, IterationBlock } from "./IterationBlock"; -import { buildLayoutSection, buildListener, buildShowField } from "../block-defaults.shared"; import { FormatShapes } from "@mui/icons-material"; + +import { IterationBlockDef, IterationBlock } from "./IterationBlock"; import { BLOCK_TYPE_INPUT } from "../block-defaults.constants"; -import { SelectInputSettings } from "../../block-settings/shared/SelectInputSettings"; -import { InputModalSettings } from "../../block-settings/shared/InputModalSettings"; -import { useBlock } from "@/hooks"; +import { BlockConfig } from "../../../store"; +import { + buildLayoutSection, + buildShowField, +} from "../block-defaults.shared"; +import { + QueryInputSettings, +} from "../../block-settings"; // export the config for the block export const config: BlockConfig = { @@ -18,7 +20,7 @@ export const config: BlockConfig = { style: {}, source: "", child: null, - show: "true" + show: "true", }, listeners: {}, slots: { @@ -29,9 +31,7 @@ export const config: BlockConfig = { contentMenu: [ { name: "Conditional", - children: [ - ...buildShowField(), - ], + children: [...buildShowField()], }, { name: "Data Source", @@ -39,7 +39,11 @@ export const config: BlockConfig = { { description: "Data Source", render: ({ id }) => ( - + ), }, ], @@ -56,7 +60,5 @@ export const config: BlockConfig = { // ], // }, ], - styleMenu: [ - buildLayoutSection(), - ], + styleMenu: [buildLayoutSection()], }; diff --git a/libs/renderer/src/components/block-defaults/iteration-block/index.ts b/libs/renderer/src/components/block-defaults/iteration-block/index.ts index 53832be4c9..ac8337a977 100644 --- a/libs/renderer/src/components/block-defaults/iteration-block/index.ts +++ b/libs/renderer/src/components/block-defaults/iteration-block/index.ts @@ -1,2 +1,2 @@ -export * from './IterationBlock'; -export * from './config'; \ No newline at end of file +export * from "./IterationBlock"; +export * from "./config"; diff --git a/libs/renderer/src/components/block-defaults/llm-comparison-block/context/LLMComparisonContext.tsx b/libs/renderer/src/components/block-defaults/llm-comparison-block/context/LLMComparisonContext.tsx index 8553dfaea0..6b3d1fe004 100644 --- a/libs/renderer/src/components/block-defaults/llm-comparison-block/context/LLMComparisonContext.tsx +++ b/libs/renderer/src/components/block-defaults/llm-comparison-block/context/LLMComparisonContext.tsx @@ -22,7 +22,10 @@ export type LLMComparisonContextType = { watch: (str: string) => unknown; - handleSubmit: UseFormHandleSubmit; + handleSubmit: UseFormHandleSubmit< + TypeLlmComparisonForm, + TypeLlmComparisonForm + >; /** All Models available for configuring variants */ allModels: TypeLlmConfig[]; diff --git a/libs/renderer/src/components/block-settings/custom/ChildBlockSettings.tsx b/libs/renderer/src/components/block-settings/custom/ChildBlockSettings.tsx index ce7cb67587..5827699d58 100644 --- a/libs/renderer/src/components/block-settings/custom/ChildBlockSettings.tsx +++ b/libs/renderer/src/components/block-settings/custom/ChildBlockSettings.tsx @@ -1,10 +1,22 @@ import React, { useState, useEffect } from "react"; import { Add, Edit } from "@mui/icons-material"; -import { Button, IconButton, LoadingScreen, Modal, Stack, Typography } from "@semoss/ui"; +import { + Button, + IconButton, + LoadingScreen, + Modal, + Stack, + Typography, +} from "@semoss/ui"; import { Env, InsightProvider, runPixel } from "@semoss/sdk"; -import { BlockDef, SerializedState, STATE_VERSION, StateStore } from "../../../store"; +import { + BlockDef, + SerializedState, + STATE_VERSION, + StateStore, +} from "../../../store"; import { useBlock } from "../../../hooks"; import { DefaultCells } from "../../cell-defaults"; import { DefaultBlocks } from "../../block-defaults"; @@ -17,26 +29,26 @@ interface ChildBlockSettingsProps { const STATE = { blocks: { "container-5656": { - id: 'container-5656', + id: "container-5656", widget: "container", parent: null, data: { style: { - border: 'solid red' + border: "solid red", }, show: "true", }, listeners: {}, slots: { - children: [] + children: [], }, - } - }, + }, + }, variables: {}, queries: {}, executionOrder: [], version: STATE_VERSION, -} +}; export const ChildBlockSettings = (props: ChildBlockSettingsProps) => { const { id } = props; @@ -45,11 +57,8 @@ export const ChildBlockSettings = (props: ChildBlockSettingsProps) => { const [state, setState] = useState(); useEffect(() => { - runPixel<[SerializedState]>( - `1+1`, - 'new', - ) - .then(async ({ pixelReturn, errors, insightId }) => { + runPixel<[SerializedState]>(`1+1`, "new").then( + async ({ pixelReturn, errors, insightId }) => { // create a new state store // const s = new StateStore({ // mode: 'static', @@ -57,22 +66,21 @@ export const ChildBlockSettings = (props: ChildBlockSettingsProps) => { // state: STATE, // cellRegistry: DefaultCells, // }); - // set it // setState(s); - - }) - }, []) + }, + ); + }, []); if (!state) { - return <>Loading... + return <>Loading...; } /** * Initialize insight for app building */ Env.update({ - MODULE: process.env.MODULE || '', + MODULE: process.env.MODULE || "", }); return ( @@ -112,12 +120,12 @@ export const ChildBlockSettings = (props: ChildBlockSettingsProps) => { <>Show Preview of Block {/* */} - {/* */} - {/* + {/* diff --git a/libs/renderer/src/components/block-settings/custom/index.ts b/libs/renderer/src/components/block-settings/custom/index.ts index b34cbacd14..9578d6c255 100644 --- a/libs/renderer/src/components/block-settings/custom/index.ts +++ b/libs/renderer/src/components/block-settings/custom/index.ts @@ -13,4 +13,4 @@ export { IconSelectSettings } from "./IconSelectSettings"; export { QueryInputSettings } from "./QueryInputSettings"; export { OptionsSettings } from "./OptionsSettings"; export { ChipSettings } from "./ChipSettings"; -export { ChildBlockSettings } from "./ChildBlockSettings" +export { ChildBlockSettings } from "./ChildBlockSettings"; diff --git a/libs/renderer/src/hooks/useBlock.tsx b/libs/renderer/src/hooks/useBlock.tsx index 92ab7c9968..89bf2fe721 100644 --- a/libs/renderer/src/hooks/useBlock.tsx +++ b/libs/renderer/src/hooks/useBlock.tsx @@ -211,7 +211,10 @@ export const useBlock = ( // try to extract the variable // debugger - return state.parseVariable(instance, block.widget !== 'iteration' ? block.id : null); + return state.parseVariable( + instance, + block.widget !== "iteration" ? block.id : null, + ); } return instance; diff --git a/libs/renderer/src/index.ts b/libs/renderer/src/index.ts index baef121bd2..97156bf537 100644 --- a/libs/renderer/src/index.ts +++ b/libs/renderer/src/index.ts @@ -41,6 +41,8 @@ export type { VariableWithId, CellState, NewCellAction, + Block, + QueryStateConfig } from "./store"; // REGISTRY AND MENUS diff --git a/libs/renderer/src/store/state/cell.state.ts b/libs/renderer/src/store/state/cell.state.ts index 33e9d227df..ea706e6374 100644 --- a/libs/renderer/src/store/state/cell.state.ts +++ b/libs/renderer/src/store/state/cell.state.ts @@ -285,7 +285,11 @@ export class CellState { }); }); // Currently console does not get pass STREAMING - if (status === "ProgressComplete" || status === "Streaming" || status === "Complete") { + if ( + status === "ProgressComplete" || + status === "Streaming" || + status === "Complete" + ) { isPolling = false; } else { // poll @@ -382,7 +386,6 @@ export class CellState { }); } - // process side effects from running a pixel this._state.processSideEffects(this.operation, this.output); } catch (e) { diff --git a/libs/renderer/src/store/state/state.store.ts b/libs/renderer/src/store/state/state.store.ts index 800805617f..0ee1b2b2f6 100644 --- a/libs/renderer/src/store/state/state.store.ts +++ b/libs/renderer/src/store/state/state.store.ts @@ -500,52 +500,58 @@ export class StateStore { let cleaned = expression.trim(); // Checks if it falls inline with special syntax - if (!cleaned.startsWith("{{") && !cleaned.endsWith("}}") && !cleaned.startsWith("$")) { + if ( + !cleaned.startsWith("{{") && + !cleaned.endsWith("}}") && + !cleaned.startsWith("$") + ) { return expression; } // Special Parsing for Iterators - if(cleaned.startsWith("$")) { + if (cleaned.startsWith("$")) { // See if id is a descendant of an iterator block - const iteratorBlock = this.isDescendantOfIterator(id) + const iteratorBlock = this.isDescendantOfIterator(id); if (iteratorBlock) { try { // Go see what index the iterator block children this id is a descendant of - const index = this.findIteratorChildIndex(iteratorBlock, id) - const iteratorList = iteratorBlock.data.source as string - let list = this.parseVariable(iteratorList) - - if(typeof list === 'string') { + const index = this.findIteratorChildIndex( + iteratorBlock, + id, + ); + const iteratorList = iteratorBlock.data.source as string; + let list = this.parseVariable(iteratorList); + + if (typeof list === "string") { try { - list = JSON.parse(list) + list = JSON.parse(list); } catch { - return expression + return expression; } } - + const variable = expression.match(/\$(.*?)\./)[1]; const stripped = iteratorList.slice(2, -2); - + // TODO: how do we handle nested loops $array.warehouse.warehouseSections // Do we just call this recursively if (variable === stripped) { - const path = expression.split(".").splice(1) - const test = path.join(".") - const val = getValueByPath(list[index], test) + const path = expression.split(".").splice(1); + const test = path.join("."); + const val = getValueByPath(list[index], test); // SHOW "" or expression - return val ? val : '' + return val ? val : ""; } else { - return expression + return expression; } - } catch { - return expression + return expression; } } else { - console.warn(`Unable to find iterator descendant - ${id}: `) - return expression + console.warn(`Unable to find iterator descendant - ${id}: `); + return expression; } } @@ -717,12 +723,12 @@ export class StateStore { }; private isDescendantOfIterator = (blockId: string) => { - console.warn(`Is ${blockId} a descendant of an iterator` ) + console.warn(`Is ${blockId} a descendant of an iterator`); let currentBlock = this._store.blocks[blockId]; while (currentBlock) { - if (currentBlock.widget === 'iteration') { + if (currentBlock.widget === "iteration") { return currentBlock; } if (currentBlock.parent && currentBlock.parent.id) { @@ -731,50 +737,49 @@ export class StateStore { break; } } - - return false; - } + return false; + }; private isDescendant = (containerId, blockId) => { const container = this._store.blocks[containerId]; - + // TODO: may need to fix if (!container || !container.slots || !container.slots.children) { return false; } - + // TODO: will it always be .children? --> Accordion .content and .header const children = container.slots.children.children; if (children.includes(blockId)) { return true; } - + for (const childId of children) { if (this.isDescendant(childId, blockId)) { return true; } } - + return false; - } + }; private findIteratorChildIndex = (iteratorBlock, blockId) => { const children = iteratorBlock.slots.children.children; - + for (let i = 0; i < children.length; i++) { const iteratorChildId = children[i]; // No need to search tree - if(iteratorChildId === blockId) return i + if (iteratorChildId === blockId) return i; if (this.isDescendant(iteratorChildId, blockId)) { return i; } } - + return -1; // Return -1 if not found - } + }; /** * Check if a parent contains the child block diff --git a/packages/client/src/components/app/NewAppModal.tsx b/packages/client/src/components/app/NewAppModal.tsx index 8078e22f30..268132b893 100644 --- a/packages/client/src/components/app/NewAppModal.tsx +++ b/packages/client/src/components/app/NewAppModal.tsx @@ -1,4 +1,6 @@ import { useMemo, useState } from 'react'; +import { Controller, useForm } from 'react-hook-form'; + import { Button, TextField, @@ -10,8 +12,8 @@ import { styled, Autocomplete, } from '@semoss/ui'; -import { Controller, useForm } from 'react-hook-form'; -import { SerializedState } from '@/stores'; +import { SerializedState } from '@semoss/renderer'; + import { useRootStore } from '@/hooks'; import { AppMetadata } from './app.types'; diff --git a/packages/client/src/components/app/templates/AskCSVTemplate.tsx b/packages/client/src/components/app/templates/AskCSVTemplate.tsx index e259b5a4a8..ffea98424c 100644 --- a/packages/client/src/components/app/templates/AskCSVTemplate.tsx +++ b/packages/client/src/components/app/templates/AskCSVTemplate.tsx @@ -1,6 +1,5 @@ -import { ActionMessages } from '@/stores'; -import QUERY from '@/assets/img/query.jpeg'; import { + ActionMessages, ButtonBlockConfig, ContainerBlockConfig, UploadBlockConfig, @@ -10,6 +9,7 @@ import { } from '@semoss/renderer'; import { Template } from './templates.types'; +import QUERY from '@/assets/img/query.jpeg'; export const AskCSVTemplate: Template = { name: 'Ask CSV', diff --git a/packages/client/src/components/app/templates/AskLLMTemplate.ts b/packages/client/src/components/app/templates/AskLLMTemplate.ts index f0de378368..68ef539fe0 100644 --- a/packages/client/src/components/app/templates/AskLLMTemplate.ts +++ b/packages/client/src/components/app/templates/AskLLMTemplate.ts @@ -1,4 +1,5 @@ -import { ActionMessages } from '@/stores'; +import { ActionMessages } from '@semoss/renderer'; + import { Template } from './templates.types'; import CHATAI from '@/assets/img/query.jpeg'; diff --git a/packages/client/src/components/app/templates/BlocksGuideTemplate.ts b/packages/client/src/components/app/templates/BlocksGuideTemplate.ts index 95e70a0036..31661b7fce 100644 --- a/packages/client/src/components/app/templates/BlocksGuideTemplate.ts +++ b/packages/client/src/components/app/templates/BlocksGuideTemplate.ts @@ -1,4 +1,5 @@ -import { ActionMessages } from '@/stores'; +import { ActionMessages } from '@semoss/renderer'; + import { Template } from './templates.types'; import LANDINGPAGE from '@/assets/img/query.jpeg'; diff --git a/packages/client/src/components/app/templates/CreateDiabetesRecordTemplate.ts b/packages/client/src/components/app/templates/CreateDiabetesRecordTemplate.ts index 50325e4b9a..e7ac0e2f57 100644 --- a/packages/client/src/components/app/templates/CreateDiabetesRecordTemplate.ts +++ b/packages/client/src/components/app/templates/CreateDiabetesRecordTemplate.ts @@ -1,4 +1,5 @@ -import { ActionMessages } from '@/stores'; +import { ActionMessages } from '@semoss/renderer'; + import { Template } from './templates.types'; import CHATAI from '@/assets/img/query.jpeg'; diff --git a/packages/client/src/components/app/templates/DeleteDiabetesRecordTemplate.ts b/packages/client/src/components/app/templates/DeleteDiabetesRecordTemplate.ts index 6a4457f5dd..8abbc2e525 100644 --- a/packages/client/src/components/app/templates/DeleteDiabetesRecordTemplate.ts +++ b/packages/client/src/components/app/templates/DeleteDiabetesRecordTemplate.ts @@ -1,4 +1,5 @@ -import { ActionMessages } from '@/stores'; +import { ActionMessages } from '@semoss/renderer'; + import { Template } from './templates.types'; import CHATAI from '@/assets/img/query.jpeg'; diff --git a/packages/client/src/components/app/templates/ReadDiabetesRecordTemplate.ts b/packages/client/src/components/app/templates/ReadDiabetesRecordTemplate.ts index 2e184cbf34..666628156a 100644 --- a/packages/client/src/components/app/templates/ReadDiabetesRecordTemplate.ts +++ b/packages/client/src/components/app/templates/ReadDiabetesRecordTemplate.ts @@ -1,4 +1,5 @@ -import { ActionMessages } from '@/stores'; +import { ActionMessages } from '@semoss/renderer'; + import { Template } from './templates.types'; import CHATAI from '@/assets/img/query.jpeg'; diff --git a/packages/client/src/components/app/templates/UpdateDiabetesRecordTemplate.ts b/packages/client/src/components/app/templates/UpdateDiabetesRecordTemplate.ts index 136b640109..27d11a91c7 100644 --- a/packages/client/src/components/app/templates/UpdateDiabetesRecordTemplate.ts +++ b/packages/client/src/components/app/templates/UpdateDiabetesRecordTemplate.ts @@ -1,4 +1,5 @@ -import { ActionMessages } from '@/stores'; +import { ActionMessages } from '@semoss/renderer'; + import { Template } from './templates.types'; import CHATAI from '@/assets/img/query.jpeg'; diff --git a/packages/client/src/components/app/templates/templates.types.ts b/packages/client/src/components/app/templates/templates.types.ts index acf4d8d28f..72e4ff62ed 100644 --- a/packages/client/src/components/app/templates/templates.types.ts +++ b/packages/client/src/components/app/templates/templates.types.ts @@ -1,4 +1,4 @@ -import { SerializedState } from '@/stores'; +import { SerializedState } from '@semoss/renderer'; export type Template = { /** Name of the template */ diff --git a/packages/client/src/components/designer/BlockSettingsMask.tsx b/packages/client/src/components/designer/BlockSettingsMask.tsx index b50ca9c223..80c28f301a 100644 --- a/packages/client/src/components/designer/BlockSettingsMask.tsx +++ b/packages/client/src/components/designer/BlockSettingsMask.tsx @@ -13,13 +13,17 @@ const STYLED_FONT_SIZE_INPUT_WIDTH = 168; const StyledContainer = styled('div')(({ theme }) => ({ position: 'absolute', - padding: theme.spacing(2), + padding: theme.spacing(1, 0, 0, 2), top: '0', right: '0', bottom: '0', left: '0', zIndex: '30', height: 'fit-content', + maxWidth: `${ + STYLED_FONT_STYLE_INPUT_WIDTH + STYLED_FONT_SIZE_INPUT_WIDTH + }px`, + minWidth: 'fit-content', })); interface FontStyleSizeMaskProps { diff --git a/packages/client/src/components/designer/QueryMenuItem.tsx b/packages/client/src/components/designer/QueryMenuItem.tsx deleted file mode 100644 index 71b3fd0655..0000000000 --- a/packages/client/src/components/designer/QueryMenuItem.tsx +++ /dev/null @@ -1,192 +0,0 @@ -import { useEffect, useState, useCallback } from 'react'; -import { Chip, List, Typography, styled } from '@semoss/ui'; -import { useBlocks, useWorkspace, useDesigner } from '@/hooks'; -import { ActionMessages, QueryState, BlockJSON } from '@/stores'; - -const StyledListItem = styled(List.Item)(() => ({ - padding: '0px 4px', -})); - -const StyledListItemText = styled(List.ItemText)(() => ({ - overflow: 'hidden', - textOverflow: 'ellipsis', -})); - -const StyledSuccessChip = styled(Chip)(({ theme }) => ({ - backgroundColor: '#E7F4E5', - color: theme.palette.success.main, -})); - -const StyledErrorChip = styled(Chip)(({ theme }) => ({ - backgroundColor: '#FBE9E8', - color: theme.palette.error.main, -})); - -interface QueryMenuItemProps { - query: QueryState; -} - -export const QueryMenuItem = (props: QueryMenuItemProps) => { - const { query } = props; - const { notebook, state } = useBlocks(); - const { workspace } = useWorkspace(); - const { designer } = useDesigner(); - - // We can provide different options for user to display this data, - // Or we can take a look at the data if it's there and render a better block for it - const json: BlockJSON = { - widget: 'text', - data: { - text: `{{${query.id}.data}}`, - }, - slots: {} as BlockJSON['slots'], - listeners: {}, - }; - - // track if it is this one that is dragging - const [local, setLocal] = useState(false); - - /** - * Handle the mousedown on the widget. - */ - const handleMouseDown = () => { - // set the dragged - designer.activateDrag( - 'text', - () => { - return true; - }, - 'text', - // getIconForMenuItemByKey('text'), - ); - - // clear the hovered - designer.setHovered(''); - - // clear the selected - designer.setSelected(''); - - // set as inactive - setLocal(true); - }; - - /** - * Handle the mouseup event on the document - */ - const handleDocumentMouseUp = useCallback(() => { - if (!designer.drag.active) { - return; - } - - // apply the action - const placeholderAction = designer.drag.placeholderAction; - - if (placeholderAction) { - if ( - placeholderAction.type === 'before' || - placeholderAction.type === 'after' - ) { - const siblingWidget = state.getBlock(placeholderAction.id); - - if (siblingWidget?.parent) { - state.dispatch({ - message: ActionMessages.ADD_BLOCK, - payload: { - json: json, - position: { - parent: siblingWidget.parent.id, - slot: siblingWidget.parent.slot, - sibling: siblingWidget.id, - type: placeholderAction.type, - }, - }, - }); - } - } else if (placeholderAction.type === 'replace') { - state.dispatch({ - message: ActionMessages.ADD_BLOCK, - payload: { - json: json, - position: { - parent: placeholderAction.id, - slot: placeholderAction.slot, - }, - }, - }); - } - } - - // clear the drag - designer.deactivateDrag(); - - // clear the hovered - designer.setHovered(''); - - // clear the selected - designer.setSelected(''); - - // set as active - setLocal(false); - }, [ - json, - designer.drag.active, - designer.drag.placeholderAction, - designer, - state, - ]); - - // add the mouse up listener when dragged - useEffect(() => { - if (!designer.drag.active || !local) { - return; - } - - document.addEventListener('mouseup', handleDocumentMouseUp); - - return () => { - document.removeEventListener('mouseup', handleDocumentMouseUp); - }; - }, [designer.drag.active, local, handleDocumentMouseUp]); - - return ( - - { - // select the active panel - // workspace.selectPanel('notebook'); - - // select the query - notebook.selectQuery(query.id); - }} - > - {query.id} - } - secondary={ - - {query.isLoading ? ( - Loading... - ) : query.output ? ( - query.isSuccessful ? ( - - ) : ( - - ) - ) : ( - Query not yet executed - )} - - } - /> - - - ); -}; diff --git a/packages/client/src/components/designer/settings-mask/TextSettingsMask.tsx b/packages/client/src/components/designer/settings-mask/TextSettingsMask.tsx index a26b2579b6..40478cccaf 100644 --- a/packages/client/src/components/designer/settings-mask/TextSettingsMask.tsx +++ b/packages/client/src/components/designer/settings-mask/TextSettingsMask.tsx @@ -6,9 +6,6 @@ import { ActionMessages, useBlocks } from '@semoss/renderer'; import { useDesigner } from '@/hooks'; -const STYLED_FONT_STYLE_INPUT_WIDTH = 232; -const STYLED_FONT_SIZE_INPUT_WIDTH = 168; - const StyledInputContainer = styled('div')(({ theme }) => ({ display: 'flex', alignItems: 'center', @@ -18,10 +15,6 @@ const StyledInputContainer = styled('div')(({ theme }) => ({ backgroundColor: 'white', padding: theme.spacing(1), borderRadius: theme.shape.borderRadius, - maxWidth: `${ - STYLED_FONT_STYLE_INPUT_WIDTH + STYLED_FONT_SIZE_INPUT_WIDTH - }px`, - minWidth: 'fit-content', })); const FontStyleOptions = [ diff --git a/packages/client/src/components/notebook/NewCellOverlay.tsx b/packages/client/src/components/notebook/NewCellOverlay.tsx index 753c984e05..42f3941119 100644 --- a/packages/client/src/components/notebook/NewCellOverlay.tsx +++ b/packages/client/src/components/notebook/NewCellOverlay.tsx @@ -8,7 +8,7 @@ import { ActionMessages, DefaultCells, useBlocks } from '@semoss/renderer'; /** * TODO: DOES THIS NEED TO BE REMOVED */ -import { NewCellAction } from '@/stores'; +import { NewCellAction } from '@semoss/renderer'; type NewCellForm = { ID: string; diff --git a/packages/client/src/components/notebook/NotebookAddCell.tsx b/packages/client/src/components/notebook/NotebookAddCell.tsx index e38eca94b0..b3eb27daf6 100644 --- a/packages/client/src/components/notebook/NotebookAddCell.tsx +++ b/packages/client/src/components/notebook/NotebookAddCell.tsx @@ -1,5 +1,14 @@ import { useState } from 'react'; import { observer } from 'mobx-react-lite'; +import { + ChangeCircleOutlined, + Code, + ImportExport, + KeyboardArrowDown, + KeyboardArrowUp, + TextFields, +} from '@mui/icons-material'; + import { styled, Button, @@ -9,7 +18,6 @@ import { Stack, Modal, } from '@semoss/ui'; - import { useBlocks, ActionMessages, @@ -21,18 +29,9 @@ import { QueryImportCellConfig, CodeCellConfig, DataImportFormModal, + NewCellAction, } from '@semoss/renderer'; -import { NewCellAction } from '@/stores'; -import { - ChangeCircleOutlined, - Code, - ImportExport, - KeyboardArrowDown, - KeyboardArrowUp, - TextFields, -} from '@mui/icons-material'; - import { ModelBrain } from '@/assets/img/ModelBrain'; const StyledButton = styled(Button)(({ theme }) => ({ diff --git a/packages/client/src/components/prompt/prompt.helpers.ts b/packages/client/src/components/prompt/prompt.helpers.ts index 465e2531bc..7b8e2308a4 100644 --- a/packages/client/src/components/prompt/prompt.helpers.ts +++ b/packages/client/src/components/prompt/prompt.helpers.ts @@ -7,13 +7,15 @@ import { INPUT_TYPE_CUSTOM_QUERY, INPUT_TYPE_DATABASE, } from './prompt.constants'; + +import { MonolithStore } from '@/stores'; import { ActionMessages, Block, - MonolithStore, QueryStateConfig, SerializedState, -} from '@/stores'; +} from '@semoss/renderer'; + import { AppMetadata } from '../app'; export const DESCRIPTION_CONTAINER = 'description-container'; diff --git a/packages/client/src/contexts/Blocks.context copy.tsx b/packages/client/src/contexts/Blocks.context copy.tsx deleted file mode 100644 index bcfd0f51e8..0000000000 --- a/packages/client/src/contexts/Blocks.context copy.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { createContext } from 'react'; -import { StateStore, Registry } from '@/stores'; - -export interface BlocksContextProps { - /** Widgets available to all of the blocks */ - registry: Registry; - - /** Store to provide */ - state: StateStore; -} - -/** - * Insight Context - */ -export const BlocksContext = createContext( - undefined, -); diff --git a/packages/client/src/contexts/Blocks.context.tsx b/packages/client/src/contexts/Blocks.context.tsx deleted file mode 100644 index 3a055f9464..0000000000 --- a/packages/client/src/contexts/Blocks.context.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { createContext } from 'react'; -import { StateStore, Registry, NotebookStore } from '@/stores'; - -export interface BlocksContextProps { - /** Widgets available to all of the blocks */ - registry: Registry; - - /** State to provide */ - state: StateStore; - - /** notebook helpers */ - notebook: NotebookStore; -} - -/** - * Insight Context - */ -export const BlocksContext = createContext( - undefined, -); diff --git a/packages/client/src/contexts/LLMComparisonContext.tsx b/packages/client/src/contexts/LLMComparisonContext.tsx deleted file mode 100644 index 83a2b91cdf..0000000000 --- a/packages/client/src/contexts/LLMComparisonContext.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { createContext } from 'react'; -import { Control } from 'react-hook-form'; - -export type LLMComparisonContextType = { - /** Block's ID from the App's JSON */ - blockId: string; - - /** React Hook Form methods stored for nested components' access */ - control: Control | null; - getValues: null | ((str?: string) => any); - setValue: null | ((str: string, val: any) => void); - watch: any; - handleSubmit: any; - - /** All Models available for configuring variants */ - allModels: any; -}; - -export const LLMComparisonContext = - createContext(undefined); diff --git a/packages/client/src/contexts/index.ts b/packages/client/src/contexts/index.ts index e72a92ca0c..ac29711adb 100644 --- a/packages/client/src/contexts/index.ts +++ b/packages/client/src/contexts/index.ts @@ -1,4 +1,3 @@ -import { BlocksContext } from './Blocks.context'; import { DesignerContextType, DesignerContext } from './DesignerContext'; import { EngineContextType, EngineContext } from './EngineContext'; import { LLMContext, LLMContextType } from './LLMContext'; @@ -7,10 +6,6 @@ import { SettingsContextType, SettingsContext } from './SettingsContext'; import { RootStoreContextType, RootStoreContext } from './RootStoreContext'; import { StepperContext, StepperContextType } from './StepperContext'; import { WorkspaceContextProps, WorkspaceContext } from './WorkspaceContext'; -import { - LLMComparisonContextType, - LLMComparisonContext, -} from './LLMComparisonContext'; export type { DesignerContextType, @@ -21,11 +16,9 @@ export type { SettingsContextType, StepperContextType, WorkspaceContextProps, - LLMComparisonContextType, }; export { - BlocksContext, DesignerContext, EngineContext, LLMContext, @@ -34,5 +27,4 @@ export { SettingsContext, StepperContext, WorkspaceContext, - LLMComparisonContext, }; diff --git a/packages/client/src/hooks/index.ts b/packages/client/src/hooks/index.ts index 0414b12466..0801ce7a29 100644 --- a/packages/client/src/hooks/index.ts +++ b/packages/client/src/hooks/index.ts @@ -1,12 +1,6 @@ import { useAPI } from './useAPI'; -import { useBlock } from './useBlock'; -import { useBlocks } from './useBlocks'; -import { useBlocksPixel } from './useBlocksPixel'; -import { useBlockSettings } from './useBlockSettings'; import { useCacheState } from './useCacheState'; import { useEngine } from './useEngine'; -import { useFrame } from './useFrame'; -import { useFrameHeaders } from './useFrameHeaders'; import { useLLM } from './useLLM'; import { useMetamodel } from './useMetamodel'; import { useRootStore } from './useRootStore'; @@ -15,21 +9,13 @@ import { usePixel } from './usePixel'; import { useDesigner } from './useDesigner'; import { useStepper } from './useStepper'; import { useWorkspace } from './useWorkspace'; -import { useLLMComparison } from './useLLMCompare'; import { useDebounce } from './useDebounce'; import { useDebounceValue } from './useDebounceValue'; -import { useTypeWriter } from './useTypeWriter'; export { useAPI, - useBlock, - useBlocks, - useBlocksPixel, - useBlockSettings, useCacheState, useEngine, - useFrame, - useFrameHeaders, useLLM, useMetamodel, useRootStore, @@ -38,8 +24,6 @@ export { useDesigner, useStepper, useWorkspace, - useLLMComparison, useDebounce, useDebounceValue, - useTypeWriter, }; diff --git a/packages/client/src/hooks/useBlock.tsx b/packages/client/src/hooks/useBlock.tsx deleted file mode 100644 index 04a7fddbb1..0000000000 --- a/packages/client/src/hooks/useBlock.tsx +++ /dev/null @@ -1,230 +0,0 @@ -import { useCallback, useMemo } from 'react'; -import { computed } from 'mobx'; - -import { upload } from '@/api'; -import { Paths, PathValue } from '@/types'; -import { ActionMessages, Block, BlockDef, ListenerActions } from '@/stores'; -import { copy } from '@/utility'; - -import { useBlocks } from './useBlocks'; - -/** - * useBlockReturn - */ -interface useBlockReturn { - /** Data for the block */ - data: Block['data']; - - /** Listeners on the block */ - listeners: Record< - keyof Block['listeners'], - ( - intercept?: (action: ListenerActions) => ListenerActions | null, - ) => void - >; - - /** Slots */ - slots: Block['slots']; - - /** Attributes to add to the block */ - attrs: { - /** block id of the block */ - 'data-block': string; - }; - - /** - * Dispatch a message to set data - * @param path - path of the data to set - * @param value - value of the data to set - */ - setData:

['data'], 4>>( - path: P, - value: PathValue, - tempOverrideMode?: boolean, - ) => void; - - /** - * Dispatch a message to delete data - * @param path - path of the data to delete - */ - deleteData:

['data'], 4>>(path: P) => void; - - /** - * Upload a file to the insight - * @param file - file(s) to upload to the insight - */ - uploadFile: (file: File | File[]) => Promise< - | { - fileName: string; - fileLocation: string; - }[] - | false - >; -} - -/** - * Access methods for the block. This should only be used by blocks. - */ -export const useBlock = ( - id: string, -): useBlockReturn => { - // get the store - const { state } = useBlocks(); - - // get the block - const block = state.getBlock(id); - - // get block - if (!block) { - throw Error(`Cannot find block ${id}`); - } - - /** - * Dispatch a message to set data - * @param path - path of the data to set - * @param value - value of the data to set - */ - const setData = useCallback( -

['data'], 4>>( - path: P | null, - value: PathValue['data'], P>, - // TODO: will remove this; needed to update LLM blocks for now. - tempOverrideMode?: boolean, - ): void => { - // ignore if static - if (!tempOverrideMode && state.mode === 'static') { - return; - } - - state.dispatch({ - message: ActionMessages.SET_BLOCK_DATA, - payload: { - id: id, - path: path, - value: value, - }, - }); - }, - [], - ); - - /** - * Dispatch a message to delete data - * @param path - path of the data to delete - */ - const deleteData = useCallback( -

['data'], 4>>(path: P | null): void => { - // ignore if static - if (state.mode === 'static') { - return; - } - - state.dispatch({ - message: ActionMessages.DELETE_BLOCK_DATA, - payload: { - id: id, - path: path, - }, - }); - }, - [], - ); - - // TODO: Dispatch as an action? - /** - * Upload a file to the insight - * @param file - file(s) to upload to the insight - */ - const uploadFile = useCallback( - async ( - file: File | File[], - ): Promise< - | { - fileName: string; - fileLocation: string; - }[] - | false - > => { - // ignore if static - if (state.mode === 'static') { - return false; - } - - const f = Array.isArray(file) ? file : [file]; - - // upload the file - return await upload(f, state.insightId, '', ''); - }, - [], - ); - - // construct the listeners to add to the widget - const listeners = useMemo(() => { - /** - * Dispatch a message to delete data - * @param actions - Actions to dispatch - * @param intercept - Intercept and modify an action - */ - const dispatchAction = ( - actions: ListenerActions[], - intercept?: (action: ListenerActions) => ListenerActions | null, - ) => { - // ignore if static - if (state.mode === 'static') { - return; - } - - // go through each one and trigger it - actions.forEach((a) => { - // convert back to a normal action - let action: ListenerActions | null = a; - - // allow the action to be intercepted before dispatch - if (intercept) { - action = intercept(action); - } - - if (action === null) { - return; - } - - state.dispatch(action); - }); - }; - - // create the listeners - return Object.keys(block.listeners).reduce((acc, val) => { - acc[val as keyof Block['listeners']] = dispatchAction.bind( - null, - block.listeners[val], - ); - - return acc; - }, {} as useBlockReturn['listeners']); - }, [JSON.stringify(block.listeners)]); - - // render the data. It is wrapped in a computed, so it's cached - const data = computed(() => { - return copy(block.data, (instance) => { - if (typeof instance === 'string') { - // try to extract the variable - - return state.parseVariable(instance); - } - - return instance; - }); - }).get(); - - return { - data: data, - listeners: listeners, - slots: block.slots, - attrs: { - 'data-block': block.id, - }, - setData: setData, - deleteData: deleteData, - uploadFile: uploadFile, - }; -}; diff --git a/packages/client/src/hooks/useBlockSettings.tsx b/packages/client/src/hooks/useBlockSettings.tsx deleted file mode 100644 index 87c31e707e..0000000000 --- a/packages/client/src/hooks/useBlockSettings.tsx +++ /dev/null @@ -1,130 +0,0 @@ -import { useCallback } from 'react'; - -import { Paths, PathValue } from '@/types'; -import { ActionMessages, Block, BlockDef, ListenerActions } from '@/stores'; - -import { useBlocks } from './useBlocks'; - -/** - * useBlockSettingsReturn - */ -interface useBlockSettingsReturn { - /** Data for the block */ - data: Block['data']; - - /** Data for the block */ - listeners: Block['listeners']; - - /** - * Dispatch a message to set data - * @param path - path of the data to set - * @param value - value of the data to set - */ - setData:

['data'], 4>>( - path: P, - value: PathValue, - ) => void; - - /** - * Dispatch a message to delete data - * @param path - path of the data to delete - */ - deleteData:

['data'], 4>>(path: P) => void; - - /** - * Dispatch a message to set the listeners - * @param listeners - listeners to attach to the block - */ - setListener: ( - listener: keyof Block['listeners'], - actions: ListenerActions[], - ) => void; -} - -/** - * Access methods for the block - */ -export const useBlockSettings = ( - id: string, -): useBlockSettingsReturn => { - // get the store - const { state } = useBlocks(); - - // get the block - const block = state.getBlock(id); - - // get block - if (!block) { - throw Error(`Cannot find block ${id}`); - } - - /** - * Dispatch a message to set data - * @param path - path of the data to set - * @param value - value of the data to set - */ - const setData = useCallback( -

['data'], 4>>( - path: P | null, - value: PathValue['data'], P>, - ): void => { - state.dispatch({ - message: ActionMessages.SET_BLOCK_DATA, - payload: { - id: id, - path: path, - value: value, - }, - }); - }, - [id], - ); - - /** - * Dispatch a message to delete data - * @param path - path of the data to delete - */ - const deleteData = useCallback( -

['data'], 4>>(path: P | null): void => { - state.dispatch({ - message: ActionMessages.DELETE_BLOCK_DATA, - payload: { - id: id, - path: path, - }, - }); - }, - [], - ); - - /** - * Dispatch a message to set the listeners - * @param listener - listener to add to the block - * @param actions - actions to add to the block - * - */ - const setListener = useCallback( - ( - listener: keyof Block['listeners'], - actions: ListenerActions[], - ): void => { - state.dispatch({ - message: ActionMessages.SET_LISTENER, - payload: { - id: id, - listener: listener as string, - actions: actions, - }, - }); - }, - [], - ); - - return { - data: block.data || {}, - listeners: block.listeners || {}, - setData: setData, - deleteData: deleteData, - setListener: setListener, - }; -}; diff --git a/packages/client/src/hooks/useBlocks.tsx b/packages/client/src/hooks/useBlocks.tsx deleted file mode 100644 index fd29a39f63..0000000000 --- a/packages/client/src/hooks/useBlocks.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { useContext } from 'react'; - -import { BlocksContext } from '@/contexts'; - -/** - * Access the current InsightStore - * @returns the InsightStore - */ -export const useBlocks = () => { - const context = useContext(BlocksContext); - if (context === undefined) { - throw new Error('useBlocks must be used within Blocks'); - } - - return context; -}; diff --git a/packages/client/src/hooks/useBlocksPixel.tsx b/packages/client/src/hooks/useBlocksPixel.tsx deleted file mode 100644 index 6e98df8daf..0000000000 --- a/packages/client/src/hooks/useBlocksPixel.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { useContext } from 'react'; - -import { BlocksContext } from '@/contexts'; -import { PixelConfig, usePixel } from './usePixel'; - -/** - * Run pixel within blocks context - * @returns Pixel response - */ -export function useBlocksPixel( - pixel: string, - config?: Partial>, -) { - const context = useContext(BlocksContext); - if (context === undefined) { - throw new Error('useBlocksPixel must be used within Blocks'); - } - - return usePixel(pixel, config, context.state.insightId); -} diff --git a/packages/client/src/hooks/useFrame.tsx b/packages/client/src/hooks/useFrame.tsx deleted file mode 100644 index a2c15dacc9..0000000000 --- a/packages/client/src/hooks/useFrame.tsx +++ /dev/null @@ -1,158 +0,0 @@ -import { useCallback, useContext, useEffect, useState } from 'react'; -import { BlocksContext } from '@/contexts'; - -import { usePixel } from './usePixel'; - -/** - * Use a frame's in an insight - * - * @param frame - * @param options - */ -export function useFrame( - /** Frame to get data from */ - frame = '', - - /** Options for the frame */ - options: Partial<{ - /** Selector to grab the data */ - selector: string; - - /** Where to start grabbing the data */ - offset: number; - - /** How many to collect */ - limit: number; - - /** Enable the count */ - enableCount: boolean; - }> = {}, -) { - const { - selector = 'QueryAll()', - offset = 0, - limit = 1000, - enableCount = false, - } = options; - - const [isLoading, setIsLoading] = useState(false); - - const context = useContext(BlocksContext); - if (context === undefined) { - throw new Error('useFrame must be used within Blocks'); - } - - const { state } = context; - - // get the frameKey, this will change whenever the data does - const frameKey = state.getFrameKey(frame); - - /** - * Filter the frame - * - * @param - filterPixel - */ - const filterFrame = useCallback( - async (filterPixel: string): Promise => { - try { - setIsLoading(true); - // filter the frame - const response = await state.runSideEffect( - `META | ${frame} | ${filterPixel};`, - ); - - console.group(response); - - return true; - } catch (e) { - // log the error - console.error(e); - return false; - } finally { - setIsLoading(false); - } - }, - [frame], - ); - - /** - * Filter the frame - * - * @param - filterPixel - */ - const unfilterFrame = useCallback(async (): Promise => { - try { - setIsLoading(true); - - // filter the frame - const response = await state.runSideEffect( - `META | UnfilterFrame("${frame}");`, - ); - - console.group(response); - - return true; - } catch (e) { - // log the error - console.error(e); - return false; - } finally { - setIsLoading(false); - } - }, []); - - /** - * Get the data - */ - const getData = usePixel<{ - data: { - headers: string[]; - values: unknown[][]; - }; - }>( - frame - ? `META | Frame("${frame}") | ${selector} | Offset(${offset}) ${ - limit !== -1 ? `| Limit(${limit})` : '' - } | Collect(${limit});` - : '', - { - silent: true, - }, - context.state.insightId, - ); - - /** - * Get the count of all of the values - */ - const getCount = usePixel( - enableCount && frame - ? `META | Frame("${frame}") | ${selector} | Distinct(false) | QueryRowCount();` - : '', - { - silent: true, - }, - context.state.insightId, - ); - - // refresh the data whenever the key changes - useEffect(() => { - getData.refresh(); - getCount.refresh(); - }, [frameKey]); - - return { - isLoading: isLoading || getData.status === 'LOADING', - data: - getData.status === 'SUCCESS' - ? getData.data.data - : { - headers: [], - values: [], - }, - error: getData.error, - count: getCount.status === 'SUCCESS' ? getCount.data : -1, - /** Actions */ - filter: filterFrame, - unfilter: unfilterFrame, - }; -} diff --git a/packages/client/src/hooks/useFrameHeaders.tsx b/packages/client/src/hooks/useFrameHeaders.tsx deleted file mode 100644 index ecf299cef4..0000000000 --- a/packages/client/src/hooks/useFrameHeaders.tsx +++ /dev/null @@ -1,81 +0,0 @@ -import { useContext, useEffect } from 'react'; -import { BlocksContext } from '@/contexts'; - -import { usePixel } from './usePixel'; - -/** - * Use a frame's header's in an insight - * - * @param frame - * @param options - */ -export function useFrameHeaders( - /** Frame to get data from */ - frame = '', - - /** Options for the frame */ - options: Partial<{ - /** Selector to grab the data */ - headerTypes: string[]; - }> = {}, -) { - const { headerTypes = [] } = options; - - const context = useContext(BlocksContext); - if (context === undefined) { - throw new Error('useFrameHeaders must be used within Blocks'); - } - - const { state } = context; - - // get the frameKey, this will change whenever the data does - const frameKey = state.getFrameKey(frame); - - /** - * Get the headers - */ - const getHeaders = usePixel<{ - name: string; - type: string; - headerInfo: { - headers: { - alias: string; - header: string; - dataType: string; - adtlType: string; - qsName: unknown; - }[]; - joins: unknown[]; - }; - }>( - frame - ? `META | ${frame} | FrameHeaders(${ - headerTypes && headerTypes.length !== 0 - ? `headerTypes=${JSON.stringify(headerTypes)}` - : '' - });` - : '', - { - silent: true, - }, - context.state.insightId, - ); - - // refresh the data whenever the key changes - useEffect(() => { - getHeaders.refresh(); - }, [frameKey]); - - return { - isLoading: getHeaders.status === 'LOADING', - data: - getHeaders.status === 'SUCCESS' - ? { - list: getHeaders.data.headerInfo.headers, - } - : { - list: [], - }, - error: getHeaders.error, - }; -} diff --git a/packages/client/src/hooks/useLLMCompare.ts b/packages/client/src/hooks/useLLMCompare.ts deleted file mode 100644 index c75aefe49c..0000000000 --- a/packages/client/src/hooks/useLLMCompare.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { useContext } from 'react'; - -import { LLMComparisonContext, LLMComparisonContextType } from '@/contexts'; - -/** - * Access the current LLM Comparison Context - * @returns the LLM Comparison Context - */ -export function useLLMComparison(): LLMComparisonContextType { - const context = useContext(LLMComparisonContext); - if (context === undefined) { - throw new Error( - 'useLLMComparison must be used within LLM Comparison Provider', - ); - } - - return context; -} diff --git a/packages/client/src/hooks/useTypeWriter.ts b/packages/client/src/hooks/useTypeWriter.ts deleted file mode 100644 index ab5b5fe0e0..0000000000 --- a/packages/client/src/hooks/useTypeWriter.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { useState, useEffect, useRef } from 'react'; - -export const useTypeWriter = (text = '', speed = 20) => { - const [displayText, setDisplayText] = useState(''); - const indexRef = useRef(-1); - let typingInterval; - - const startTyping = () => { - if (typingInterval) return; - typingInterval = setInterval(() => { - if (indexRef.current < text.length && text !== '') { - indexRef.current += 1; - setDisplayText(text.slice(0, indexRef.current)); - } else { - clearInterval(typingInterval); - } - }, speed); - }; - - useEffect(() => { - if (!text.length) return; - const delayTimeout = setTimeout(startTyping, 100); - - return () => { - clearTimeout(delayTimeout); - clearInterval(typingInterval); - }; - }, [text, speed]); - - useEffect(() => { - if (text.length < indexRef.current) { - indexRef.current = text.length; - } - }, [text]); - - return displayText; -}; diff --git a/packages/client/src/stores/index.ts b/packages/client/src/stores/index.ts index 2e479a92fd..5197c490b1 100644 --- a/packages/client/src/stores/index.ts +++ b/packages/client/src/stores/index.ts @@ -1,7 +1,5 @@ export * from './config'; export * from './designer'; export * from './monolith'; -export * from './notebook'; export * from './root'; -export * from './state'; export * from './workspace'; diff --git a/packages/client/src/stores/notebook/index.ts b/packages/client/src/stores/notebook/index.ts deleted file mode 100644 index 0e2fea06d7..0000000000 --- a/packages/client/src/stores/notebook/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './notebook.store'; diff --git a/packages/client/src/stores/notebook/notebook.store.ts b/packages/client/src/stores/notebook/notebook.store.ts deleted file mode 100644 index 029588832a..0000000000 --- a/packages/client/src/stores/notebook/notebook.store.ts +++ /dev/null @@ -1,118 +0,0 @@ -import { makeAutoObservable } from 'mobx'; - -import { StateStore } from '../state'; - -export interface NotebookStoreInterface { - /** Current selected query */ - selectedQueryId: string; - - /** Store the previously selected query -> cell */ - selectedCells: Record; - - /** Current selected Variant */ - selectedVariantId: string; -} - -/** - * Internal state management of the notebook object - */ -export class NotebookStore { - private _state: StateStore; - private _store: NotebookStoreInterface = { - selectedQueryId: '', - selectedCells: {}, - selectedVariantId: '', - }; - - constructor(state: StateStore) { - // set the state - this._state = state; - - // make it observable - makeAutoObservable(this); - } - - /** - * Getters - */ - /** - * Get the queries - * @returns the queries - */ - get queriesList() { - return Object.values(this._state.queries).sort((a, b) => { - const aId = a.id.toLowerCase(), - bId = b.id.toLowerCase(); - - if (aId < bId) { - return -1; - } - if (aId > bId) { - return 1; - } - return 0; - }); - } - - /** - * Get the selected query - */ - get selectedQuery() { - return this._state.queries[this._store.selectedQueryId]; - } - - /** - * Get the selected cell - */ - get selectedCell() { - const selectedQuery = this.selectedQuery; - if (!selectedQuery) { - return null; - } - - const selectedCellId = this._store.selectedCells[selectedQuery.id]; - if (!selectedCellId) { - return null; - } - const selectedCell = this.selectedQuery.getCell(selectedCellId); - if (!selectedCell) { - return null; - } - - return selectedCell; - } - - /** - * Actions - */ - /** - * Set the selected query - * @param queryId - id of the block that is selected - */ - selectQuery(queryId: string) { - // set the id - this._store.selectedQueryId = queryId; - // automatically select last cell of query - const queryCells = this._state.queries[queryId].list; - if (queryCells.length) { - this.selectCell(queryId, queryCells[queryCells.length - 1]); - } - } - - /** - * Set the selected cell - * @param queryId - id of the block that is selected - */ - selectCell(queryId: string, cellId: string) { - // select the cell - this._store.selectedCells[queryId] = cellId; - } - - /** - * Set the selected Variant - * @param variantId - id of selected variant - */ - selectVariant(variantId: string) { - this._store.selectedVariantId = variantId; - } -} diff --git a/packages/client/src/stores/state/cell.state.ts b/packages/client/src/stores/state/cell.state.ts deleted file mode 100644 index 6f29625f56..0000000000 --- a/packages/client/src/stores/state/cell.state.ts +++ /dev/null @@ -1,441 +0,0 @@ -import { makeAutoObservable, runInAction, toJS } from 'mobx'; - -import { setValueByPath } from '@/utility'; - -import { CellComponent, CellConfig, CellDef } from './state.types'; -import { StateStore } from './state.store'; -import { QueryState } from './query.state'; -import { pixelConsole, pixelResult, runPixelAsync } from '@/api'; - -export interface CellStateStoreInterface { - /** Id of the cell */ - id: string; - - /** Track if the cell is loading */ - isLoading: boolean; - - /** Track how long the cell took */ - executionDurationMilliseconds: number | undefined; - - /** Operation associated with the cell */ - operation: string[]; - - /** Output associated with the cell */ - output: unknown | undefined; - - /** Prints and logs */ - messages: string[] | undefined; - - /** Widget to bind the cell to */ - widget: D['widget']; - - /** Parameters associated with the cell */ - parameters: D['parameters']; -} - -export interface CellStateConfig { - /** Id of the cell */ - id: string; - - /** Widget to bind the cell to */ - widget: D['widget']; - - /** Parameters associated with the cell */ - parameters: D['parameters']; -} - -/** - * Store that manages each cell in a query - */ -export class CellState { - private _state: StateStore; - private _query: QueryState; - private _store: CellStateStoreInterface = { - id: '', - isLoading: false, - executionDurationMilliseconds: undefined, - operation: [], - output: undefined, - messages: [], - widget: '', - parameters: {}, - }; - - constructor(config: CellStateConfig, query: QueryState, state: StateStore) { - // register the query + state - this._query = query; - this._state = state; - - // set the initial state information - this._store.id = config.id; - this._store.widget = config.widget; - this._store.parameters = config.parameters; - - // make it observable - makeAutoObservable(this); - } - - /** - * Getters - */ - /** - * Id of the cell - */ - get id() { - return this._store.id; - } - - /** - * Query associated with the cell - */ - get query() { - return this._query; - } - - /** - * Track if the cell is loading - */ - get isLoading() { - return this._store.isLoading; - } - - /** Track how long the cell took */ - get executionDurationMilliseconds() { - return this._store.executionDurationMilliseconds; - } - - /** - * Track if the cell has errored loading - */ - get isError() { - if (this._store.operation.indexOf('ERROR') > -1) { - return true; - } - - return false; - } - - /** - * Track if the cell was successfully run - */ - get isSuccessful() { - if ( - this._store.operation.length > 0 && - this._store.operation.indexOf('ERROR') === -1 - ) { - return true; - } - - return false; - } - - /** - * Track if the query is executed (there is an output or an error) - */ - get isExecuted() { - if (this._store.operation.length > 0) { - return true; - } - - return false; - } - - /** - * Get any errors associated with the cell - */ - get error() { - if (this.isError) { - return this.output as string; - } - - return ''; - } - - /** - * Get the operation of the cell - */ - get operation() { - return this._store.operation; - } - - /** - * Get the output of the cell - */ - get output() { - return this._store.output; - } - - /** - * Get the messages of the cell - */ - get messages() { - return this._store.messages; - } - - /** - * Get the widget associated with the cell - */ - get widget() { - return this._store.widget; - } - - /** - * Get the component associated with the cell - */ - get component(): CellComponent | null { - if (this._state.cellRegistry[this._store.widget]) { - return this._state.cellRegistry[this._store.widget].view; - } - - return null; - } - - /** - * Get the config associated with the cell - */ - get config(): CellConfig | null { - if (this._state.cellRegistry[this._store.widget]) { - return this._state.cellRegistry[this._store.widget]; - } - - return null; - } - - /** - * Get the parameters associated with the cell - */ - get parameters() { - return this._store.parameters; - } - - /** - * Actions - */ - /** - * Serialize to JSON - */ - toJSON = (): CellStateConfig => { - return { - id: this._store.id, - widget: this._store.widget, - parameters: toJS(this._store.parameters), - }; - }; - - /** - * Convert the parameters to pixel - * - * @param parameters - Convert the cell with these parameters - */ - toPixel( - parameters: Record = this._store.parameters, - ): string | string[] { - const cellConfig = this.config; - - // use the toPixel from the cell - if (cellConfig) { - const pixelReturn = cellConfig.toPixel(parameters); - return pixelReturn; - } - - return Object.keys(parameters) - .map((key) => { - return `${key}=[${JSON.stringify(parameters[key])}]`; - }) - .join(', '); - } - - /** - * Helpers - */ - /** - * Helper function to run a pixel - * @param rawPixel - pixel to be formatted and run - */ - private async runPixel(rawPixel: string) { - // Gets rid of braces and evaluate parameters in query - // const filled = this._state.flattenVar(raw); - const filled = this._state.flattenVariable(rawPixel); - - // clear the previous messages + operation + output - this._store.messages = []; - this._store.operation = []; - this._store.output = undefined; - - // start polling - const { jobId } = await runPixelAsync(filled, this._state.insightId); - - // Set up polling in order to get full stdout - let isPolling = true; - while (isPolling) { - try { - // get the reponse from the job id - const { messages, status } = await pixelConsole(jobId); - - // add the new messages - runInAction(() => { - messages.forEach((mess) => { - this._store.messages.push(mess); - }); - }); - - // Currently console does not get pass STREAMING - if (status === 'Complete') { - isPolling = false; - } else if (status === 'Streaming') { - isPolling = false; - } else { - // poll - await new Promise((resolve) => setTimeout(resolve, 2000)); - } - } catch (error) { - console.error('Error during polling:', error.message); - - // turn it off - isPolling = false; - } - } - - const { errors, results } = await pixelResult(jobId); - if (errors.length > 0) { - throw new Error(errors.join('')); - } - - const last = results[results.length - 1]; - - // set the output per operation - let output: unknown; - const opType: string[] = last.operationType; - - if (last.operationType.indexOf('CUSTOM_DATA_STRUCTURE') > -1) { - output = last.output; - } else if (last.operationType.indexOf('FORMATTED_DATA_SET') > -1) { - output = last.output[0]; - } else if (last.operationType.indexOf('CODE_EXECUTION') > -1) { - output = last.output[0].output; - } else if (last.operationType.indexOf('CODE') > -1) { - output = last.output[0].value[0]; - } else if (last.operationType.indexOf('ERROR') > -1) { - output = last.output[0]; - } else if (last.operationType.indexOf('CONST_STRING') > -1) { - output = last.output[0]; - } else if (last.operationType.indexOf('INVALID_SYNTAX') > -1) { - output = last.output[0]; - } else if (last.operationType.indexOf('VECTOR') > -1) { - output = last.output[0]; - } else { - output = last.output; - } - - return { opType, output }; - } - - /** - * Run the cell - */ - async _run() { - const start = new Date(); - - try { - // check the loading state - if (this._store.isLoading) { - throw new Error('Cell is already loading'); - } - - // start the loading screen - this._store.isLoading = true; - - // convert the cells to the raw pixel - const raw: string | string[] = this.toPixel(); - - // Determine if multiple pixels need to be ran. - if (typeof raw === 'string') { - const { opType, output } = await this.runPixel(raw); - - runInAction(() => { - // store the operation and output - this._store.operation = opType; - - // save the last output - this._store.output = output; - }); - } else if (Array.isArray(raw)) { - // Collect responses for each call to store in state. - let opTypes = []; - const outputs = []; - - for (const str of raw) { - const { opType, output } = await this.runPixel(str); - opTypes = [...opTypes, ...opType]; - outputs.push(output); - } - - runInAction(() => { - // store the operation and output - this._store.operation = opTypes; - - // save the last output - this._store.output = outputs; - }); - } - - // log it - console.log(JSON.stringify(this.operation), this.output); - - // process side effects from running a pixel - this._state.processSideEffects(this.operation, this.output); - } catch (e) { - runInAction(() => { - // store the operation and output - this._store.operation = ['ERROR']; - - // save the last output - this._store.output = e.message; - }); - } finally { - runInAction(() => { - //TODO: Integrate with backend - const end = new Date(); - - this._store.executionDurationMilliseconds = - end.getTime() - start.getTime(); - - // stop the loading screen - this._store.isLoading = false; - }); - } - } - - /** - * Update the the store of the cell - * @param path - path of the data to set - * @param value - value of the data - */ - _update(path: string | null, value: unknown) { - if (!path) { - // set the value - this._store = value as CellStateStoreInterface; - return; - } - - // update the parameters - setValueByPath(this._store, path, value); - } - - /** - * Get the exposed value that can be accesed by a variable - */ - get _exposed() { - return { - id: this._store.id, - isExecuted: this.isExecuted, - isLoading: this.isLoading, - isError: this.isError, - isSuccessful: this.isSuccessful, - error: this.error, - output: this.output, - messages: this.messages, - operation: this.operation, - }; - } -} diff --git a/packages/client/src/stores/state/index.ts b/packages/client/src/stores/state/index.ts deleted file mode 100644 index 07989adf91..0000000000 --- a/packages/client/src/stores/state/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -export * from './state.constants'; -export * from './state.store'; -export * from './state.actions'; -export * from './state.types'; -export * from './query.state'; -export * from './cell.state'; - -// export * from '../../../../../libs/renderer/src/store/state/migration'; diff --git a/packages/client/src/stores/state/query.state.ts b/packages/client/src/stores/state/query.state.ts deleted file mode 100644 index f5a0bb52ff..0000000000 --- a/packages/client/src/stores/state/query.state.ts +++ /dev/null @@ -1,367 +0,0 @@ -import { makeAutoObservable, runInAction } from 'mobx'; - -import { setValueByPath } from '@/utility'; - -import { CellState, CellStateConfig } from './cell.state'; -import { StateStore } from './state.store'; - -export interface QueryStateStoreInterface { - /** Id of the query */ - id: string; - - /** Track if the cell is loading */ - isLoading: boolean; - - /** Error associated with the Query */ - error: Error | null; - - /** Pixel Cells in the query */ - cells: Record; - - /** Ordered list of the cells in the query */ - list: string[]; -} - -export interface QueryStateConfig { - /** Id of the query */ - id: string; - - /** Cells in the query */ - cells: CellStateConfig[]; -} - -/** - * Store that manages instances of the insights and handles applicaiton level querying - */ -export class QueryState { - private _state: StateStore; - private _store: QueryStateStoreInterface = { - id: '', - isLoading: false, - error: null, - cells: {}, - list: [], - }; - - constructor(config: QueryStateConfig, state: StateStore) { - // register the state - this._state = state; - - // set the id - this._store.id = config.id; - - // create the cells - const { cells, list } = config.cells.reduce( - (acc, val) => { - acc.cells[val.id] = new CellState(val, this, this._state); - acc.list.push(val.id); - - return acc; - }, - { - cells: {}, - list: [], - }, - ); - - this._store.cells = cells; - this._store.list = list; - - // make it observable - makeAutoObservable(this); - } - - /** - * Getters - */ - /** - * Id of the query - */ - get id() { - return this._store.id; - } - - /** - * Track if the query is executed - */ - get isExecuted() { - for (const c of this._store.list) { - const cell = this._store.cells[c]; - if (!cell.isExecuted) { - return false; - } - } - - return true; - } - - /** - * Track if the query is loading - */ - get isLoading() { - if (this._store.isLoading) { - return true; - } - - for (const c of this._store.list) { - const cell = this._store.cells[c]; - if (cell.isLoading) { - return true; - } - } - - return false; - } - - /** - * Track if the query has errored - */ - get isError() { - if (this._store.error) { - return true; - } - - for (const s of this._store.list) { - const cell = this._store.cells[s]; - if (cell.isError) { - return true; - } - } - - return false; - } - - /** - * Track if the query successfully ran - */ - get isSuccessful() { - for (const c of this._store.list) { - const cell = this._store.cells[c]; - if (!cell.isExecuted || cell.isError) { - return false; - } - } - - return true; - } - - /** - * Data associateed with the query - */ - get error() { - // display the query error - if (this._store.error) { - return this._store.error.message; - } - - // collect the cell errors - const messages = []; - for (const s of this._store.list) { - const cell = this._store.cells[s]; - if (cell.isError) { - messages.push(cell.error); - } - } - - if (messages.length > 0) { - return messages.join('\r\n'); - } - - return ''; - } - - /** - * Output associated with the query - */ - get output() { - const cellLen = this._store.list.length; - if (cellLen > 0) { - // get the last cell - const cellId = this._store.list[cellLen - 1]; - return this._store.cells[cellId].output; - } - - return undefined; - } - - /** - * Get list of the cells of the query - */ - get list() { - return this._store.list; - } - - /** - * Get the cells of the query - */ - get cells() { - return this._store.cells; - } - - /** - * Get the cells of the query as a list - */ - get cellList() { - return this._store.list.map((cId) => this._store.cells[cId]); - } - - /** - * Get a cell from the query - * @param id - id of the cell to get - */ - getCell = (id: string): CellState => { - return this._store.cells[id]; - }; - - /** - * Actions - */ - /** - * Serialize to JSON - */ - toJSON = (): QueryStateConfig => { - return { - id: this._store.id, - cells: this._store.list.map((s) => this._store.cells[s].toJSON()), - }; - }; - - /** - * Convert the query to pixel - */ - toPixel = () => { - return this._store.list - .map((s) => this._store.cells[s].toPixel()) - .join(';'); - }; - - /** - * Helpers - */ - /** - * Run the query - */ - _run = async () => { - try { - // check the loading state - if (this._store.isLoading) { - throw new Error('Query is loading'); - } - - // start the loading screen - this._store.isLoading = true; - - // run each synchronously - for (const s of this._store.list) { - const cell = this._store.cells[s]; - - // run the cell - await cell._run(); - } - } catch (e) { - // if a cell errors out of the runPixel and causes a break/catch here, - // we're unable to get granular information about which cell caused the error. - runInAction(() => { - this._store.error = e; - }); - } finally { - // stop the loading screen - runInAction(() => { - this._store.isLoading = false; - }); - } - }; - - /** - * Update the the store of the query - * @param path - path of the data to set - * @param value - value of the data - */ - _update = (path: string | null, value: unknown) => { - if (!path) { - // set the value - this._store = value as QueryStateStoreInterface; - return; - } - - // update the parameters - setValueByPath(this._store, path, value); - }; - - /** - * Add a cell - * @param cell - new cell being added - * @param previousCellId - id of the previous cell - */ - _addCell = ( - cellId: string, - config: Omit, - previousCellId: string, - ) => { - // create the new cell - const cell = new CellState( - { - ...config, - id: cellId, - }, - this, - this._state, - ); - - // save the cell - this._store.cells[cellId] = cell; - - // get the index of the previous one - let previousCellIdx = -1; - if (previousCellId) { - previousCellIdx = this._store.list.indexOf(previousCellId); - } - - // add to end if there is no previous cell - if (previousCellIdx === -1) { - this._store.list.push(cellId); - return; - } - - // add it - if (!this._store.list.includes(cellId)) { - this._store.list.splice(previousCellIdx + 1, 0, cellId); - } - }; - - /** - * Remove a cell - * @param id - id of the cell to delete - */ - _removeCell = (id: string) => { - // find the index to delete at - const deleteCellIdx = this._store.list.indexOf(id); - if (deleteCellIdx === -1) { - throw new Error(`Unable to find cell ${id}. This was not deleted`); - } - - // remove it by index - this._store.list.splice(deleteCellIdx, 1); - - // remove it by id - if (this._store.cells[id]) { - delete this._store.cells[id]; - } - }; - - /** - * Get the exposed value that can be accesed by a variable - */ - get _exposed() { - return { - id: this._store.id, - isExecuted: this.isExecuted, - isLoading: this.isLoading, - isError: this.isError, - isSuccessful: this.isSuccessful, - error: this.error, - output: this.output, - list: this.list, - }; - } -} diff --git a/packages/client/src/stores/state/state.actions.ts b/packages/client/src/stores/state/state.actions.ts deleted file mode 100644 index 774273e12a..0000000000 --- a/packages/client/src/stores/state/state.actions.ts +++ /dev/null @@ -1,273 +0,0 @@ -import { - BlockJSON, - ListenerActions, - SerializedState, - VariableType, - VariableWithId, -} from './state.types'; -import { CellStateConfig } from './cell.state'; -import { QueryStateConfig } from './query.state'; - -export enum ActionMessages { - SET_STATE = 'SET_STATE', - ADD_BLOCK = 'ADD_BLOCK', - MOVE_BLOCK = 'MOVE_BLOCK', - REMOVE_BLOCK = 'REMOVE_BLOCK', - SET_BLOCK_DATA = 'SET_BLOCK_DATA', - DELETE_BLOCK_DATA = 'DELETE_BLOCK_DATA', - SET_LISTENER = 'SET_LISTENER', - SET_QUERY = 'SET_QUERY', - NEW_QUERY = 'NEW_QUERY', - DELETE_QUERY = 'DELETE_QUERY', - UPDATE_QUERY = 'UPDATE_QUERY', - RUN_QUERY = 'RUN_QUERY', - NEW_CELL = 'NEW_CELL', - DELETE_CELL = 'DELETE_CELL', - UPDATE_CELL = 'UPDATE_CELL', - RUN_CELL = 'RUN_CELL', - DISPATCH_EVENT = 'DISPATCH_EVENT', - ADD_VARIABLE = 'ADD_VARIABLE', - RENAME_VARIABLE = 'RENAME_VARIABLE', - EDIT_VARIABLE = 'EDIT_VARIABLE', - DELETE_VARIABLE = 'DELETE_VARIABLE', - SET_SHEET_EXECUTION_ORDER = 'SET_SHEET_EXECUTION_ORDER', -} - -export type Actions = - | SetStateAction - | AddBlockAction - | MoveBlockAction - | RemoveBlockAction - | SetBlockDataAction - | DeleteBlockDataAction - | SetListenerAction - | NewQueryAction - | DeleteQueryAction - | UpdateQueryAction - | RunQueryAction - | NewCellAction - | DeleteCellAction - | UpdateCellAction - | RunCellAction - | DispatchEventAction - | AddVariableAction - | RenameVariableAction - | EditVariableAction - | DeleteVariableAction - | SetSheetExecutionOrderAction; - -export interface Action { - message: string; - payload: Record; -} - -export interface SetStateAction extends Action { - message: ActionMessages.SET_STATE; - payload: { - state?: SerializedState; - }; -} - -export interface AddBlockAction extends Action { - message: ActionMessages.ADD_BLOCK; - payload: { - json: BlockJSON; - position?: - | null - | { parent: string; slot: string } - | { - parent: string; - slot: string; - type: 'before'; - sibling: string; - } - | { - parent: string; - slot: string; - type: 'after'; - sibling: string; - }; - }; -} - -export interface MoveBlockAction extends Action { - message: ActionMessages.MOVE_BLOCK; - payload: { - id: string; - position?: - | null - | { parent: string; slot: string } - | { - parent: string; - slot: string; - type: 'before'; - sibling: string; - } - | { - parent: string; - slot: string; - type: 'after'; - sibling: string; - }; - }; -} - -export interface RemoveBlockAction extends Action { - message: ActionMessages.REMOVE_BLOCK; - payload: { - id: string; - keep: boolean; - }; -} - -export interface SetBlockDataAction extends Action { - message: ActionMessages.SET_BLOCK_DATA; - payload: { - id: string; - path: string | null; - value: unknown; - }; -} - -export interface DeleteBlockDataAction extends Action { - message: ActionMessages.DELETE_BLOCK_DATA; - payload: { - id: string; - path: string | null; - }; -} - -export interface SetListenerAction extends Action { - message: ActionMessages.SET_LISTENER; - payload: { - id: string; - listener: string; - actions: ListenerActions[]; - }; -} - -export interface NewQueryAction extends Action { - message: ActionMessages.NEW_QUERY; - payload: { - queryId: string; - config: Omit; - }; -} - -export interface DeleteQueryAction extends Action { - message: ActionMessages.DELETE_QUERY; - payload: { - queryId: string; - }; -} - -export interface UpdateQueryAction extends Action { - message: ActionMessages.UPDATE_QUERY; - payload: { - queryId: string; - path: string | null; - value: unknown; - }; -} - -export interface RunQueryAction extends Action { - message: ActionMessages.RUN_QUERY; - payload: { - queryId: string; - }; -} - -export interface NewCellAction extends Action { - message: ActionMessages.NEW_CELL; - payload: { - queryId: string; - cellId: string; - previousCellId: string; - config: Omit; - }; -} - -export interface DeleteCellAction extends Action { - message: ActionMessages.DELETE_CELL; - payload: { - queryId: string; - cellId: string; - }; -} - -export interface UpdateCellAction extends Action { - message: ActionMessages.UPDATE_CELL; - payload: { - queryId: string; - cellId: string; - path: string | null; - value: unknown; - }; -} - -export interface RunCellAction extends Action { - message: ActionMessages.RUN_CELL; - payload: { - queryId: string; - cellId: string; - }; -} - -export interface DispatchEventAction extends Action { - message: ActionMessages.DISPATCH_EVENT; - payload: { - name: string; - detail?: Record; - }; -} - -export interface AddVariableAction extends Action { - message: ActionMessages.ADD_VARIABLE; - payload: { - id: string; - type: VariableType; - to?: string; - cellId?: string; - value?: string; - isInput?: boolean; - isOutput?: boolean; - }; -} - -export interface EditVariableAction extends Action { - message: ActionMessages.EDIT_VARIABLE; - payload: { - id: string; - from: VariableWithId; - to: { - type: VariableType; - to?: string; - cellId?: string; - value?: string; - isInput?: boolean; - isOutput?: boolean; - }; - }; -} - -export interface RenameVariableAction extends Action { - message: ActionMessages.RENAME_VARIABLE; - payload: { - id: string; - alias: string; - }; -} - -export interface DeleteVariableAction extends Action { - message: ActionMessages.DELETE_VARIABLE; - payload: { - id: string; - }; -} - -export interface SetSheetExecutionOrderAction extends Action { - message: ActionMessages.SET_SHEET_EXECUTION_ORDER; - payload: { - list: string[]; - }; -} diff --git a/packages/client/src/stores/state/state.constants.ts b/packages/client/src/stores/state/state.constants.ts deleted file mode 100644 index cf397a32b8..0000000000 --- a/packages/client/src/stores/state/state.constants.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { ActionMessages } from './state.actions'; - -export const INPUT_BLOCK_TYPES = [ - 'audio-input', - 'input', - 'select', - 'upload', - 'checkbox', - 'toggle-button', - 'radio', -]; - -export const VARIABLE_TYPES = [ - 'block', - 'cell', - 'query', - 'database', - 'model', - 'vector', - 'storage', - 'function', - 'string', - 'number', - 'date', - 'array', - 'JSON', - // 'LLM Comparison', -]; - -export const ACTIONS_DISPLAY = { - [ActionMessages.RUN_QUERY]: 'Run Notebook', - [ActionMessages.DISPATCH_EVENT]: 'Dispatch Event', -}; diff --git a/packages/client/src/stores/state/state.store.ts b/packages/client/src/stores/state/state.store.ts deleted file mode 100644 index b8e6540c57..0000000000 --- a/packages/client/src/stores/state/state.store.ts +++ /dev/null @@ -1,1447 +0,0 @@ -import { makeAutoObservable, runInAction, toJS } from 'mobx'; - -import { download, runPixel } from '@/api'; -import { cancellablePromise, getValueByPath } from '@/utility'; - -import { - ActionMessages, - Actions, - AddBlockAction, - MoveBlockAction, - RemoveBlockAction, -} from './state.actions'; -import { - Block, - BlockJSON, - CellRegistry, - ListenerActions, - SerializedState, - Variable, - VariableType, - VariableWithId, - Frame, -} from './state.types'; -import { QueryState, QueryStateConfig } from './query.state'; -import { CellStateConfig } from './cell.state'; -import { STATE_VERSION } from '../../../../../libs/renderer/src/store/state/migration/MigrationManager'; - -interface StateStoreInterface { - /** Mode */ - mode: 'interactive' | 'static'; - - /** insightID to load */ - insightId: string; - - /** token to reference (blocks, cells, constants) */ - variables: Record; - - /** Queries rendered in the insight */ - queries: Record; - - /** Blocks rendered in the insight */ - blocks: Record; - - /** Frames stored in the insight */ - frames: Record; - - /** Cells registered to the insight */ - cellRegistry: CellRegistry; - - /** What version the state store we currently are on link: https://semver.org/ */ - version: string; - - /** Order of how we consume app as API */ - executionOrder: string[]; -} - -export class StateStoreConfig { - /** Mode */ - mode: 'interactive' | 'static'; - - /** insightID to load */ - insightId: string; - - /** State to load into the store */ - state: SerializedState; - - /** Cells registered to the insight */ - cellRegistry: CellRegistry; - - /** initial params for our variables can come from query params */ - initialParams?: Record; -} - -/** - * Hold the state information for the insight - */ -export class StateStore { - private _store: StateStoreInterface = { - mode: 'interactive', - insightId: '', - version: '', - queries: {}, - blocks: {}, - frames: {}, - cellRegistry: {}, - variables: {}, - executionOrder: [], - }; - - /** - * Utility variables - */ - private _utils: { - /** - * Track any executing queries - */ - queryPromises: Record< - string, - ReturnType | null - >; - } = { - queryPromises: {}, - }; - - constructor(config: StateStoreConfig) { - // save the connected insight - this._store.insightId = config.insightId; - - // set the mode of the store based on how it is being used - this._store.mode = config.mode; - - // register the cells - this._store.cellRegistry = config.cellRegistry || {}; - - // make it observable - makeAutoObservable(this); - - // set the initial state after reactive to invoke it - this.setState(config.state, config.initialParams); - } - - /** - * Getters - */ - /** - * Get the mode - * @returns the mode - */ - get mode() { - return this._store.mode; - } - - /** - * Get the Insight ID - * @returns the Insight ID - */ - get insightId() { - return this._store.insightId; - } - - /** - * Get the blocks - * @returns the blocks - */ - get blocks() { - return this._store.blocks; - } - - /** - * Get the queries - * @returns the queries - */ - get queries() { - return this._store.queries; - } - - /** - * Gets all tokens - * @returns the tokens - */ - get variables() { - return this._store.variables; - } - - /** - * Gets ordered list of sheet ids - * @returns the order sheets should be executed - */ - get executionOrder() { - return this._store.executionOrder; - } - - /** - * Get the cell type registry - * @returns the cell type registry - */ - get cellRegistry() { - return this._store.cellRegistry; - } - - /** - * Get the specific block information - * @param id - id of the block to get - * @returns the specific block information - */ - getBlock(id: string) { - if (this._store.blocks[id]) { - return this._store.blocks[id]; - } - - return null; - } - - /** - * Get all blocks of a specific type - * @param type - type of the block to get - * @returns all blocks of the specific type - */ - getAllBlocksOfType(type: string) { - return Object.values(this._store.blocks).filter( - (block) => block.widget === type, - ); - } - - /** - * Get all parents of a block - * @param nodeId - id of the block to get the parents of - * @returns all parents of the block - */ - getAllParents(nodeId: string) { - let selected = nodeId; - const parents = []; - while (selected) { - parents.push(selected); - selected = this._store.blocks[selected]?.parent?.id; - } - return parents; - } - - /** - * Get a specific queries's state - * @param id - id of the queries to get - * @returns the specific block information - */ - getQuery(id: string): QueryState | null { - if (this._store.queries[id]) { - return this._store.queries[id]; - } - - return null; - } - /** - * Gets the variable by it's pointer - * @param pointer - * @param type - * @param path - {{.isLoading}} {{.data.value}} - * @returns - */ - getVariable( - pointer: string, - type: VariableType, - path?: string[], - cellId?: string, - value?: string, - ): Variable | unknown { - try { - if (pointer) { - if (type === 'block') { - const block = this._store.blocks[pointer]; - - // Old Version of JSON - notebooks, will be dependent on the .value and may crash - if (path && path.length === 1) { - return block.data.value as string; - } else { - if (block) { - // get the search path - const s = path.slice(1).join('.'); - return getValueByPath(block.data, s); - } - } - } else if (type === 'query') { - const query = this._store.queries[pointer]; - if (query) { - if (path.length === 1) { - // Just get query output - return query.output; - } else { - const key = path[1]; - if (query) { - if (key in query._exposed) { - // get the search path - const s = path.slice(1).join('.'); - return getValueByPath(query._exposed, s); - } - } - } - } - // get the attribute key - } else if (type === 'cell') { - const query = this.getQuery(pointer); - const cell = query.getCell(cellId); - - if (cell) { - if (path.length === 1) { - return cell.output; - } else { - const key = path[1]; - if (key in cell._exposed) { - // get the search path - const s = path.slice(1).join('.'); - return getValueByPath(cell._exposed, s); - } - } - } - } - return undefined; - } else { - if ( - type === 'database' || - type === 'model' || - type === 'vector' || - type === 'function' || - type === 'storage' || - type === 'string' || - type === 'date' || - type === 'number' - ) { - return value; - } else if (type === 'array' || type === 'JSON') { - let v; - if (value === 'string') { - v = JSON.parse(value as string); - } else v = value; - - return v; - } - return undefined; - } - } catch (e) { - return undefined; - } - } - - /** - * Gets the variable alias by it's pointer - * @param pointer - * @param type - * @returns - */ - getAlias(pointer: string, cellId?: string): string { - let alias = ''; - - // Do we need to change how variables are stored to get rid of this iteration - Object.entries(this._store.variables).forEach((keyValue) => { - const variable = keyValue[1]; - - if (variable.to === pointer && !cellId) { - alias = keyValue[0]; - } else if (variable.to === pointer && variable.cellId === cellId) { - alias = keyValue[0]; - } - }); - return alias; - } - - /** - * Get a frame. Create one if it isn't there - * @param name - */ - getFrameKey(name: string): Frame['key'] { - // create the frame if it is not there - if (!this._store.frames[name]) { - runInAction(() => { - this.createFrame(name); - }); - } - - return this._store.frames[name].key; - } - - /** - * Actions - */ - /** - * Dispatch a message to update the state - * - * @param action - Action to execute - */ - dispatch = (action: Actions) => { - // TODO: Develop History + Invert + UNDO; - console.log( - 'ACTION :::', - JSON.parse(JSON.stringify(action.message)), - JSON.parse(JSON.stringify(action.payload)), - ); - - try { - // apply the action - if (ActionMessages.SET_STATE === action.message) { - const { state } = action.payload; - - this.setState(state); - } else if (ActionMessages.ADD_BLOCK === action.message) { - const { json, position } = action.payload; - - return this.addBlock(json, position); - } else if (ActionMessages.MOVE_BLOCK === action.message) { - const { id, position } = action.payload; - - this.moveBlock(id, position); - } else if (ActionMessages.REMOVE_BLOCK === action.message) { - const { id, keep } = action.payload; - - this.removeBlock(id, keep); - } else if (ActionMessages.SET_BLOCK_DATA === action.message) { - const { id, path, value } = action.payload; - - this.setBlockData(id, path, value); - } else if (ActionMessages.DELETE_BLOCK_DATA === action.message) { - const { id, path } = action.payload; - - this.deleteBlockData(id, path); - } else if (ActionMessages.SET_LISTENER === action.message) { - const { id, listener, actions } = action.payload; - - this.setListener(id, listener, actions); - } else if (ActionMessages.NEW_QUERY === action.message) { - const { queryId, config } = action.payload; - - return this.newQuery(queryId, config); - } else if (ActionMessages.DELETE_QUERY === action.message) { - const { queryId } = action.payload; - - this.deleteQuery(queryId); - } else if (ActionMessages.UPDATE_QUERY === action.message) { - const { queryId, path, value } = action.payload; - - this.updateQuery(queryId, path, value); - } else if (ActionMessages.RUN_QUERY === action.message) { - const { queryId } = action.payload; - - this.runQuery(queryId); - } else if (ActionMessages.NEW_CELL === action.message) { - const { queryId, cellId, config, previousCellId } = - action.payload; - - this.newCell(queryId, cellId, config, previousCellId); - } else if (ActionMessages.DELETE_CELL === action.message) { - const { queryId, cellId } = action.payload; - - this.deleteCell(queryId, cellId); - } else if (ActionMessages.UPDATE_CELL === action.message) { - const { queryId, cellId, path, value } = action.payload; - - this.updateCell(queryId, cellId, path, value); - } else if (ActionMessages.RUN_CELL === action.message) { - const { queryId, cellId } = action.payload; - - this.runCell(queryId, cellId); - } else if (ActionMessages.DISPATCH_EVENT === action.message) { - const { name, detail } = action.payload; - - this.dispatchEvent(name, detail); - } else if (ActionMessages.RENAME_VARIABLE === action.message) { - const { id, alias } = action.payload; - - return this.renameVariable(id, alias); - } else if (ActionMessages.ADD_VARIABLE === action.message) { - const { id, to, type, cellId, value, isInput, isOutput } = - action.payload; - - return this.addVariable( - id, - to, - type, - cellId, - value, - isInput, - isOutput, - ); - } else if (ActionMessages.EDIT_VARIABLE === action.message) { - const { id, from, to } = action.payload; - - const newVariable = { - type: to.type, - }; - - if (to.to) newVariable['to'] = to.to; - if (to.cellId) newVariable['cellId'] = to.cellId; - if (to.value) newVariable['value'] = to.value; - - newVariable['isInput'] = to.isInput ? to.isInput : false; - newVariable['isOutput'] = to.isOutput ? to.isOutput : false; - - this.editVariable(id, from, newVariable); - } else if (ActionMessages.DELETE_VARIABLE === action.message) { - const { id } = action.payload; - - this.deleteVariable(id); - } else if ( - ActionMessages.SET_SHEET_EXECUTION_ORDER === action.message - ) { - const { list } = action.payload; - - return this.setExecutionOrder(list); - } - } catch (e) { - console.error(e); - } - }; - - /** Variable Methods */ - /** - * Parse a variables and return the value if it exists (otherwise return the expression) - */ - parseVariable = (expression: string): unknown => { - // trim the whitespace - let cleaned = expression.trim(); - if (!cleaned.startsWith('{{') && !cleaned.endsWith('}}')) { - return expression; - } - - // remove the brackets - cleaned = cleaned.slice(2, -2); - - // get the keys in the path - const path = cleaned.split('.'); - - if (this._store.variables[path[0]]) { - const variable = this._store.variables[path[0]]; - const value = this.getVariable( - variable.to, - variable.type, - path, - variable.cellId, - variable.type !== 'cell' && variable.value - ? variable.value - : null, - ); - - // TODO: Check this, protects for false values - // (query.isLoading tied to a block.label **bad use-case) - if (value !== undefined && value !== null) { - return value; - } - - if (value === undefined) { - return value; - } - } - - return expression; - }; - - /** - * Flatten a string containing multiple variables - * @param expression - expression to flatten - * @returns the flatten parameter - */ - flattenVariable = (expression: string): string => { - return expression.replace(/{{(.*?)}}/g, (match) => { - // try to extract the variable - const v = this.parseVariable(match); - - // if it is not a string, convert to a string - if (typeof v !== 'string') { - return JSON.stringify(v); - } - - return v; - }); - }; - - /** Side effects Methods */ - /** - * Run a side effect pixel and process the response - * - * @param pixel - side effect to run - */ - runSideEffect = async (pixel: string) => { - const response = await runPixel(pixel, this._store.insightId); - - // process the side effects - for (const { operationType, output } of response.pixelReturn) { - this.processSideEffects(operationType, output); - } - - // return the response - return response; - }; - - /** - * Process side-effects from running a pixel - * - * @param operation - operation that was run - * @param output - output fo the operation - */ - processSideEffects = (operation: string[], output: unknown) => { - // download the file - if (operation.includes('FILE_DOWNLOAD')) { - download(this.insightId, output as string); - } else if ( - operation.includes('FRAME_DATA_CHANGE') || - operation.includes('FRAME_FILTER_CHANGE') - ) { - this.syncFrame((output as { name: string }).name); - } - }; - - /** - * Serialize to JSON - */ - toJSON(): SerializedState { - return { - queries: Object.keys(this._store.queries).reduce((acc, val) => { - acc[val] = this._store.queries[val].toJSON(); - return acc; - }, {} as SerializedState['queries']), - blocks: toJS(this._store.blocks), - variables: toJS(this._store.variables), - executionOrder: toJS(this._store.executionOrder), - version: this._store.version, - }; - } - - /** - * - */ - - /** - * Internal - */ - /** - * Helpers - */ - /** - * Generate a new block from the json - * @param json - json of the block that we are generating - * @returns block - */ - private generateBlock = (json: BlockJSON) => { - // generate a new id - const id = `${json.widget}--${Math.floor(Math.random() * 10000)}`; - - // create the block - const block = { - id: id, - widget: json.widget, - parent: null, - data: {}, - listeners: {}, - slots: {}, - } as Block; - - // add the data - block.data = json.data; - // Defaulting the route to the block id - block.data.route = id; - - // add the listeners - block.listeners = json.listeners; - - // generate the slots - for (const slot in json.slots) { - if (json.slots[slot]) { - block.slots[slot] = { - name: slot, - children: json.slots[slot].map((child) => { - // build the children, but only store the ids - const b = this.generateBlock(child); - - return b.id; - }), - }; - } - } - - // register it - this._store.blocks[id] = block; - - // return it - return block; - }; - - /** - * Check if a parent contains the child block - * @param parent - id of the parent block - * @param child - id of the child block - * @returns true if the child is in the parent - */ - containsBlock = (parent: string, child: string): boolean => { - const queue = [parent]; - while (queue.length) { - const current = queue.shift() as string; - - if (current === child) { - return true; - } - - // check if the block exists - const block = this._store.blocks[current]; - - // validate the children - for (const s in block.slots) { - queue.push(...block.slots[s].children); - } - } - - return false; - }; - - /** - * Attach a block to the parent block's slot. At this point, we assume that everything can be attached correctly. - * @param parent - id of the block that we are attaching to - * @param slot - slot that we are attaching to - * @param index - children index where we are attaching - * @param id - id of the block that we are attaching - */ - private attachBlock = ( - parent: string, - slot: string, - index: number, - id: string, - ) => { - const parentBlock = this._store.blocks[parent]; - - // if the slot is not valid, we cannot attach - if (!parentBlock.slots[slot]) { - return; - } - - // if it is is already there, we cannot attach - if (parentBlock.slots[slot].children.indexOf(id) !== -1) { - return; - } - - // get the block - const block = this._store.blocks[id]; - - // insert it - parentBlock.slots[slot].children.splice(index, 0, id); - - // update the child block - block.parent = { - id: parent, - slot: slot, - }; - - return; - }; - - /** - * Detach a block from the current parent. At this point, we assume that everything can be detached correctly. - * @param id - id of the block that we are detaching - */ - private detachBlock = (id: string) => { - const block = this._store.blocks[id]; - - // if there is no parent, there is no need to detach - if (!block.parent) { - return; - } - - // get the parent - const parentBlock = this._store.blocks[block.parent.id]; - - // validate that the slot and index are correct - const parentSlot = parentBlock.slots[block.parent.slot]; - if (!parentSlot) { - return; - } - - // - const blockIdx = parentSlot.children.indexOf(id); - if (blockIdx === -1) { - return; - } - - // remove it from the parent - parentSlot.children.splice(blockIdx, 1); - - // update the child - block.parent = null; - }; - - /** - * Create a new frame - */ - private createFrame = (name: string) => { - this._store.frames[name] = { - name: name, - key: 0, - }; - }; - - /** - * Resync the frame and change the data key - */ - private syncFrame = (name: string) => { - // create the frame if it is not there - if (!this._store.frames[name]) { - this.createFrame(name); - } - - // increment the key - this._store.frames[name].key = this._store.frames[name].key + 1; - }; - - /** - * Actions - */ - /** - * Set the state information - * - * @param state - pixel to execute - */ - private setState = ( - state: SerializedState, - initialParams?: Record, - ) => { - // store the block information - this._store.blocks = state.blocks; - - // load the queries - this._store.queries = Object.keys(state.queries).reduce((acc, val) => { - acc[val] = new QueryState(state.queries[val], this); - return acc; - }, {}); - - // store the variables - this._store.variables = state.variables ? state.variables : {}; - - // store the execution order of notebooks - let order = []; - const sheets = Object.keys(this._store.queries); - - if (state.executionOrder.length) { - order = state.executionOrder; - } else { - sheets.forEach((k) => { - order.push(k); - }); - } - - sheets.forEach(async (s) => { - const found = await order.find((o) => { - return o === s; - }); - - if (!found) { - order.push(s); - } - }); - - this._store.executionOrder = order; - - // Replace initial param values provided from URL - if (initialParams) { - Object.entries(initialParams).forEach((keyValue) => { - const key = keyValue[0]; - const value = keyValue[1]; - - const variable = this._store.variables[key]; - - if (variable) { - // retrieve the "to" value - const toValue = variable.to; - if (variable.type == 'block') { - // Look into blocks section - if (this._store.blocks[toValue]) { - this._store.blocks[toValue].data.value = value; - } - } else if ( - variable.type == 'cell' || - variable.type == 'query' - ) { - // TODO: Handle query and cell types do we just swap output? - } else { - this._store.variables[key]['value'] = value; - } - } - }); - } - - // store the version or the one we currently are on - this._store.version = state.version ? state.version : STATE_VERSION; - }; - - /** - * Create a block and add it to the tree - * @param json - json of the block that we are adding - * @param position - where is the block going - * @returns id of new block - */ - private addBlock = ( - json: BlockJSON, - position?: AddBlockAction['payload']['position'], - ): string => { - // generate the block - const block = this.generateBlock(json); - - // try to place it if position - if (!position) { - return; - } - - const { parent, slot } = position; - - // get the parent - const parentBlock = this._store.blocks[parent]; - - if ('sibling' in position) { - const { sibling, type } = position; - - // get the index of the sibling (it might have changed) - const siblingIdx = - parentBlock.slots[slot].children.indexOf(sibling); - - if (type === 'before') { - // attach the block before - this.attachBlock(parent, slot, siblingIdx, block.id); - } else if (type === 'after') { - // attach the block after - this.attachBlock(parent, slot, siblingIdx + 1, block.id); - } - } else { - // attach the block - this.attachBlock( - parent, - slot, - parentBlock.slots[slot].children.length, - block.id, - ); - } - return block.id; - }; - - /** - * Move a block in the tree - * @param id - id of the child block that we are moving - * @param position - where is the block going - */ - private moveBlock = ( - id: string, - position: MoveBlockAction['payload']['position'], - ): void => { - if (!position) { - // detach the current block (this might not always be possible) - this.detachBlock(id); - return; - } - - // if there is a parent see if you can detach - const { parent, slot } = position; - - // if the parent block is a child of the moved block, we cannot move - if (this.containsBlock(id, parent)) { - return; - } - - // get the parent - const parentBlock = this._store.blocks[parent]; - - // detach the current block (this might not always be possible) - this.detachBlock(id); - - if ('sibling' in position) { - const { sibling, type } = position; - - // get the index of the sibling (it might have changed) - const siblingIdx = - parentBlock.slots[slot].children.indexOf(sibling); - - if (type === 'before') { - // attach the block before - this.attachBlock(parent, slot, siblingIdx, id); - } else if (type === 'after') { - // attach the block after - this.attachBlock(parent, slot, siblingIdx + 1, id); - } - } else { - // attach the block - this.attachBlock( - parent, - slot, - parentBlock.slots[slot].children.length, - id, - ); - } - }; - - /** - * Remove the block from the tree - * @param id - id of the block that we are removing - * @param keep - keep the block - */ - private removeBlock = ( - id: string, - keep: RemoveBlockAction['payload']['keep'], - ): void => { - // get the block - const block = this._store.blocks[id]; - - if (block) { - // Remove the variable - Object.entries(this._store.variables).forEach((keyValue) => { - const varId = keyValue[0]; - const variable = keyValue[1]; - - if (variable.type === 'block') { - if (variable.to === id) { - delete this._store.variables[varId]; - } - } - }); - - // remove the children - for (const slot in block.slots) { - const { children } = block.slots[slot]; - // use copy of children so we can detach without breaking loop - for (const c of [...children]) { - this.removeBlock(c, false); - } - } - - // detach the current block (this might not always be possible) - this.detachBlock(id); - - // delete it - if (!keep) { - delete this._store.blocks[id]; - } - } else { - console.error("Block doesn't exist. Skipping."); - } - }; - - /** - * Set a block's data - * @param id - id of the block - * @param path - path of the data to set - * @param value - value of the data - */ - private setBlockData = ( - id: string, - path: string | null, - value: unknown, - ): void => { - if (!path) { - // set the value - this._store.blocks[id].data = value as Record; - return; - } - - // get the keys - const p = path.split('.'); - - // get the last key. If there is none, set the block data - const last = p.pop(); - if (!last) { - return; - } - - // traverse to the correct element - let current = this._store.blocks[id].data as Record; - while (p.length) { - const key = p.shift(); - - if (!key) { - return; - } - - // create the object if the key doesn't exist. This will allow us to have partials. - // TODO Generate with default? - if (!current[key]) { - current[key] = {}; - } - - current = current[key] as Record; - } - - // set the value - current[last] = value; - }; - - /** - * Delete a block's data - * @param id - id of the block - * @param path - path of the data to delete - */ - private deleteBlockData = (id: string, path: string | null): void => { - if (!path) { - // clear the data - this._store.blocks[id].data = {}; - - return; - } - - // get the keys - const p = path.split('.'); - - // get the last key - const last = p.pop(); - if (!last) { - return; - } - - // traverse to the correct element - let current = this._store.blocks[id].data as Record; - while (p.length) { - const key = p.shift(); - - if (!key || !current) { - return; - } - - current = current[key] as Record; - } - - // delete the value - delete current[last]; - }; - - /** - * Set a listener on a block - * @param id - id of the block - * @param listener - listener to add to the block - * @param actions - actions to add to the block - */ - private setListener = ( - id: string, - listener: string, - actions: ListenerActions[], - ): void => { - this._store.blocks[id].listeners[listener] = actions; - }; - - /** - * Create a new query - * @param queryId - name of the query that we are setting - */ - private newQuery = ( - queryId: string, - config: Omit, - ): string => { - this._store.queries[queryId] = new QueryState( - { - ...config, - id: queryId, - }, - this, - ); - - this._store.executionOrder.push(queryId); - - return queryId; - }; - - /** - * Delete a query - * @param queryId - name of the query that we are deleting - */ - private deleteQuery = (queryId: string): void => { - // Delete the query - delete this._store.queries[queryId]; - - // Remove it from our execition order tracking - const index = this._store.executionOrder.indexOf(queryId); - this._store.executionOrder.splice(index, 1); - - // clean up variables - Object.entries(this._store.variables).forEach((keyValue) => { - const id = keyValue[0]; - const variable = keyValue[1]; - if (variable.type === 'query') { - if (variable.to === queryId) { - delete this._store.variables[id]; - } - } - }); - }; - - /** - * Update the store in the query - * @param queryId - id of the updated query - * @param path - path of the data to set - * @param value - value of the data - */ - private updateQuery = ( - queryId: string, - path: string | null, - value: unknown, - ): void => { - const q = this._store.queries[queryId]; - - // set the value - q._update(path, value); - }; - - /** - * Run a query - * @param queryId - name of the query that we are running - */ - private runQuery = (queryId: string): void => { - const q = this._store.queries[queryId]; - - const key = `query--${queryId};`; - - // cancel a previous command - this._utils.queryPromises[key]?.cancel(); - - // setup the promise - const p = cancellablePromise(async () => { - // run the query - await q._run(); - - // turn it off - return true; - }); - - p.promise - .then(() => { - // noop - }) - .catch((e) => { - console.error('ERROR:', e); - }); - - // save the promise - this._utils.queryPromises[key] = p; - }; - - /** - * Create a new cell - * @param queryId - id of the updated query - * @param cellId - id of the new cell - * @param config - config of the - * @param previousCellId: id of the previous cell, - */ - private newCell = ( - queryId: string, - cellId: string, - config: Omit, - previousCellId: string, - ): void => { - // get the query - const q = this._store.queries[queryId]; - - // add the cell - q._addCell(cellId, config, previousCellId); - }; - - /** - * Delete a cell - * @param queryId - id of the updated query - * @param cellId - id of the deleted cell - */ - private deleteCell = (queryId: string, cellId: string): void => { - // get the query - const q = this._store.queries[queryId]; - - // remove the cell - q._removeCell(cellId); - - // clean up variables - Object.entries(this._store.variables).forEach((keyValue) => { - const id = keyValue[0]; - const variable = keyValue[1]; - if (variable.type === 'cell') { - if (variable.to === queryId && cellId === variable.cellId) { - delete this._store.variables[id]; - } - } - }); - - // always have at least one cell - if (q.list.length === 0) { - const newCellId = `${Math.floor(Math.random() * 100000)}`; - - this.newCell( - queryId, - newCellId, - { - parameters: { - code: '', - type: 'pixel', - }, - widget: 'code', - } as Omit, - '', - ); - } - }; - - /** - * Update the store in the cell - * @param queryId - id of the updated query - * @param cellId - id of the updated cell - * @param path - path of the data to set - * @param value - value of the data - */ - private updateCell = ( - queryId: string, - cellId: string, - path: string | null, - value: unknown, - ): void => { - const q = this._store.queries[queryId]; - const s = q.getCell(cellId); - - // set the value - s._update(path, value); - }; - - /** - * Run the cell - * @param queryId - id of the updated query - * @param cellId - id of the deleted cell - */ - private runCell = (queryId: string, cellId: string): void => { - const q = this._store.queries[queryId]; - const c = q.getCell(cellId); - - const key = `cell--${cellId} (query--${queryId});`; - - // cancel a previous command - this._utils.queryPromises[key]?.cancel(); - - // setup the promise - const p = cancellablePromise(async () => { - // run the cell - await c._run(); - - // turn it off - return true; - }); - - p.promise - .then(() => { - // noop - }) - .catch((e) => { - console.error('ERROR:', e); - }); - - // save the promise - this._utils.queryPromises[key] = p; - }; - - /** - * Dispatch a custom event - * @param name - name of the event - * @param detail - payload associated with event - */ - private dispatchEvent = ( - name: string, - detail: Record = {}, - ): void => { - const event = new CustomEvent(name, { - detail: detail, - }); - - // dispatch the event to the window - window.dispatchEvent(event); - }; - - // ----------------------------------- - // REVIEW VARIABLE AND DEPENDENCY CODE - // ----------------------------------- - /** - * Adds to variable that can be referenced - * @param id - referenced as - * @param to - points to - * @param type - type of variable - */ - private addVariable = ( - id: string, - to: string, - type: VariableType, - cellId?: string, - value?, - isInput?, - isOutput?, - ) => { - if (id.includes('.')) { - return false; - } - - if (this._store.variables[id]) { - return false; - } - - const token = { type }; - - if (to) token['to'] = to; - if (cellId) token['cellId'] = cellId; - if (isInput) token['isInput'] = isInput; - if (isOutput) token['isOutput'] = isOutput; - if (value) token['value'] = value; - - this._store.variables[id] = token as Variable; - - return token; - }; - - /** - * Renames variable that can be referenced - * @param old - points to old id - * @param id - new id for variable - */ - private renameVariable = (old: string, id: string): boolean => { - if (id.includes('.')) { - return false; - } - - if (this._store.variables[id]) { - return false; - } else { - this._store.variables[id] = this._store.variables[old]; - - delete this._store.variables[old]; - - return true; - } - }; - - /** - * Replace old variable and remove old dependency - * @param from - * @param to - */ - private editVariable = (id: string, oldVar: VariableWithId, newVar) => { - if (oldVar.id !== id) { - console.log('----------------------------'); - console.log('remove old variable due to name change'); - console.log('----------------------------'); - delete this._store.variables[oldVar.id]; - } - - this._store.variables[id] = newVar; - }; - - /** - * Deletes variable and corresponding dependency that can be referenced - * @param id - id to delete - */ - private deleteVariable = async (id: string) => { - // Stringify blocks - const blocksToMutate = JSON.stringify(this._store.blocks); - // remove the references of it from ui (don't touch users code notebook) - const regex = RegExp(`{{${id}(\\.[^}]+)?}}`, 'g'); - - const modifiedBlocks = await blocksToMutate.replace(regex, ''); - - this._store.blocks = JSON.parse(modifiedBlocks); - - delete this._store.variables[id]; - }; - - /** - * - */ - private setExecutionOrder = (orderedList: string[]) => { - this._store.executionOrder = orderedList; - return; - }; -} diff --git a/packages/client/src/stores/state/state.types.ts b/packages/client/src/stores/state/state.types.ts deleted file mode 100644 index 3c694cd5e3..0000000000 --- a/packages/client/src/stores/state/state.types.ts +++ /dev/null @@ -1,321 +0,0 @@ -import React from 'react'; -import { RunQueryAction, DispatchEventAction } from './state.actions'; -import { CellState } from './cell.state'; -import { QueryStateConfig } from './query.state'; - -export type SerializedState = { - /** What version the state store we currently are on link: https://semver.org/ */ - version: string; - - /** Queries rendered in the insight */ - queries: Record; - - /** Blocks rendered in the insight */ - blocks: Record; - - /** Variables used in notebook */ - variables: Record; - - /** Order of how we consume app as api */ - executionOrder: string[]; -}; - -/** - * Variable Types - */ -export type VariableType = - | 'block' - | 'cell' - | 'query' - | 'string' - | 'number' - | 'database' - | 'model' - | 'vector' - | 'storage' - | 'function' - | 'JSON' - | 'date' - | 'array' - | 'LLM Comparison'; - -/** - * Variables - */ -export type Variable = - | { - type: Exclude; // Exclude 'cell' from VariableType for this case - to?: string; - cellId?: never; // Explicitly setting it as never when 'type' is not 'cell' - value?: any; - isInput?: boolean; - isOutput?: boolean; - } - | { - to: string; - type: 'cell'; // Specific case when type is 'cell' - cellId: string; - isInput?: boolean; - isOutput?: boolean; - }; - -export type VariableWithId = - | ({ - type: Exclude; - to?: string; - value?: any; - isInput?: boolean; - isOutput?: boolean; - cellId?: string; - } & { id: string }) - | ({ - type: 'cell'; - to: string; - cellId: string; - isInput?: boolean; - isOutput?: boolean; - } & { id: string }); - -/** - * Frame - */ -export type Frame = { - /** Name of the frame */ - name: string; - - /** Key associated with the frame, it changes whenever the data changes */ - key: number; -}; - -/** - * Variants - */ -export type Variant = { - id: string; - sortWeight: number; - model: VariantModel; -}; - -export type VariantModel = { - id: string; - name: string; - topP: number; - temperature: number; - length: number; -}; - -/** - * Block - */ -export type Block = D extends D - ? { - /** ID of the Block */ - id: string; - - /** Unique widget name */ - widget: D['widget']; - - /** Parent of the block */ - parent: { - /** Parent ID of the block */ - id: string; - - /** Slot the block is in */ - slot: string; - } | null; - - /** Data associated with the block */ - data: D['data']; - - /** Event listeners associated with the block */ - listeners: Record; - - /** Slots associated with the block */ - slots: Record< - keyof D['slots'], - { - /** Name of the slot */ - name: keyof D['slots']; - /** Children IDs of the slot */ - children: string[]; - } - >; - } - : never; - -/** - * Block Definition - */ -export interface BlockDef { - /** Unique widget name */ - widget: W; - - /** Data associated with the widget */ - data: Record; - - /** Listeners associated with the widget */ - listeners: Record; - - /** Names of the slot associated with the widget */ - slots: Record; -} - -/** - * Block configuration - */ -export interface BlockConfig { - /** Unique widget name */ - widget: D['widget']; - - /** Block type: BLOCK_TYPE_ACTION | BLOCK_TYPE_CHART | BLOCK_TYPE_DISPLAY | BLOCK_TYPE_INPUT | BLOCK_TYPE_LAYOUT | BLOCK_TYPE_DATA */ - type: string; - - /** Data associated with the block */ - data: D['data']; - - /** Listeners associated with the block */ - listeners: Record; - - /** Children associated with the block */ - slots: Record; - - /** Render the block */ - render: BlockComponent; - - /** Icon to render in the builder sidebar */ - icon: React.FunctionComponent; - - /** *new* custom menu */ - menu?: BlockComponent; - - /** Content Menu */ - contentMenu?: { - name: string; - children: { - /** Description for the setting */ - description: string; - /** Render the setting */ - render: (props: { - /** Id of the block */ - id: string; - }) => JSX.Element; - }[]; - }[]; - - /** Style Menu */ - styleMenu?: { - name: string; - children: { - /** Description for the setting */ - description: string; - /** Render the setting */ - render: (props: { - /** Id of the block */ - id: string; - }) => JSX.Element; - }[]; - }[]; -} - -/** - * Component Innformation - */ -export type BlockComponent = (props: { - /** Id of the block */ - id: string; -}) => JSX.Element; - -/** - * JSON - */ -export type BlockJSON< - T extends BlockDef = BlockDef, - A extends BlockDef = BlockDef, -> = T extends BlockDef - ? { - /** Widget */ - widget: T['widget']; - - /** Data associated with the widget */ - data: T['data']; - - /** Event listeners associated with the widget */ - listeners: Record; - - /** Slot information */ - - slots: Record[]>; - } - : never; - -/** - * Registry - */ -export type Registry = D extends BlockDef - ? Record> - : never; - -/** - * Unwrap the Registry - */ -export type RegistryUnwrap> = R extends Registry< - infer W -> - ? W - : never; - -/** - * Listener Actions - */ -export type ListenerActions = RunQueryAction | DispatchEventAction; - -/** - * Cell Definition - */ -export interface CellDef { - /** Unique widget name */ - widget: W; - - /** Parameters associated with the widget */ - parameters: Record; -} - -/** - * Cell Registry - */ -export type CellRegistry = D extends CellDef - ? Record> - : never; -/** - * Component Information - */ -export type CellComponent = - React.FunctionComponent<{ - /** Cell that is controlling the cell */ - cell: CellState; - /** Whether the content is expanded */ - isExpanded?: boolean; - }>; - -/** - * Config Information - */ -export type CellConfig = { - /** Nmae of the Cell */ - name: string; - - /** Unique widget name */ - widget: D['widget']; - - /** Component rendered in the view */ - view: CellComponent; - - /** Parameters associated with the cell */ - parameters: D['parameters']; - - /** Method that to convert the cell into pixel */ - toPixel: ( - /** Parameters associated with the cell */ - parameters: D['parameters'], - ) => string | string[]; -};