Browse Source

Upgrade dependency: Mantine + use our own Graphviz React component (renders much faster)

Joeri Exelmans 1 year ago
parent
commit
b46db7d246

+ 14 - 12
package.json

@@ -1,44 +1,46 @@
 {
 	"devDependencies": {
-		"@emotion/react": "^11.10.6",
-		"@mantine/core": "^5.10.5",
-		"@mantine/hooks": "^5.10.5",
+		"@emotion/react": "^11.11.0",
 		"@tabler/icons": "^1.119.0",
 		"@types/d3": "^7.4.0",
 		"@types/d3-drag": "^3.0.2",
 		"@types/d3-force": "^3.0.4",
 		"@types/d3-selection": "^3.0.4",
 		"@types/mocha": "^10.0.1",
-		"@types/node": "^18.14.6",
-		"@types/react": "^18.0.28",
-		"@types/react-dom": "^18.0.11",
+		"@types/node": "^18.16.12",
+		"@types/react": "^18.2.6",
+		"@types/react-dom": "^18.2.4",
 		"fork-ts-checker-webpack-plugin": "^7.3.0",
 		"mocha": "^10.2.0",
 		"nyc": "^15.1.0",
 		"ts-loader": "^9.4.2",
 		"url-loader": "^4.1.1",
-		"webpack": "^5.76.0",
-		"webpack-cli": "^5.0.1",
+		"webpack": "^5.83.0",
+		"webpack-cli": "^5.1.1",
 		"webpack-dev-server": "^4.11.1"
 	},
 	"dependencies": {
-		"allotment": "^1.18.1",
+		"@mantine/core": "^6.0.19",
+		"@mantine/hooks": "^6.0.19",
+		"@mantine/modals": "^6.0.19",
+		"@viz-js/viz": "^3.1.0",
+		"allotment": "^1.19.0",
 		"buffer": "^6.0.3",
 		"crypto-browserify": "^3.12.0",
 		"css-loader": "^6.7.3",
-		"d3": "^7.8.2",
+		"d3": "^7.8.4",
 		"d3-drag": "^3.0.0",
 		"d3-force": "^3.0.0",
 		"d3-scale": "^4.0.2",
 		"d3-selection": "^3.0.0",
-		"graphviz-react": "^1.2.5",
+		"graphviz-worker": "^1.0.5",
 		"lodash": "^4.17.21",
 		"react": "^18.2.0",
 		"react-dom": "^18.2.0",
 		"react-icons": "^4.8.0",
 		"stream-browserify": "^3.0.0",
 		"style-loader": "^3.3.1",
-		"ts-node": "<10",
+		"ts-node": "^9.1.1",
 		"typescript": "^4.9.5",
 		"uuid": "^9.0.0"
 	},

File diff suppressed because it is too large
+ 238 - 232
pnpm-lock.yaml


+ 1 - 1
src/frontend/app.tsx

@@ -38,7 +38,7 @@ export function getApp() {
             <MantineProvider theme={{colorScheme: preferredColorScheme}} withGlobalStyles withNormalizeCSS>
                 <Styledtabs defaultValue="welcome" orientation="vertical" style={{height: '100%'}}>
                     <Allotment maxSize={'50%'}>
-                        <Allotment.Pane preferredSize={250} minSize={250}>
+                        <Allotment.Pane preferredSize={250} minSize={150} snap>
                             <Stack style={{height: '100%', direction: 'column', gap: '0px'}}>
                                 <Title order={4} style={{paddingLeft: '5px'}}>Pick a demo:</Title>
                                 <Tabs.List>

+ 22 - 6
src/frontend/demos/demo_live.tsx

@@ -1,8 +1,9 @@
 import * as React from 'react';
 import * as Icons from '@tabler/icons';
-import {Button, Divider, Group, Image, SimpleGrid, Space, Text, Title, TextInput, Select, Stack, Paper, Alert, Center} from '@mantine/core';
+import {Button, Divider, Group, Image, SimpleGrid, Space, Text, Title, TextInput, Select, Stack, Paper, Alert, Center, MantineProvider} from '@mantine/core';
+import { modals, ModalsProvider } from '@mantine/modals';
 
-import { Graphviz } from 'graphviz-react';
+import {GraphvizComponent} from "../graphviz";
 
 import {newOnion, undoButtonHelpText, VersionedModelState,} from '../versioned_model/single_model';
 import {InfoHoverCard, InfoHoverCardOverlay} from "../info_hover_card";
@@ -412,12 +413,23 @@ export function getDemoLive() {
     function onExecuteNonDeterministicStep(transitions: Transition[]) {
       if (runtimeStuff.runtimeModelNode !== null) {
         const deterministic = transitions.length <= 1;
+        if (!deterministic) {
+          modals.open({
+            title: (<b>Non-determinism!</b>),
+            children: (
+              <>
+                <Text>Multiple futures exist.</Text>
+                <Text>Use <b>Redo</b> or <b>History</b> to select your desired future.</Text>
+                <Button fullWidth onClick={modals.closeAll} mt="md">
+                  OK
+                </Button>
+              </>
+            ),
+          });
+        }
         for (const transition of transitions) {
           onExecuteStep(transition, deterministic /* only go to next version if only one future exists */);
         }
-        if (!deterministic) {
-          alert("Non-determinism -> multiple futures exist.\nUse the Redo button or the History view to select your desired future.")
-        }
       }
     }
 
@@ -425,6 +437,8 @@ export function getDemoLive() {
       srcName+'--('+label+')-->'+tgtName;
 
     return <>
+      <MantineProvider>
+      <ModalsProvider>
       <OnionContext.Provider value={{generateUUID, primitiveRegistry}}>
         <SimpleGrid cols={2}>
           <Stack>
@@ -518,7 +532,7 @@ export function getDemoLive() {
               </>}>
               <div style={{backgroundColor:"#eee"}}>{
                 runtimeStuff.states.length > 0 ?
-                <Graphviz dot={runtimeStuff.dotGraph} options={{fit:false, width:null, height:null}} />
+                <GraphvizComponent dot={runtimeStuff.dotGraph} options={{fit:false, width:null, height:null}} />
                 : <Center position="center" style={{padding:20}}>
                     <Text>FSA will appear here.</Text>
                   </Center>
@@ -533,6 +547,8 @@ export function getDemoLive() {
           </Stack>
         </SimpleGrid>
       </OnionContext.Provider>
+      </ModalsProvider>
+      </MantineProvider>
     </>;
   }
 }

+ 19 - 0
src/frontend/graphviz.tsx

@@ -0,0 +1,19 @@
+import * as React from "react";
+
+const viz = import("@viz-js/viz").then(module => module.instance());
+
+export function GraphvizComponent({dot, options}) {
+  const [svg, setSvg] = React.useState<string>("");
+
+  React.useEffect(() => {
+    viz.then(viz => {
+      // TODO: move this function to a Web Worker
+      const {output} = viz.render(dot, {format: 'svg'});
+      if (output !== undefined) {
+        setSvg(output);
+      }
+    });
+  }, [dot]);
+
+  return <div dangerouslySetInnerHTML={{__html:svg}}/>;
+}

+ 2 - 2
src/frontend/versioned_model/graph_view.tsx

@@ -1,6 +1,6 @@
 import * as React from "react";
 import * as Mantine from "@mantine/core";
-import { Graphviz } from 'graphviz-react';
+import { GraphvizComponent } from '../graphviz';
 
 import {D3Graph, D3GraphData, D3NodeData, defaultGraphForces} from "../d3graph/d3graph";
 import {InfoHoverCardOverlay} from "../info_hover_card";
@@ -46,7 +46,7 @@ export function GraphView<N,L>(props: GraphViewProps<N,L>) {
 
   // @ts-ignore:
   const graphviz = <Mantine.ScrollArea style={{backgroundColor:"#eee"}}>
-      <Graphviz dot={`digraph {
+      <GraphvizComponent dot={`digraph {
         bgcolor="transparent";
         ${graphData.nodes.map(node => `"${esc(node.id)}" [${node.label===""?`shape=circle, width=0.3, height=0.3`:`shape=box`}, label="${esc(node.label)}", fillcolor="${node.color}", style="filled,rounded", ${node.bold?`penwidth=4.0,`:``} URL="javascript:${esc2(`graphvizClicked('${id+node.id}', 2)`)}"]`).join('\n')}
         ${graphData.links.map(link => `"${esc(link.source.id || link.source)}" -> "${esc(link.target.id || link.target)}" [label="${esc(link.label)}", fontcolor="${link.color}", color="${link.color}"${link.bidirectional?`, dir=none`:``}]`).join('\n')}

+ 1 - 2
src/frontend/versioned_model/single_model.tsx

@@ -292,12 +292,11 @@ export function newOnion({readonly, primitiveRegistry}, versionRegistry?) {
       if (parentsOrChildren.length === 1) {
         return <Mantine.Button compact leftIcon={leftIcon} rightIcon={rightIcon} onClick={callback?.bind(null, parentsOrChildren[0][0], parentsOrChildren[0][1])}>{text}</Mantine.Button>;
       }
-      return <Mantine.Menu shadow="md" position="bottom-start" trigger="hover" offset={0} transitionDuration={0}>
+      return <Mantine.Menu shadow="md" position="bottom-start" trigger="hover" offset={0} transitionProps={{duration:0}}>
           <Mantine.Menu.Target>
             <Mantine.Button compact leftIcon={leftIcon} rightIcon={rightIcon}>{text} ({parentsOrChildren.length.toString()})</Mantine.Button>
           </Mantine.Menu.Target>
           <Mantine.Menu.Dropdown>
-            {/*<Mantine.Menu.Label>{text}</Mantine.Menu.Label>*/}
             {parentsOrChildren.map(([parentOrChildVersion,deltaToUndoOrRedo]) =>
               <Mantine.Menu.Item key={fullDeltaId(deltaToUndoOrRedo)} onClick={callback?.bind(null, parentOrChildVersion, deltaToUndoOrRedo)}>{deltaToUndoOrRedo.getDescription()}</Mantine.Menu.Item>)}
           </Mantine.Menu.Dropdown>