You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by cd...@apache.org on 2023/12/09 11:48:23 UTC
(plc4x) branch feature/new-ui-tool updated: feat: Refactored the UI to have a more responsive layout.
This is an automated email from the ASF dual-hosted git repository.
cdutz pushed a commit to branch feature/new-ui-tool
in repository https://gitbox.apache.org/repos/asf/plc4x.git
The following commit(s) were added to refs/heads/feature/new-ui-tool by this push:
new 4c51a18aa5 feat: Refactored the UI to have a more responsive layout.
4c51a18aa5 is described below
commit 4c51a18aa539e09c4ff07c51fb431904584edf52
Author: Christofer Dutz <cd...@apache.org>
AuthorDate: Sat Dec 9 12:48:07 2023 +0100
feat: Refactored the UI to have a more responsive layout.
---
plc4j/tools/ui/frontend/frontend/package.json | 7 +-
plc4j/tools/ui/frontend/frontend/src/App.tsx | 209 ++-------------------
.../frontend/frontend/src/components/MainMenu.tsx | 80 ++++++++
.../ui/frontend/frontend/src/components/NavBar.tsx | 19 --
.../frontend/src/components/NavigationTree.tsx | 2 +-
.../frontend/frontend/src/layouts/MainLayout.tsx | 87 +++++++++
.../ui/frontend/frontend/src/pages/Editor.tsx | 11 ++
7 files changed, 200 insertions(+), 215 deletions(-)
diff --git a/plc4j/tools/ui/frontend/frontend/package.json b/plc4j/tools/ui/frontend/frontend/package.json
index bc0ac8b510..728597a923 100644
--- a/plc4j/tools/ui/frontend/frontend/package.json
+++ b/plc4j/tools/ui/frontend/frontend/package.json
@@ -10,12 +10,17 @@
"preview": "vite preview"
},
"dependencies": {
+ "@emotion/react": "^11.11.1",
+ "@emotion/styled": "^11.11.0",
+ "@mui/icons-material": "^5.14.19",
+ "@mui/material": "^5.14.20",
"axios": "^1.6.2",
"primeflex": "^3.3.1",
"primeicons": "^6.0.1",
"primereact": "^10.2.1",
"react": "^18.2.0",
- "react-dom": "^18.2.0"
+ "react-dom": "^18.2.0",
+ "react-router-dom": "^6.20.1"
},
"devDependencies": {
"@types/react": "^18.2.37",
diff --git a/plc4j/tools/ui/frontend/frontend/src/App.tsx b/plc4j/tools/ui/frontend/frontend/src/App.tsx
index 66b59e0432..b645aa9fff 100644
--- a/plc4j/tools/ui/frontend/frontend/src/App.tsx
+++ b/plc4j/tools/ui/frontend/frontend/src/App.tsx
@@ -18,206 +18,27 @@
*/
import './App.css'
-import NavigationTree from "./components/NavigationTree.tsx";
import axios from 'axios';
-import {useState} from "react";
-import {RestApplicationClient} from "./generated/plc4j-tools-ui-frontend.ts";
-import {TreeItemData} from "./model/TreeItemData.ts";
-import {TabPanel, TabView} from "primereact/tabview";
-import {Menubar} from "primereact/menubar";
-import {MenuItem} from "primereact/menuitem";
-import plc4xLogo from "./assets/plc4x-logo.svg";
-import { Splitter, SplitterPanel } from 'primereact/splitter';
-import {ScrollPanel} from "primereact/scrollpanel";
+import {createBrowserRouter, RouterProvider} from "react-router-dom";
+import MainLayout from "./layouts/MainLayout.tsx";
+import Editor from "./pages/Editor.tsx";
axios.defaults.baseURL = 'http://localhost:8080';
-function App() {
- const [driverTreeRoots, setDriverTreeRoots] = useState<TreeItemData[]>([])
- const restClient = new RestApplicationClient(axios);
- const start = <img alt="logo" src={plc4xLogo} height="40" className="mr-8"></img>;
- const menuModel: MenuItem[] = [
- /*{
- label: 'File',
- icon: 'pi pi-fw pi-file',
- items: [
- {
- label: 'New',
- icon: 'pi pi-fw pi-plus',
- items: [
- {
- label: 'Bookmark',
- icon: 'pi pi-fw pi-bookmark'
- },
- {
- label: 'Video',
- icon: 'pi pi-fw pi-video'
- },
-
- ]
- },
- {
- label: 'Delete',
- icon: 'pi pi-fw pi-trash'
- },
- {
- separator: true
- },
- {
- label: 'Export',
- icon: 'pi pi-fw pi-external-link'
- }
- ]
- },
- {
- label: 'Edit',
- icon: 'pi pi-fw pi-pencil',
- items: [
- {
- label: 'Left',
- icon: 'pi pi-fw pi-align-left'
- },
- {
- label: 'Right',
- icon: 'pi pi-fw pi-align-right'
- },
- {
- label: 'Center',
- icon: 'pi pi-fw pi-align-center'
- },
- {
- label: 'Justify',
- icon: 'pi pi-fw pi-align-justify'
- },
-
- ]
- },
- {
- label: 'Users',
- icon: 'pi pi-fw pi-user',
- items: [
- {
- label: 'New',
- icon: 'pi pi-fw pi-user-plus',
-
- },
- {
- label: 'Delete',
- icon: 'pi pi-fw pi-user-minus',
-
- },
- {
- label: 'Search',
- icon: 'pi pi-fw pi-users',
- items: [
- {
- label: 'Filter',
- icon: 'pi pi-fw pi-filter',
- items: [
- {
- label: 'Print',
- icon: 'pi pi-fw pi-print'
- }
- ]
- },
- {
- icon: 'pi pi-fw pi-bars',
- label: 'List'
- }
- ]
- }
- ]
- },
- {
- label: 'Events',
- icon: 'pi pi-fw pi-calendar',
- items: [
- {
- label: 'Edit',
- icon: 'pi pi-fw pi-pencil',
- items: [
- {
- label: 'Save',
- icon: 'pi pi-fw pi-calendar-plus'
- },
- {
- label: 'Delete',
- icon: 'pi pi-fw pi-calendar-minus'
- }
- ]
- },
- {
- label: 'Archive',
- icon: 'pi pi-fw pi-calendar-times',
- items: [
- {
- label: 'Remove',
- icon: 'pi pi-fw pi-calendar-minus'
- }
- ]
- }
- ]
- },*/
- {
- label: 'Dummy',
- icon: 'pi pi-fw pi-file',
- }
- ];
-
- function updateDriverList() {
- const driverList = restClient.getDriverList();
- driverList.then(response => {
- let newDriverTreeRoots: TreeItemData[] = [];
- response.data.map(driverValue => {
- newDriverTreeRoots = [...newDriverTreeRoots, {
- id: driverValue.code,
- name: driverValue.name,
- type: "DRIVER",
- supportsDiscovery: driverValue.supportsDiscovery,
- supportsBrowsing: false,
- supportsReading: false,
- supportsWriting: false,
- supportsSubscribing: false,
- supportsPublishing: false,
- }]
- })
- setDriverTreeRoots(newDriverTreeRoots)
- })
- }
- if(driverTreeRoots.length == 0) {
- updateDriverList()
- }
+// We're actually just using this concept in order to separate the layout for the general page from the content.
+const router = createBrowserRouter([
+ {
+ path: '/',
+ element: <MainLayout/>,
+ children: [
+ {path: '/', element: <Editor/>},
+ ]
+ },
+])
+function App() {
return (
- <div className="flex flex-column w-screen h-screen">
- <header>
- <Menubar start={start} model={menuModel}/>
- </header>
- <Splitter className="flex h-full">
- <SplitterPanel className="flex">
- <TabView style={{width: '100%', height:'100%'}}>
- <TabPanel header="By Driver" className="m-0">
- <ScrollPanel style={{width: '100%', height:'100%'}} className="h-full">
- <NavigationTree treeItems={driverTreeRoots}/>
- </ScrollPanel>
- </TabPanel>
- <TabPanel header="By Device">
- <ScrollPanel style={{width: '100%', height:'100%'}}>
- <NavigationTree treeItems={driverTreeRoots}/>
- </ScrollPanel>
- </TabPanel>
- </TabView>
- </SplitterPanel>
- <SplitterPanel className="w-full">
- <TabView>
-
- <TabPanel key={"ads://192.168.23.20"} header="ads://192.168.23.20" closable={true}>
- <p>test</p>
- </TabPanel>
- </TabView>
- </SplitterPanel>
- </Splitter>
- </div>
+ <RouterProvider router={router}/>
)
}
diff --git a/plc4j/tools/ui/frontend/frontend/src/components/MainMenu.tsx b/plc4j/tools/ui/frontend/frontend/src/components/MainMenu.tsx
new file mode 100644
index 0000000000..dd7a06cd06
--- /dev/null
+++ b/plc4j/tools/ui/frontend/frontend/src/components/MainMenu.tsx
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import plc4xLogo from "../assets/plc4x-logo.svg";
+import {Divider, Toolbar} from "@mui/material";
+import {Image} from "primereact/image";
+import {TabPanel, TabView} from "primereact/tabview";
+import {ScrollPanel} from "primereact/scrollpanel";
+import NavigationTree from "./NavigationTree.tsx";
+import {useState} from "react";
+import {TreeItemData} from "../model/TreeItemData.ts";
+import {RestApplicationClient} from "../generated/plc4j-tools-ui-frontend.ts";
+import axios from "axios";
+
+export default function MainMenu() {
+ const [driverTreeRoots, setDriverTreeRoots] = useState<TreeItemData[]>([])
+ const restClient = new RestApplicationClient(axios);
+
+ function updateDriverList() {
+ const driverList = restClient.getDriverList();
+ driverList.then(response => {
+ let newDriverTreeRoots: TreeItemData[] = [];
+ response.data.map(driverValue => {
+ newDriverTreeRoots = [...newDriverTreeRoots, {
+ id: driverValue.code,
+ name: driverValue.name,
+ type: "DRIVER",
+ supportsDiscovery: driverValue.supportsDiscovery,
+ supportsBrowsing: false,
+ supportsReading: false,
+ supportsWriting: false,
+ supportsSubscribing: false,
+ supportsPublishing: false,
+ }]
+ })
+ setDriverTreeRoots(newDriverTreeRoots)
+ })
+ }
+
+ if(driverTreeRoots.length == 0) {
+ updateDriverList()
+ }
+
+ return (
+ <div>
+ <Toolbar>
+ <Image src={plc4xLogo} width="200px"/>
+ </Toolbar>
+ <Divider/>
+ <TabView style={{width: '100%', height:'100%'}}>
+ <TabPanel header="By Driver" className="m-0">
+ <ScrollPanel style={{width: '100%', height:'100%'}} className="h-full">
+ <NavigationTree treeItems={driverTreeRoots}/>
+ </ScrollPanel>
+ </TabPanel>
+ <TabPanel header="By Device">
+ <ScrollPanel style={{width: '100%', height:'100%'}}>
+ <NavigationTree treeItems={driverTreeRoots}/>
+ </ScrollPanel>
+ </TabPanel>
+ </TabView>
+ </div>
+ )
+}
\ No newline at end of file
diff --git a/plc4j/tools/ui/frontend/frontend/src/components/NavBar.tsx b/plc4j/tools/ui/frontend/frontend/src/components/NavBar.tsx
deleted file mode 100644
index bd244d07ab..0000000000
--- a/plc4j/tools/ui/frontend/frontend/src/components/NavBar.tsx
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
diff --git a/plc4j/tools/ui/frontend/frontend/src/components/NavigationTree.tsx b/plc4j/tools/ui/frontend/frontend/src/components/NavigationTree.tsx
index 56741eec57..e6d4fad617 100644
--- a/plc4j/tools/ui/frontend/frontend/src/components/NavigationTree.tsx
+++ b/plc4j/tools/ui/frontend/frontend/src/components/NavigationTree.tsx
@@ -54,6 +54,6 @@ export default function NavigationTree({treeItems}: NavigationTreeProps) {
}
}
- let treeNodes: TreeNode[] = treeItems.map(value => createTreeNode(value))
+ const treeNodes: TreeNode[] = treeItems.map(value => createTreeNode(value))
return <Tree value={treeNodes} selectionMode="single"/>
}
\ No newline at end of file
diff --git a/plc4j/tools/ui/frontend/frontend/src/layouts/MainLayout.tsx b/plc4j/tools/ui/frontend/frontend/src/layouts/MainLayout.tsx
new file mode 100644
index 0000000000..91221e5674
--- /dev/null
+++ b/plc4j/tools/ui/frontend/frontend/src/layouts/MainLayout.tsx
@@ -0,0 +1,87 @@
+import {Outlet} from "react-router-dom";
+import {AppBar, Box, CssBaseline, Drawer, IconButton, Toolbar, Typography} from "@mui/material";
+import MenuIcon from "@mui/icons-material/Menu";
+import MainMenu from "../components/MainMenu.tsx";
+import React from "react";
+
+const drawerWidth = 480;
+
+export default function MainLayout() {
+ const [mobileOpen, setMobileOpen] = React.useState(false);
+
+ const handleDrawerToggle = () => {
+ setMobileOpen(!mobileOpen);
+ };
+
+ return(
+ <Box sx={{display: 'flex'}}>
+ <CssBaseline/>
+ {/* This is the main application bar */}
+ <AppBar
+ position="fixed"
+ sx={{
+ width: {sm: `calc(100% - ${drawerWidth}px)`},
+ ml: {sm: `${drawerWidth}px`},
+ }}>
+ <Toolbar>
+ {/* This is the menu button, which is displayed in very narrow screens (Hidden otherwise) */}
+ <IconButton
+ color="inherit"
+ aria-label="open drawer"
+ edge="start"
+ onClick={handleDrawerToggle}
+ sx={{mr: 2, display: {sm: 'none'}}}
+ >
+ <MenuIcon/>
+ </IconButton>
+ {/* This is the title text in the main application bar */}
+ <Typography variant="h6" noWrap component="div">
+ Responsive drawer
+ </Typography>
+ </Toolbar>
+ </AppBar>
+ {/* This is the drawer content (Menu) */}
+ <Box
+ component="nav"
+ sx={{width: {sm: drawerWidth}, flexShrink: {sm: 0}}}
+ aria-label="mailbox folders"
+ >
+ {/* This is the dynamic drawer used on mobile devices. */}
+ <Drawer
+ variant="temporary"
+ open={mobileOpen}
+ onClose={handleDrawerToggle}
+ ModalProps={{
+ keepMounted: true, // Better open performance on mobile.
+ }}
+ sx={{
+ display: {xs: 'block', sm: 'none'},
+ '& .MuiDrawer-paper': {boxSizing: 'border-box', width: drawerWidth},
+ }}
+ >
+ <MainMenu/>
+ </Drawer>
+ {/* This is the static drawer used on normal devices. */}
+ <Drawer
+ variant="permanent"
+ sx={{
+ display: {xs: 'none', sm: 'block'},
+ '& .MuiDrawer-paper': {boxSizing: 'border-box', width: drawerWidth},
+ }}
+ open
+ >
+ <MainMenu/>
+ </Drawer>
+ </Box>
+ {/* This is the main application content */}
+ <Box
+ component="main"
+ sx={{flexGrow: 1, p: 3, width: {sm: `calc(100% - ${drawerWidth}px)`}}}
+ >
+ {/* This is a dummy toolbar to prevent the content from going behind the real application bar */}
+ <Toolbar/>
+ <Outlet/>
+ </Box>
+ </Box>
+ )
+}
\ No newline at end of file
diff --git a/plc4j/tools/ui/frontend/frontend/src/pages/Editor.tsx b/plc4j/tools/ui/frontend/frontend/src/pages/Editor.tsx
new file mode 100644
index 0000000000..0e9f4a20cf
--- /dev/null
+++ b/plc4j/tools/ui/frontend/frontend/src/pages/Editor.tsx
@@ -0,0 +1,11 @@
+import {TabPanel, TabView} from "primereact/tabview";
+
+export default function Editor() {
+ return (
+ <TabView style={{width: "100%", height: "100%"}}>
+ <TabPanel key={"ads://192.168.23.20"} header="ads://192.168.23.20" closable={true}>
+ <p>test</p>
+ </TabPanel>
+ </TabView>
+ )
+}