diff --git a/libs/shared/lib/components/Dialog.tsx b/libs/shared/lib/components/Dialog.tsx new file mode 100644 index 0000000000000000000000000000000000000000..c975753399caf237003d19386079c98dd5e443d9 --- /dev/null +++ b/libs/shared/lib/components/Dialog.tsx @@ -0,0 +1,26 @@ +import { PropsWithChildren, useEffect, useRef } from 'react'; + +export type DialogProps = { + onClose(): void; + open: boolean; +}; + +export const Dialog = (props: PropsWithChildren<DialogProps>) => { + const ref = useRef<HTMLDialogElement>(null); + + useEffect(() => { + if (props.open) ref.current?.showModal(); + else ref.current?.close(); + }, [props.open]); + + return ( + <dialog className="modal" ref={ref} onClose={() => props.onClose()}> + <form method="dialog" className="modal-box card flex gap-4"> + {props.children} + </form> + <form method="dialog" className="modal-backdrop"> + <button>close</button> + </form> + </dialog> + ); +}; diff --git a/libs/shared/lib/data-access/store/schemaSlice.ts b/libs/shared/lib/data-access/store/schemaSlice.ts index add8bd0adab1b8c830cc226e2bca03d85a82fd9d..b187a78d9c3f41b642bdda555c1fca5d8732d13d 100644 --- a/libs/shared/lib/data-access/store/schemaSlice.ts +++ b/libs/shared/lib/data-access/store/schemaSlice.ts @@ -70,7 +70,6 @@ export const schemaSlice = createSlice({ }, }, }); - export const { readInSchemaFromBackend, setSchema } = schemaSlice.actions; /** diff --git a/libs/shared/lib/schema/panel/schema.tsx b/libs/shared/lib/schema/panel/schema.tsx index 1c04a64c33d3c1e2d74fcde06ff61c37d6b23337..def690e907db2e986a0a7af772863c92bd2a031f 100644 --- a/libs/shared/lib/schema/panel/schema.tsx +++ b/libs/shared/lib/schema/panel/schema.tsx @@ -1,6 +1,6 @@ import { AlgorithmToLayoutProvider, AllLayoutAlgorithms, LayoutFactory } from '@graphpolaris/shared/lib/graph-layout'; import { schemaGraphology2Reactflow, schemaExpandRelation } from '@graphpolaris/shared/lib/schema/schema-utils'; -import { useSchemaGraph, useSchemaGraphology, useSchemaLayout } from '@graphpolaris/shared/lib/data-access/store'; +import { useSchemaGraph, useSchemaGraphology, useSchemaLayout, useSessionCache } from '@graphpolaris/shared/lib/data-access/store'; import { useEffect, useMemo, useRef, useState } from 'react'; import ReactFlow, { @@ -15,6 +15,7 @@ import ReactFlow, { Background, } from 'reactflow'; import CachedIcon from '@mui/icons-material/Cached'; +import SettingsIcon from '@mui/icons-material/Settings'; import 'reactflow/dist/style.css'; @@ -25,6 +26,8 @@ import { EntityNode } from '../pills/nodes/entity/entity-node'; import { RelationNode } from '../pills/nodes/relation/relation-node'; import NodeEdge from '../pills/edges/node-edge'; import SelfEdge from '../pills/edges/self-edge'; +import { useSchemaAPI } from '../../data-access'; +import { SchemaDialog } from './schemaDialog'; interface Props { content?: string; @@ -54,10 +57,16 @@ const edgeTypes = { }; export const Schema = (props: Props) => { + const api_schema = useSchemaAPI(); + const session = useSessionCache(); + + const [toggleSchemaSettings, setToggleSchemaSettings] = useState(false); const [nodes, setNodes, onNodeChanged] = useNodesState([] as Node[]); const [edges, setEdges, onEdgeChanged] = useEdgesState([] as Edge[]); const [firstUserConnection, setFirstUserConnection] = useState<boolean>(true); const [auth, setAuth] = useState(props.auth); + const settingsIconRef = useRef<SVGSVGElement>(null); + const dialogRef = useRef<HTMLDivElement>(null); // In case the schema is updated const schemaGraphology = useSchemaGraphology(); @@ -119,10 +128,19 @@ export const Schema = (props: Props) => { // console.log(nodes, edges); + useEffect(() => { + console.log(settingsIconRef.current?.getBoundingClientRect()); + if (dialogRef.current && settingsIconRef.current) { + dialogRef.current.style.top = `${settingsIconRef.current.getBoundingClientRect().top}px`; + dialogRef.current.style.left = `${settingsIconRef.current.getBoundingClientRect().left + 30}px`; + } + }, [settingsIconRef, dialogRef, toggleSchemaSettings]); + return ( <div className="w-full h-full"> + <SchemaDialog open={toggleSchemaSettings} onClose={() => setToggleSchemaSettings(false)} ref={dialogRef} /> <h1 className="h-[1rem]">Schema</h1> - {nodes.length === 0 && <p>DEBUG: No Elements</p>} + {nodes.length === 0 && <p>No Elements</p>} <ReactFlowProvider> <div className="h-[calc(100%-.8rem)] w-full"> <ReactFlow @@ -158,10 +176,21 @@ export const Schema = (props: Props) => { title={'Refresh graph schema'} onClick={(event) => { event.stopPropagation(); + api_schema.RequestSchema(session.currentDatabase); }} > <CachedIcon /> </ControlButton> + <ControlButton + className={styles.exportButton} + title={'Open Settings'} + onClick={(event) => { + event.stopPropagation(); + setToggleSchemaSettings(!toggleSchemaSettings); + }} + > + <SettingsIcon ref={settingsIconRef} /> + </ControlButton> </Controls> </ReactFlow> </div> diff --git a/libs/shared/lib/schema/panel/schemaDialog.tsx b/libs/shared/lib/schema/panel/schemaDialog.tsx new file mode 100644 index 0000000000000000000000000000000000000000..e2bb5ffd846143403d1c0de8ee2c0866bca16d92 --- /dev/null +++ b/libs/shared/lib/schema/panel/schemaDialog.tsx @@ -0,0 +1,78 @@ +import { PropsWithChildren, useEffect, useRef } from 'react'; +import { Dialog, DialogProps } from '../../components/Dialog'; +import React from 'react'; +import CloseIcon from '@mui/icons-material/Close'; + +export const SchemaDialog = React.forwardRef<HTMLDivElement, DialogProps>((props, ref) => { + return ( + <> + {props.open && ( + <div className="absolute top-0 left-10 opacity-100 transition-opacity group-hover:opacity-100 z-50 " ref={ref}> + <div className="card absolute card-bordered bg-white rounded-none"> + <form + className="card-body px-0 w-72 py-5" + onSubmit={(e) => { + e.preventDefault(); + }} + > + <div className="card-title p-5 py-0 flex w-full"> + <h2 className="w-full">Quick Settings</h2> + <button className="btn btn-circle btn-sm btn-ghost" onClick={() => props.onClose()}> + <CloseIcon fontSize="small" /> + </button> + </div> + <div className="divider m-0"></div> + <div className="form-control px-5"> + <label className="label cursor-pointer w-fit gap-2 px-0 py-1"> + <input type="checkbox" checked={true} className="checkbox checkbox-xs" /> + <span className="label-text">Points</span> + </label> + <label className="label cursor-pointer w-fit gap-2 px-0 py-1"> + <input type="checkbox" checked={true} className="checkbox checkbox-xs" /> + <span className="label-text">Line</span> + </label> + <label className="label cursor-pointer w-fit gap-2 px-0 py-1"> + <input type="checkbox" checked={true} className="checkbox checkbox-xs" /> + <span className="label-text">Line</span> + </label> + </div> + <div className="divider m-0"></div> + <div className="form-control px-5"> + <label className="label"> + <span className="label-text">Opacity</span> + </label> + <input type="range" min={0} max="100" value="40" className="range range-sm" /> + </div> + <div className="divider m-0"></div> + <div className="form-control px-5"> + <label className="label"> + <span className="label-text">Histogram</span> + </label> + ... + </div> + <div className="divider m-0"></div> + <div className="form-control px-5"> + <label className="label"> + <span className="label-text">Goal Value</span> + </label> + <select className="select select-primary select-sm "> + <option className="option">35438</option> + </select> + </div> + <div className="divider m-0"></div> + <div className="card-actions w-full px-5"> + <button className="btn btn-primary w-full">Apply</button> + </div> + <div className="card-actions w-full px-5"> + <button className="btn btn-secondary w-full">Cancel</button> + </div> + <div className="card-actions w-full px-5"> + <button className="btn btn-outline w-full">Advance settings</button> + </div> + </form> + </div> + </div> + )} + </> + ); +}); diff --git a/libs/shared/lib/schema/panel/schemaOLD.tsx b/libs/shared/lib/schema/panel/schemaOLD.tsx deleted file mode 100644 index 8a135069260e2261d5b48808a7418adb98b0e6be..0000000000000000000000000000000000000000 --- a/libs/shared/lib/schema/panel/schemaOLD.tsx +++ /dev/null @@ -1,115 +0,0 @@ -import { AllLayoutAlgorithms, LayoutFactory } from '@graphpolaris/shared/lib/graph-layout'; -import { schemaGraphology2Reactflow, schemaExpandRelation } from '@graphpolaris/shared/lib/schema/schema-utils'; -import { useSchemaGraphology, useSchemaLayout } from '@graphpolaris/shared/lib/data-access/store'; -import { MultiGraph } from 'graphology'; -// import { AllLayoutAlgorithms, LayoutFactory } from '@graphpolaris/graph-layout'; -import { useEffect, useMemo, useState } from 'react'; -import ReactFlow, { ControlButton, Controls, Node, Edge, ReactFlowProvider, useNodesState, useEdgesState } from 'reactflow'; - -import 'reactflow/dist/style.css'; - -import styles from './schema.module.scss'; - -import { EntityFlowElement, RelationPill, ConnectionDragLine, ConnectionLine } from '@graphpolaris/shared/lib/querybuilder/pills'; - -interface Props { - content?: string; -} - -const onLoad = (reactFlowInstance: any) => { - setTimeout(() => reactFlowInstance.fitView(), 100); -}; - -const nodeTypes = { - entity: EntityFlowElement, - relation: RelationPill, -}; -const edgeTypes = { - connection: ConnectionLine, -}; - -export const Schema = (props: Props) => { - const [nodes, setNodes, onNodeChanged] = useNodesState([] as Node[]); - const [edges, setEdges, onEdgeChanged] = useEdgesState([] as Edge[]); - // In case the schema is updated - const dbschema = useSchemaGraphology(); - // const [dbschema, setSchema] = useState(useSchema()); - const [schemaLayout, setSchemaLayout] = useState(useSchemaLayout()); - - // useEffect(() => { - // console.log('dbSchema', dbschema, dbschema.order); - // }, [dbschema]); - - const expandedSchema = useMemo(() => schemaExpandRelation(dbschema), [dbschema]); - - useEffect(() => { - if (dbschema == undefined || dbschema.order == 0) { - return; - } - - const layoutFactory = new LayoutFactory(); - console.log('schema Layout', schemaLayout, 'order', expandedSchema); - const layout = layoutFactory.createLayout(schemaLayout as AllLayoutAlgorithms); - layout?.layout(expandedSchema); - - const flowElements = schemaGraphology2Reactflow(expandedSchema); - setNodes(flowElements.nodes); - setEdges(flowElements.edges); - console.log('update schema useEffect', dbschema, dbschema.order, flowElements); - }, [dbschema, schemaLayout]); - - const graphStyles = { width: '100%', height: '500px' }; - - // console.log(nodes, edges); - - return ( - <div - style={{ - width: '100%', - height: '100%', - }} - > - {nodes.length === 0 && <p>DEBUG: No Elements</p>} - <ReactFlowProvider> - <ReactFlow - className={styles.schemaPanel} - onlyRenderVisibleElements={false} - nodesDraggable={false} - nodeTypes={nodeTypes} - connectionLineComponent={ConnectionDragLine} - onNodesChange={onNodeChanged} - onEdgesChange={onEdgeChanged} - nodes={nodes} - edges={edges} - style={graphStyles} - onLoad={onLoad} - attributionPosition="top-right" - > - <Controls showInteractive={false} showZoom={false} showFitView={true} className={styles.controls}> - <ControlButton - className={styles.exportButton} - title={'Export graph schema'} - onClick={(event) => { - event.stopPropagation(); - // this.setState({ - // ...this.state, - // exportMenuAnchor: event.currentTarget, - // }); - }} - > - {/* <img src={exportIcon} width={21}></img> */} - </ControlButton> - </Controls> - </ReactFlow> - </ReactFlowProvider> - </div> - ); -}; - -export default Schema; - -// Fix layout of the schema -// create reactflow elements on xy coords -// connect reactflow elements together - -// maybe ook gelijk instellingen knoppie fixen op alle panels