Skip to content

Commit

Permalink
more ui features (#314)
Browse files Browse the repository at this point in the history
* lift exec into layout; fix cancel button

* add iterations to results

* fix cfg saving to localstorage; fix nested <a>

* fix card styling

* add sample tab

* stop it vscode

* super dumb debugger

* fix dumb linting rule
  • Loading branch information
srliao authored Oct 23, 2024
1 parent e3a3d55 commit 67e388b
Show file tree
Hide file tree
Showing 37 changed files with 1,840 additions and 259 deletions.
9 changes: 9 additions & 0 deletions .task/protos/taskfile.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
version: "3"

tasks:
default:
desc: run all protos generation
cmds:
- task: go
- task: ts-types
go:
desc: generate go code
cmds:
Expand All @@ -26,3 +31,7 @@ tasks:
--ts_proto_opt=useJsonName=true \
--ts_proto_opt=outputIndex=true \
pb/**/*.proto
tygo:
desc: run tygo
dir: js/packages/ts-types
cmd: go run github.com/gzuidhof/tygo@latest generate
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
"source.fixAll.eslint": "explicit"
},

"[javascript]": {
Expand Down
19 changes: 19 additions & 0 deletions Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,22 @@ tasks:
cmds:
- go test ./pkg/... ./tests/...
- golangci-lint run --fast --fix --print-issued-lines=false --out-format=colored-line-number --issues-exit-code=0
servermode:
desc: watches for change and launches server mode
watch: true
sources:
- "**/*.go"
vars:
WIN_CMD: Get-CimInstance -ClassName Win32_PRocess -Filter "CommandLine LIKE '%GCSIM_SERVER%'" | ForEach-Object -Process {taskkill /F /PID $_.ProcessId}
cmds:
- cmd: powershell {{shellQuote .WIN_CMD}}
platforms: [windows]
ignore_error: true
- cmd: pkill -f SRSIM_SERVER=1
platforms: [linux, darwin]
ignore_error: true
- go run cmd/server/main.go SRSIM_SERVER=1
webdev:
internal: true
dir: js
cmd: pnpm start
2 changes: 1 addition & 1 deletion js/apps/storybook/src/stories/Result/RollupCard.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ type Story = StoryObj<typeof meta>;
// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args
export const Primary: Story = {
args: {
color: "bg-red",
color: "bg-red-500",
title: "Damage Per Cycle (DPC)",
value: "66,000",
auxStats: [
Expand Down
1 change: 1 addition & 0 deletions js/apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"react": "^18",
"react-dom": "^18",
"react-dropzone": "^14.2.3",
"react-icons": "^5.3.0",
"sonner": "^1.5.0",
"ui": "workspace:*"
},
Expand Down
54 changes: 54 additions & 0 deletions js/apps/web/src/app/exec/provider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
"use client";
import React, { createContext, ReactNode } from "react";
import { Executor, ExecutorSupplier, NullExecutor, ServerExecutor } from "@srsim/executor";

type ExecutorContextProviderProps = {
children: ReactNode;
};

type ExecutorContextType = {
supplier: ExecutorSupplier<Executor>;
};

export const ExecutorContext = createContext<ExecutorContextType>({
supplier: () => {
return new NullExecutor();
},
});

let exec: ServerExecutor | undefined;
const urlKey = "server-mode-url";
const defaultURL = "http://127.0.0.1:54321";

export const ExecutorProvider = ({ children }: ExecutorContextProviderProps) => {
const [url, setURL] = React.useState<string>(defaultURL);
React.useEffect(() => {
if (typeof window !== "undefined") {
const saved = window.localStorage.getItem(urlKey);
if (saved === null) {
window.localStorage.setItem(urlKey, defaultURL);
return;
}
setURL(saved);
}
}, []);
React.useEffect(() => {
if (typeof window !== "undefined") {
window.localStorage.setItem(urlKey, url);
}
if (exec != null) {
exec.set_url(url);
}
}, [url]);
const supplier = React.useRef<ExecutorSupplier<Executor>>(() => {
if (exec == null) {
exec = new ServerExecutor(url);
}
return exec;
});
return (
<ExecutorContext.Provider value={{ supplier: supplier.current }}>
{children}
</ExecutorContext.Provider>
);
};
40 changes: 22 additions & 18 deletions js/apps/web/src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import type {Metadata} from 'next';
import {Inter} from 'next/font/google';
import '@ui/styles/globals.css';
import {ThemeProvider} from '../components/theme-provider';
import {cn} from 'ui/src/lib/utils';
import {Toaster} from 'ui';
import {ViewerProvider} from './viewer/provider';
import Navigation from './navigation';
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "@ui/styles/globals.css";
import { ThemeProvider } from "../components/theme-provider";
import { cn } from "ui/src/lib/utils";
import { Toaster } from "ui";
import { ViewerProvider } from "./viewer/provider";
import { ExecutorProvider } from "./exec/provider";
import Navigation from "./navigation";

const inter = Inter({subsets: ['latin']});
const inter = Inter({ subsets: ["latin"] });

export const metadata: Metadata = {
title: 'srsim',
title: "srsim",
};

export default function RootLayout({
Expand All @@ -20,18 +21,21 @@ export default function RootLayout({
}>) {
return (
<html lang="en">
<body className={cn('bg-background h-screen', inter.className)}>
<body className={cn("bg-background h-screen", inter.className)}>
<ThemeProvider
attribute="class"
defaultTheme="system"
enableSystem
disableTransitionOnChange>
<ViewerProvider>
<>
<Navigation />
{children}
</>
</ViewerProvider>
disableTransitionOnChange
>
<ExecutorProvider>
<ViewerProvider>
<>
<Navigation />
{children}
</>
</ViewerProvider>
</ExecutorProvider>
<Toaster />
</ThemeProvider>
</body>
Expand Down
22 changes: 9 additions & 13 deletions js/apps/web/src/app/navigation.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
'use client';
import Link from 'next/link';
import {useRouter} from 'next/navigation';
import React from 'react';
"use client";
import Link from "next/link";
import { useRouter } from "next/navigation";
import React from "react";
import {
NavigationMenu,
NavigationMenuItem,
NavigationMenuLink,
NavigationMenuList,
navigationMenuTriggerStyle,
} from 'ui';
} from "ui";

export default function Navigation() {
const router = useRouter();
Expand All @@ -17,19 +17,15 @@ export default function Navigation() {
<NavigationMenu>
<NavigationMenuList>
<NavigationMenuItem>
<NavigationMenuLink className={navigationMenuTriggerStyle()}>
<Link href={'/'}>Simulator</Link>
<NavigationMenuLink className={navigationMenuTriggerStyle()} href="/">
Simulator
</NavigationMenuLink>
</NavigationMenuItem>
<NavigationMenuItem>
<NavigationMenuLink className={navigationMenuTriggerStyle()}>
Docs
</NavigationMenuLink>
<NavigationMenuLink className={navigationMenuTriggerStyle()}>Docs</NavigationMenuLink>
</NavigationMenuItem>
<NavigationMenuItem>
<NavigationMenuLink className={navigationMenuTriggerStyle()}>
About
</NavigationMenuLink>
<NavigationMenuLink className={navigationMenuTriggerStyle()}>About</NavigationMenuLink>
</NavigationMenuItem>
</NavigationMenuList>
</NavigationMenu>
Expand Down
86 changes: 26 additions & 60 deletions js/apps/web/src/app/simulator.tsx
Original file line number Diff line number Diff line change
@@ -1,48 +1,20 @@
"use client";
import React, { useRef } from "react";
import React from "react";
import { Button, Editor } from "@ui/components";
import { Executor, ExecutorSupplier, ServerExecutor } from "@srsim/executor";
import { Executor } from "@srsim/executor";
import { useRouter } from "next/navigation";
import { throttle } from "lodash-es";
import { model } from "@srsim/ts-types";
import { ViewerContext } from "./viewer/provider";

let exec: ServerExecutor | undefined;
const urlKey = "server-mode-url";
const defaultURL = "http://127.0.0.1:54321";
import { ExecutorContext } from "./exec/provider";

export default function Simulator() {
const [url, setURL] = React.useState<string>(defaultURL);
React.useEffect(() => {
if (typeof window !== "undefined") {
const saved = window.localStorage.getItem(urlKey);
if (saved === null) {
window.localStorage.setItem(urlKey, defaultURL);
return;
}
setURL(saved);
}
}, []);
React.useEffect(() => {
if (typeof window !== "undefined") {
window.localStorage.setItem(urlKey, url);
}
if (exec != null) {
exec.set_url(url);
}
}, [url]);
const supplier = useRef<ExecutorSupplier<ServerExecutor>>(() => {
if (exec == null) {
exec = new ServerExecutor(url);
}
return exec;
});

return <SimulatorCore exec={supplier.current} />;
const { supplier } = React.useContext(ExecutorContext);
return <SimulatorCore exec={supplier()} />;
}

type SimulatorCoreProps = {
exec: ExecutorSupplier<Executor>;
exec: Executor;
};

const DEFAULT_VIEWER_THROTTLE = 100;
Expand All @@ -54,56 +26,50 @@ const SimulatorCore = ({ exec }: SimulatorCoreProps) => {
const router = useRouter();
const [cfg, setCfg] = React.useState<string>("");
React.useEffect(() => {
if (typeof window !== "undefined") {
const saved = window.localStorage.getItem(cfgKey);
if (saved === null) {
window.localStorage.setItem(cfgKey, "");
return;
}
setCfg(saved);
const saved = localStorage.getItem(cfgKey);
if (saved === null) {
localStorage.setItem(cfgKey, "");
return;
}
setCfg(saved);
}, []);
React.useEffect(() => {
if (typeof window !== "undefined") {
window.localStorage.setItem(cfgKey, cfg);
}
}, [cfg]);
const updateCfg = (v: string) => {
setCfg(v);
localStorage.setItem(cfgKey, cfg);
};
const { dispatch } = React.useContext(ViewerContext);

const run = () => {
const updateResult = throttle(
(res: model.SimResult, iters: number, hash: string) => {
(res: model.SimResult, hash: string) => {
console.log("updating result", res);
dispatch({
type: "SET_RESULT",
payload: {
result: res,
progress: (100 * iters) / DEFAULT_ITERS,
done: iters === DEFAULT_ITERS,
progress: (100 * (res.statistics?.iterations ?? 0)) / DEFAULT_ITERS,
},
});
},
DEFAULT_VIEWER_THROTTLE,
{ leading: true, trailing: true }
);

exec()
.run(cfg, DEFAULT_ITERS, updateResult)
.catch(err => {
dispatch({
type: "SET_ERROR",
payload: {
error: err,
config: cfg,
},
});
exec.run(cfg, DEFAULT_ITERS, updateResult).catch(err => {
dispatch({
type: "SET_ERROR",
payload: {
error: err,
config: cfg,
},
});
});

router.push("/viewer");
};
return (
<div className="m-3">
<Editor cfg={cfg} onChange={v => setCfg(v)} className="mb-2"></Editor>
<Editor cfg={cfg} onChange={updateCfg} className="mb-2"></Editor>
<div className="sticky bottom-0 flex flex-col gap-y-1 z-10">
<Button variant="secondary" onClick={() => run()}>
Run
Expand Down
Loading

0 comments on commit 67e388b

Please sign in to comment.