From 93505d58b6719a9144d23ed64140cb6eead088cf Mon Sep 17 00:00:00 2001 From: Ruben Thoms Date: Thu, 21 Sep 2023 15:49:50 +0200 Subject: [PATCH] Improvements to GUI - Changed icon set to MUI/Google Material Icons (replaced all icons) - Modules only highlighted when in modules settings/sync settings - Removed LoginDialog and replaced with StartScreen - Opening module list when layout is empty (all modules removed) - Added optional description to modules and added info dialog to modules list items --- frontend/package-lock.json | 25 ++-- frontend/package.json | 2 +- frontend/src/App.tsx | 12 +- frontend/src/GlobalErrorBoundary.tsx | 6 +- frontend/src/framework/Module.tsx | 16 ++- frontend/src/framework/ModuleRegistry.ts | 4 +- .../private-components/crashView.tsx | 14 +-- .../ViewWrapper/private-components/header.tsx | 4 +- .../ViewWrapper/viewWrapper.tsx | 4 +- .../internal/components/Drawer/drawer.tsx | 6 +- .../components/LoginButton/loginButton.tsx | 8 +- .../internal/components/LoginDialog/index.ts | 1 - .../components/LoginDialog/loginDialog.tsx | 33 ------ .../internal/components/NavBar/navBar.tsx | 76 ++++++++---- .../selectEnsemblesDialog.tsx | 10 +- .../colorPaletteSettings.tsx | 10 +- .../private-components/modulesList.tsx | 111 +++++++++++++----- .../Settings/private-components/setting.tsx | 4 +- .../private-components/syncSettings.tsx | 12 +- .../private-components/templatesList.tsx | 4 +- .../internal/components/Settings/settings.tsx | 4 +- .../internal/components/StartScreen/index.ts | 1 + .../components/StartScreen/startScreen.tsx | 40 +++++++ .../CollapsibleGroup/collapsibleGroup.tsx | 4 +- frontend/src/lib/components/Dialog/dialog.tsx | 4 +- .../src/lib/components/Dropdown/dropdown.tsx | 4 +- frontend/src/lib/components/Label/label.tsx | 4 +- .../src/lib/components/ListBox/list-box.tsx | 6 +- .../private-components/tag.tsx | 21 ++-- .../SmartNodeSelector/smartNodeSelector.tsx | 4 +- frontend/src/lib/components/Table/table.tsx | 8 +- frontend/src/main.tsx | 9 +- .../src/modules/MyModule/registerModule.ts | 6 +- frontend/src/modules/Sensitivity/view.tsx | 15 ++- .../SimulationTimeSeries/registerModule.ts | 3 +- 35 files changed, 286 insertions(+), 209 deletions(-) delete mode 100644 frontend/src/framework/internal/components/LoginDialog/index.ts delete mode 100644 frontend/src/framework/internal/components/LoginDialog/loginDialog.tsx create mode 100644 frontend/src/framework/internal/components/StartScreen/index.ts create mode 100644 frontend/src/framework/internal/components/StartScreen/startScreen.tsx diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 9dc9be156..06fad83bd 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -9,8 +9,8 @@ "version": "0.0.0", "dependencies": { "@headlessui/react": "^1.7.8", - "@heroicons/react": "^2.0.14", "@mui/base": "^5.0.0-beta.3", + "@mui/icons-material": "^5.14.9", "@tanstack/react-query": "^4.24.10", "@tanstack/react-query-devtools": "^4.24.12", "@webviz/subsurface-viewer": "^0.0.2-alpha.9", @@ -647,9 +647,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.22.11", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.11.tgz", - "integrity": "sha512-ee7jVNlWN09+KftVOu9n7S8gQzD/Z6hN/I8VBRXW4P1+Xe7kJGXMwu8vds4aGIMHZnNbdpSWCfZZtinytpcAvA==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.15.tgz", + "integrity": "sha512-T0O+aa+4w0u06iNmapipJXMV4HoUir03hpx3/YqXXhu9xim3w+dVphjFWl1OH8NbZHw5Lbm9k45drDkgq2VNNA==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -1408,14 +1408,6 @@ "react-dom": "^16 || ^17 || ^18" } }, - "node_modules/@heroicons/react": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/@heroicons/react/-/react-2.0.18.tgz", - "integrity": "sha512-7TyMjRrZZMBPa+/5Y8lN0iyvUU/01PeMGX2+RE7cQWpEUIcb4QotzUObFkJDejj/HUH4qjP/eQ0gzzKs2f+6Yw==", - "peerDependencies": { - "react": ">= 16" - } - }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", @@ -2791,12 +2783,11 @@ } }, "node_modules/@mui/icons-material": { - "version": "5.14.7", - "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.14.7.tgz", - "integrity": "sha512-mWp4DwMa8c1Gx9yOEtPgxM4b+e6hAbtZyzfSubdBwrnEE6G5D2rbAJ5MB+If6kfI48JaYaJ5j8+zAdmZLuZc0A==", - "peer": true, + "version": "5.14.9", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.14.9.tgz", + "integrity": "sha512-xTRQbDsogsJo7tY5Og8R9zbuG2q+KIPVIM6JQoKxtJlz9DPOw1u0T2fGrvwD+XAOVifQf6epNMcGCDLfJAz4Nw==", "dependencies": { - "@babel/runtime": "^7.22.10" + "@babel/runtime": "^7.22.15" }, "engines": { "node": ">=12.0.0" diff --git a/frontend/package.json b/frontend/package.json index 968995756..dc3cd32be 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -16,8 +16,8 @@ }, "dependencies": { "@headlessui/react": "^1.7.8", - "@heroicons/react": "^2.0.14", "@mui/base": "^5.0.0-beta.3", + "@mui/icons-material": "^5.14.9", "@tanstack/react-query": "^4.24.10", "@tanstack/react-query-devtools": "^4.24.12", "@webviz/subsurface-viewer": "^0.0.2-alpha.9", diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 4a0e9b82f..5f7e01cd2 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,7 +1,6 @@ import React from "react"; import { DrawerContent, LayoutElement, Workbench } from "@framework/Workbench"; -import { LoginDialog } from "@framework/internal/components/LoginDialog"; import { NavBar } from "@framework/internal/components/NavBar"; import { SettingsContentPanels } from "@framework/internal/components/SettingsContentPanels"; import { useQueryClient } from "@tanstack/react-query"; @@ -41,13 +40,10 @@ function App() { }, []); return ( - <> - -
- - -
- +
+ + +
); } diff --git a/frontend/src/GlobalErrorBoundary.tsx b/frontend/src/GlobalErrorBoundary.tsx index 5c1adc268..446b666f1 100644 --- a/frontend/src/GlobalErrorBoundary.tsx +++ b/frontend/src/GlobalErrorBoundary.tsx @@ -1,9 +1,9 @@ import React from "react"; -import { BugAntIcon, Square2StackIcon } from "@heroicons/react/20/solid"; import { Button } from "@lib/components/Button"; import { IconButton } from "@lib/components/IconButton"; import { resolveClassNames } from "@lib/utils/resolveClassNames"; +import { BugReport, ContentCopy } from "@mui/icons-material"; type Props = { children?: React.ReactNode; @@ -68,7 +68,7 @@ export class GlobalErrorBoundary extends React.Component { {freshStartUrl.toString()} - +
{ this.state.error?.stack ?? "" ) } - startIcon={} + startIcon={} > Report issue diff --git a/frontend/src/framework/Module.tsx b/frontend/src/framework/Module.tsx index c58fd420e..f9eb9dc96 100644 --- a/frontend/src/framework/Module.tsx +++ b/frontend/src/framework/Module.tsx @@ -44,13 +44,15 @@ export class Module { private _syncableSettingKeys: SyncSettingKey[]; private _channelsDef: BroadcastChannelsDef; private _drawPreviewFunc: DrawPreviewFunc | null; + private _description: string | null; constructor( name: string, defaultTitle: string, syncableSettingKeys: SyncSettingKey[] = [], broadcastChannelsDef: BroadcastChannelsDef = {}, - drawPreviewFunc: DrawPreviewFunc | null = null + drawPreviewFunc: DrawPreviewFunc | null = null, + description: string | null = null ) { this._name = name; this._defaultTitle = defaultTitle; @@ -63,6 +65,7 @@ export class Module { this._syncableSettingKeys = syncableSettingKeys; this._channelsDef = broadcastChannelsDef; this._drawPreviewFunc = drawPreviewFunc; + this._description = description; } getDrawPreviewFunc(): DrawPreviewFunc | null { @@ -73,14 +76,18 @@ export class Module { return this._importState; } - getName() { + getName(): string { return this._name; } - getDefaultTitle() { + getDefaultTitle(): string { return this._defaultTitle; } + getDescription(): string | null { + return this._description; + } + setWorkbench(workbench: Workbench): void { this._workbench = workbench; } @@ -99,14 +106,11 @@ export class Module { return this._syncableSettingKeys; } - hasSyncableSettingKey(key: SyncSettingKey): boolean { return this._syncableSettingKeys.includes(key); } - makeInstance(instanceNumber: number): ModuleInstance { - if (!this._workbench) { throw new Error("Module must be added to a workbench before making an instance"); } diff --git a/frontend/src/framework/ModuleRegistry.ts b/frontend/src/framework/ModuleRegistry.ts index 113f3eb08..34064da6f 100644 --- a/frontend/src/framework/ModuleRegistry.ts +++ b/frontend/src/framework/ModuleRegistry.ts @@ -10,6 +10,7 @@ export type RegisterModuleOptions = { syncableSettingKeys?: SyncSettingKey[]; broadcastChannelsDef?: BroadcastChannelsDef; preview?: DrawPreviewFunc; + description?: string; }; export class ModuleRegistry { @@ -26,7 +27,8 @@ export class ModuleRegistry { options.defaultTitle, options.syncableSettingKeys, options.broadcastChannelsDef, - options.preview || null + options.preview ?? null, + options.description ?? null ); this._registeredModules[options.moduleName] = module; return module; diff --git a/frontend/src/framework/internal/components/Content/private-components/ViewWrapper/private-components/crashView.tsx b/frontend/src/framework/internal/components/Content/private-components/ViewWrapper/private-components/crashView.tsx index 179ed3ad5..51d067680 100644 --- a/frontend/src/framework/internal/components/Content/private-components/ViewWrapper/private-components/crashView.tsx +++ b/frontend/src/framework/internal/components/Content/private-components/ViewWrapper/private-components/crashView.tsx @@ -1,8 +1,8 @@ import React from "react"; -import { ArrowPathIcon, DocumentMagnifyingGlassIcon, FaceFrownIcon, MegaphoneIcon } from "@heroicons/react/20/solid"; import { Button } from "@lib/components/Button"; import { Dialog } from "@lib/components/Dialog"; +import { BugReport, Info, MoodBad, Refresh } from "@mui/icons-material"; export type FormattedErrorProps = { moduleName: string; @@ -79,24 +79,20 @@ export const CrashView: React.FC = (props) => { return (
- +
{props.error.message}
The above error made your module instance crash. Unfortunately, this means that its state is lost. You can try to reset the instance to its initial state in order to start over.
- - -
diff --git a/frontend/src/framework/internal/components/Content/private-components/ViewWrapper/private-components/header.tsx b/frontend/src/framework/internal/components/Content/private-components/ViewWrapper/private-components/header.tsx index c9acc4517..2208b481b 100644 --- a/frontend/src/framework/internal/components/Content/private-components/ViewWrapper/private-components/header.tsx +++ b/frontend/src/framework/internal/components/Content/private-components/ViewWrapper/private-components/header.tsx @@ -2,8 +2,8 @@ import React from "react"; import { ModuleInstance } from "@framework/ModuleInstance"; import { SyncSettingKey, SyncSettingsMeta } from "@framework/SyncSettings"; -import { XMarkIcon } from "@heroicons/react/20/solid"; import { isDevMode } from "@lib/utils/devMode"; +import { Close } from "@mui/icons-material"; export type HeaderProps = { moduleInstance: ModuleInstance; @@ -75,7 +75,7 @@ export const Header: React.FC = (props) => { onPointerDown={props.onRemoveClick} title="Remove this module" > - +
); diff --git a/frontend/src/framework/internal/components/Content/private-components/ViewWrapper/viewWrapper.tsx b/frontend/src/framework/internal/components/Content/private-components/ViewWrapper/viewWrapper.tsx index c00cb8e2a..c284464fd 100644 --- a/frontend/src/framework/internal/components/Content/private-components/ViewWrapper/viewWrapper.tsx +++ b/frontend/src/framework/internal/components/Content/private-components/ViewWrapper/viewWrapper.tsx @@ -92,6 +92,8 @@ export const ViewWrapper: React.FC = (props) => { handleModuleClick(); } + const showAsActive = props.isActive && [DrawerContent.ModuleSettings, DrawerContent.SyncSettings].includes(drawerContent); + return ( <> {props.isDragged && ( @@ -111,7 +113,7 @@ export const ViewWrapper: React.FC = (props) => { >
= (props) => { return (
- {props.icon && React.cloneElement(props.icon, { className: "w-5 h-5 mr-2" })} + {props.icon && React.cloneElement(props.icon, { fontSize: "small", className: "mr-2" })} {props.title}
@@ -25,7 +25,7 @@ export const Drawer: React.FC = (props) => {
} + startAdornment={} onChange={props.onFilterChange} />
diff --git a/frontend/src/framework/internal/components/LoginButton/loginButton.tsx b/frontend/src/framework/internal/components/LoginButton/loginButton.tsx index bc365854c..6e514c6dc 100644 --- a/frontend/src/framework/internal/components/LoginButton/loginButton.tsx +++ b/frontend/src/framework/internal/components/LoginButton/loginButton.tsx @@ -1,13 +1,13 @@ import React from "react"; import { AuthState, useAuthProvider } from "@framework/internal/providers/AuthProvider"; -import { ArrowLeftOnRectangleIcon, ArrowRightOnRectangleIcon, UserIcon } from "@heroicons/react/20/solid"; import { CircularProgress } from "@lib/components/CircularProgress"; import { Menu } from "@lib/components/Menu"; import { MenuItem } from "@lib/components/MenuItem"; import { resolveClassNames } from "@lib/utils/resolveClassNames"; import { getTextWidth } from "@lib/utils/textSize"; import { Dropdown, MenuButton } from "@mui/base"; +import { AccountCircle, Login, Logout } from "@mui/icons-material"; export type LoginButtonProps = { className?: string; @@ -29,9 +29,9 @@ export const LoginButton: React.FC = (props) => { function makeIcon() { if (authState === AuthState.LoggedIn) { - return ; + return ; } else if (authState === AuthState.NotLoggedIn) { - return ; + return ; } else { return ; } @@ -81,7 +81,7 @@ export const LoginButton: React.FC = (props) => { - + Sign out diff --git a/frontend/src/framework/internal/components/LoginDialog/index.ts b/frontend/src/framework/internal/components/LoginDialog/index.ts deleted file mode 100644 index 3b09d5b99..000000000 --- a/frontend/src/framework/internal/components/LoginDialog/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { LoginDialog } from "./loginDialog"; diff --git a/frontend/src/framework/internal/components/LoginDialog/loginDialog.tsx b/frontend/src/framework/internal/components/LoginDialog/loginDialog.tsx deleted file mode 100644 index dfd5cb46d..000000000 --- a/frontend/src/framework/internal/components/LoginDialog/loginDialog.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import React from "react"; - -import { AuthState, useAuthProvider } from "@framework/internal/providers/AuthProvider"; -import { Button } from "@lib/components/Button"; -import { CircularProgress } from "@lib/components/CircularProgress"; -import { Dialog } from "@lib/components/Dialog"; - -export const LoginDialog: React.FC = () => { - const auth = useAuthProvider(); - - function signIn() { - window.location.href = `/api/login?redirect_url_after_login=${btoa("/")}`; - } - - if (auth.authState !== AuthState.LoggedIn) { - return ( - - {auth.authState === AuthState.NotLoggedIn ? "Sign in" : } - - } - > - You have to sign in in order to use this application. - - ); - } else { - return null; - } -}; diff --git a/frontend/src/framework/internal/components/NavBar/navBar.tsx b/frontend/src/framework/internal/components/NavBar/navBar.tsx index ccff4ee24..11c0c6f40 100644 --- a/frontend/src/framework/internal/components/NavBar/navBar.tsx +++ b/frontend/src/framework/internal/components/NavBar/navBar.tsx @@ -3,27 +3,27 @@ import React from "react"; import WebvizLogo from "@assets/webviz.svg"; import { EnsembleIdent } from "@framework/EnsembleIdent"; import { useStoreState } from "@framework/StateStore"; -import { DrawerContent, Workbench } from "@framework/Workbench"; +import { DrawerContent, Workbench, WorkbenchEvents } from "@framework/Workbench"; import { useEnsembleSet } from "@framework/WorkbenchSession"; import { LoginButton } from "@framework/internal/components/LoginButton"; import { SelectEnsemblesDialog } from "@framework/internal/components/SelectEnsemblesDialog"; import { EnsembleItem } from "@framework/internal/components/SelectEnsemblesDialog/selectEnsemblesDialog"; -import { - ChevronLeftIcon, - ChevronRightIcon, - Cog6ToothIcon, - LinkIcon, - QueueListIcon, - Squares2X2Icon, - StarIcon, - SwatchIcon, - WindowIcon, -} from "@heroicons/react/20/solid"; import { Badge } from "@lib/components/Badge"; import { Button } from "@lib/components/Button"; import { CircularProgress } from "@lib/components/CircularProgress"; import { isDevMode } from "@lib/utils/devMode"; import { resolveClassNames } from "@lib/utils/resolveClassNames"; +import { + ChevronLeft, + ChevronRight, + GitHub, + GridView, + Link, + List, + Palette, + Settings, + WebAsset, +} from "@mui/icons-material"; import { useQueryClient } from "@tanstack/react-query"; type NavBarProps = { @@ -36,6 +36,7 @@ const NavBarDivider: React.FC = () => { export const NavBar: React.FC = (props) => { const [ensembleDialogOpen, setEnsembleDialogOpen] = React.useState(false); + const [layoutEmpty, setLayoutEmpty] = React.useState(props.workbench.getLayout().length === 0); const [expanded, setExpanded] = React.useState(localStorage.getItem("navBarExpanded") === "true"); const [loadingEnsembleSet, setLoadingEnsembleSet] = useStoreState( props.workbench.getGuiStateStore(), @@ -50,6 +51,27 @@ export const NavBar: React.FC = (props) => { const queryClient = useQueryClient(); + React.useEffect( + function reactToModuleInstancesChanged() { + function listener() { + if ( + props.workbench.getLayout().length === 0 && + [DrawerContent.ModuleSettings, DrawerContent.SyncSettings].includes(drawerContent) + ) { + setDrawerContent(DrawerContent.ModulesList); + } + setLayoutEmpty(props.workbench.getLayout().length === 0); + } + + const unsubscribeFunc = props.workbench.subscribe(WorkbenchEvents.ModuleInstancesChanged, listener); + + return () => { + unsubscribeFunc(); + }; + }, + [drawerContent] + ); + function ensureSettingsPanelIsVisible() { if (settingsPanelWidth <= 5) { setSettingsPanelWidth(20); @@ -126,7 +148,7 @@ export const NavBar: React.FC = (props) => { className="!text-slate-800" title={expanded ? "Collapse menu" : "Expand menu"} > - {expanded ? : } + {expanded ? : }
@@ -136,7 +158,7 @@ export const NavBar: React.FC = (props) => { className="w-full !text-slate-800 h-10" startIcon={ selectedEnsembles.length === 0 && !loadingEnsembleSet ? ( - + ) : ( = (props) => { ) } > - + ) } @@ -160,24 +182,26 @@ export const NavBar: React.FC = (props) => { @@ -185,11 +209,11 @@ export const NavBar: React.FC = (props) => { diff --git a/frontend/src/framework/internal/components/SelectEnsemblesDialog/selectEnsemblesDialog.tsx b/frontend/src/framework/internal/components/SelectEnsemblesDialog/selectEnsemblesDialog.tsx index f3be24941..618bc9666 100644 --- a/frontend/src/framework/internal/components/SelectEnsemblesDialog/selectEnsemblesDialog.tsx +++ b/frontend/src/framework/internal/components/SelectEnsemblesDialog/selectEnsemblesDialog.tsx @@ -2,7 +2,6 @@ import React from "react"; import { CaseInfo_api, EnsembleInfo_api } from "@api"; import { apiService } from "@framework/ApiService"; -import { CheckIcon, PlusIcon, TrashIcon } from "@heroicons/react/20/solid"; import { ApiStateWrapper } from "@lib/components/ApiStateWrapper"; import { Button } from "@lib/components/Button"; import { CircularProgress } from "@lib/components/CircularProgress"; @@ -12,6 +11,7 @@ import { IconButton } from "@lib/components/IconButton"; import { Label } from "@lib/components/Label"; import { Select } from "@lib/components/Select"; import { useValidState } from "@lib/hooks/useValidState"; +import { Add, Check, Remove } from "@mui/icons-material"; import { useQuery } from "@tanstack/react-query"; import { isEqual } from "lodash"; @@ -232,11 +232,7 @@ export const SelectEnsemblesDialog: React.FC = (prop color={ensembleAlreadySelected ? "success" : "primary"} disabled={ensembleAlreadySelected || ensembleOpts.length === 0} startIcon={ - ensembleAlreadySelected ? ( - - ) : ( - - ) + ensembleAlreadySelected ? : } > {ensembleAlreadySelected ? "Ensemble already selected" : "Add Ensemble"} @@ -282,7 +278,7 @@ export const SelectEnsemblesDialog: React.FC = (prop } color="danger" > - + {" "} diff --git a/frontend/src/framework/internal/components/Settings/private-components/colorPaletteSettings.tsx b/frontend/src/framework/internal/components/Settings/private-components/colorPaletteSettings.tsx index e21fd805d..eb9af71fa 100644 --- a/frontend/src/framework/internal/components/Settings/private-components/colorPaletteSettings.tsx +++ b/frontend/src/framework/internal/components/Settings/private-components/colorPaletteSettings.tsx @@ -5,7 +5,6 @@ import { useStoreValue } from "@framework/StateStore"; import { DrawerContent, Workbench } from "@framework/Workbench"; import { ColorPaletteType, ColorScaleDiscreteSteps } from "@framework/WorkbenchSettings"; import { Drawer } from "@framework/internal/components/Drawer"; -import { ChevronDownIcon } from "@heroicons/react/20/solid"; import { ColorGradient } from "@lib/components/ColorGradient"; import { ColorTileGroup } from "@lib/components/ColorTileGroup"; import { IconButton } from "@lib/components/IconButton"; @@ -16,6 +15,7 @@ import { useElementBoundingRect } from "@lib/hooks/useElementBoundingRect"; import { ColorPalette } from "@lib/utils/ColorPalette"; import { resolveClassNames } from "@lib/utils/resolveClassNames"; import { convertRemToPixels } from "@lib/utils/screenUnitConversions"; +import { ExpandMore, Palette } from "@mui/icons-material"; enum ColorPaletteSelectorType { Categorical = "categorical", @@ -144,7 +144,7 @@ const ColorPaletteSelector: React.FC = (props) => {
{makeColorPalettePreview(selectedColorPalette, props.type, props.steps)}
- + {open && ReactDOM.createPortal( @@ -201,7 +201,11 @@ export const ColorPaletteSettings: React.FC = (props) } return ( - + } + visible={drawerContent === DrawerContent.ColorPaletteSettings} + >