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 2024/01/19 22:16:27 UTC
(plc4x) branch feature/new-ui-tool updated: feat: Worked on implementing the dialog for editing devices.
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 d1d3f714fb feat: Worked on implementing the dialog for editing devices.
d1d3f714fb is described below
commit d1d3f714fb71e78229f4cfc2854e6f7bfa34d4c1
Author: Christofer Dutz <cd...@apache.org>
AuthorDate: Fri Jan 19 23:16:20 2024 +0100
feat: Worked on implementing the dialog for editing devices.
---
.gitignore | 6 +-
plc4j/tools/ui/frontend/frontend/package.json | 2 +-
.../frontend/src/components/DeviceDialog.tsx | 94 ++++++++++++++++++++++
.../frontend/src/components/NavigationTree.tsx | 69 +++++++++++++---
.../src/generated/plc4j-tools-ui-frontend.ts | 2 +-
.../ui/frontend/frontend/src/model/TreeItemData.ts | 4 +
.../ui/frontend/frontend/src/pages/Inspect.tsx | 2 +
.../{model/TreeItemData.ts => utils/Counter.ts} | 19 ++---
8 files changed, 168 insertions(+), 30 deletions(-)
diff --git a/.gitignore b/.gitignore
index c356315c88..84dfdc5d9a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -55,7 +55,7 @@ buildNumber.properties
*.tmp
*.bak
*.swp
-*~.nib
+#*~.nib
local.properties
.settings/
.loadpath
@@ -75,7 +75,7 @@ local.properties
.worksheet
# Emacs backup files
-*~
+#*~
.scannerwork
spock-reports
@@ -119,7 +119,7 @@ gradle-app.setting
# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898
# gradle/wrapper/gradle-wrapper.properties
-exclude ruby specifics:
+#exclude ruby specifics:
*.gem
*.rbc
diff --git a/plc4j/tools/ui/frontend/frontend/package.json b/plc4j/tools/ui/frontend/frontend/package.json
index 0f83ca022c..8174c491e9 100644
--- a/plc4j/tools/ui/frontend/frontend/package.json
+++ b/plc4j/tools/ui/frontend/frontend/package.json
@@ -15,7 +15,7 @@
"@mdi/js": "^7.3.67",
"@mdi/react": "^1.6.1",
"@mui/icons-material": "^5.14.19",
- "@mui/material": "^5.14.20",
+ "@mui/material": "^5.15.5",
"@reduxjs/toolkit": "^2.0.1",
"axios": "^1.6.2",
"primeflex": "^3.3.1",
diff --git a/plc4j/tools/ui/frontend/frontend/src/components/DeviceDialog.tsx b/plc4j/tools/ui/frontend/frontend/src/components/DeviceDialog.tsx
new file mode 100644
index 0000000000..3954427297
--- /dev/null
+++ b/plc4j/tools/ui/frontend/frontend/src/components/DeviceDialog.tsx
@@ -0,0 +1,94 @@
+import {Device} from "../generated/plc4j-tools-ui-frontend.ts";
+import {Dialog} from "primereact/dialog";
+import {Button} from "primereact/button";
+import {InputText} from "primereact/inputtext";
+import withWidth from "@mui/material/Hidden/withWidth";
+import {DataTable} from "primereact/datatable";
+import {Column} from "primereact/column";
+
+interface ConnectionDialogProps {
+ device: Device
+ visible: boolean
+
+ onSave: (device:Device) => void
+ onCancel: () => void
+}
+
+interface TableEntry {
+ key: string
+ value: string
+}
+
+type Dictionary = { [index: string]: string }
+
+function mapToTableEntry(map : Dictionary):TableEntry[] {
+ let tableEntries = [] as TableEntry[]
+ for(const key in map) {
+ const value = map[key]
+ tableEntries = [...tableEntries, {key: key, value: value}]
+ }
+ return tableEntries
+}
+
+export default function DeviceDialog({device, visible, onSave, onCancel}: ConnectionDialogProps) {
+ function handleSave() {
+ onSave(device)
+ }
+ function handleCancel() {
+ onCancel()
+ }
+
+ return (
+ <Dialog visible={visible} modal style={{width: '60rem'}} draggable={true} resizable={true} onHide={() => {
+ }}>
+ <div className="formgrid grid">
+ <label htmlFor="name" className="col-12 mb-2 md:col-2 md:mb-0">Device Name</label>
+ <div className="col-12 md:col-10">
+ <InputText id="name" value={device.name}/>
+ </div>
+ </div>
+ <div className="formgrid grid">
+ <label htmlFor="protocol" className="col-12 mb-2 md:col-2 md:mb-0">Protocol</label>
+ <div className="col-12 md:col-10">
+ <InputText id="protocol" value={device.protocolCode}/>
+ </div>
+ </div>
+ <div className="formgrid grid">
+ <label htmlFor="transportCode" className="col-12 mb-2 md:col-2 md:mb-0">Transport Type</label>
+ <div className="col-12 md:col-10">
+ <InputText id="transportCode" value={device.transportCode}/>
+ </div>
+ </div>
+ <div className="formgrid grid">
+ <label htmlFor="transportUrl" className="col-12 mb-2 md:col-2 md:mb-0">Transport URL</label>
+ <div className="col-12 md:col-10">
+ <InputText id="transportUrl" value={device.transportUrl}/>
+ </div>
+ </div>
+ <div className="formgrid grid">
+ <label htmlFor="options" className="col-12 mb-2 md:col-2 md:mb-0">Options</label>
+ <div className="col-12 md:col-10">
+ <DataTable id="options" value={mapToTableEntry(device.options)} tableStyle={{minWidth: '50rem'}}>
+ <Column field="key" header="Name"/>
+ <Column field="value" header="Value"/>
+ </DataTable>
+ </div>
+ </div>
+ <div className="formgrid grid">
+ <label htmlFor="attributes" className="col-12 mb-2 md:col-2 md:mb-0">Attributes</label>
+ <div className="col-12 md:col-10">
+ <DataTable id="attributes" value={mapToTableEntry(device.attributes)} tableStyle={{minWidth: '50rem'}}>
+ <Column field="key" header="Name"/>
+ <Column field="value" header="Value"/>
+ </DataTable>
+ </div>
+ </div>
+ <div className="formgrid grid">
+ <div className="field col">
+ <Button label={"Save"} onClick={handleSave}/>
+ <Button label={"Cancel"} onClick={handleCancel}/>
+ </div>
+ </div>
+ </Dialog>
+ )
+}
\ No newline at end of file
diff --git a/plc4j/tools/ui/frontend/frontend/src/components/NavigationTree.tsx b/plc4j/tools/ui/frontend/frontend/src/components/NavigationTree.tsx
index c3b72b0fe8..299e0000c3 100644
--- a/plc4j/tools/ui/frontend/frontend/src/components/NavigationTree.tsx
+++ b/plc4j/tools/ui/frontend/frontend/src/components/NavigationTree.tsx
@@ -22,11 +22,13 @@ import {Tree} from "primereact/tree";
import {TreeNode} from "primereact/treenode";
import {IconType} from "primereact/utils";
import 'primeicons/primeicons.css';
-import {useRef} from "react";
+import {useRef, useState} from "react";
import {ContextMenu} from "primereact/contextmenu";
import {MenuItem} from "primereact/menuitem";
-import {RestApplicationClient} from "../generated/plc4j-tools-ui-frontend.ts";
+import {Device, RestApplicationClient} from "../generated/plc4j-tools-ui-frontend.ts";
import axios from "axios";
+import {Counter} from "../utils/Counter.ts";
+import DeviceDialog from "./DeviceDialog.tsx";
type NavigationTreeProps = {
treeItems: TreeItemData[];
@@ -35,6 +37,17 @@ type NavigationTreeProps = {
const restClient = new RestApplicationClient(axios);
export default function NavigationTree({treeItems}: NavigationTreeProps) {
+ const dialogDevice = useRef<Device>({
+ id: 0,
+ name: "",
+ protocolCode: "",
+ transportCode: "",
+ transportUrl: "",
+ options: {},
+ attributes: {},
+ });
+ const [showDeviceDialog, setShowDeviceDialog] = useState(false)
+
const cm = useRef<ContextMenu>(null);
const menu = [
{
@@ -73,7 +86,8 @@ export default function NavigationTree({treeItems}: NavigationTreeProps) {
disabled: false,
} as MenuItem
] as MenuItem[]
- function updateMenu(selectedItem:TreeItemData) {
+
+ function updateMenu(selectedItem: TreeItemData) {
// Discover
menu[0].disabled = !selectedItem.supportsDiscovery && selectedItem.type != "ROOT"
menu[0].command = () => {
@@ -82,17 +96,45 @@ export default function NavigationTree({treeItems}: NavigationTreeProps) {
// Add
menu[1].disabled = selectedItem.type != "DRIVER"
+ menu[1].command = () => {
+ dialogDevice.current.id = 0;
+ dialogDevice.current.name = "";
+ dialogDevice.current.transportCode = "";
+ dialogDevice.current.transportUrl = "";
+ dialogDevice.current.protocolCode = selectedItem.id;
+ dialogDevice.current.options = {};
+ dialogDevice.current.attributes = {};
+ setShowDeviceDialog(true);
+ }
// Edit
menu[2].disabled = selectedItem.type != "DEVICE"
-
+ menu[2].command = () => {
+ console.log(JSON.stringify(selectedItem))
+ if(selectedItem.device) {
+ dialogDevice.current.id = selectedItem.device.id;
+ dialogDevice.current.name = selectedItem.device.name;
+ dialogDevice.current.transportCode = selectedItem.device.transportCode;
+ dialogDevice.current.transportUrl = selectedItem.device.transportUrl;
+ dialogDevice.current.protocolCode = selectedItem.device.protocolCode;
+ dialogDevice.current.options = selectedItem.device.options;
+ dialogDevice.current.attributes = selectedItem.device.attributes;
+ setShowDeviceDialog(true);
+ }
+ }
// Delete
menu[3].disabled = selectedItem.type != "DEVICE"
-
+ menu[3].command = () => {
+ // TODO: Ask for confirmation ...
+ }
// Connect
menu[4].disabled = selectedItem.type != "DEVICE"
+ menu[4].command = () => {
+ // TODO: Open a new tab with the connection ...
+ }
}
- function getIcon(curItem: TreeItemData):IconType<TreeNode> {
+
+ function getIcon(curItem: TreeItemData): IconType<TreeNode> {
switch (curItem.type) {
case "DRIVER":
return "pi pi-fw pi-folder-open"//"material-icons md-18 folder_open"
@@ -109,26 +151,27 @@ export default function NavigationTree({treeItems}: NavigationTreeProps) {
// publish: "Keyboard Double Arrow Up"
}
}
- function createTreeNode(curItem:TreeItemData):TreeNode {
+
+ function createTreeNode(curItem: TreeItemData, keyGenerator: Counter): TreeNode {
return {
- key: curItem.type + '-' + curItem.id,
+ key: keyGenerator.getAndIncrement(),
id: curItem.id,
label: curItem.name,
icon: getIcon(curItem),
data: curItem,
- children: curItem.children?.map(value => createTreeNode(value))
+ children: curItem.children?.map(value => createTreeNode(value, keyGenerator))
}
}
- const treeNodes: TreeNode[] = treeItems.map(value => createTreeNode(value))
- return(
+ const treeNodes: TreeNode[] = treeItems.map(value => createTreeNode(value, new Counter()))
+ return (
<div>
+ <DeviceDialog device={dialogDevice.current} visible={showDeviceDialog} />
<ContextMenu model={menu} ref={cm}/>
-
<Tree value={treeNodes}
selectionMode="single"
onContextMenu={event => {
- if(cm.current) {
+ if (cm.current) {
// Update the state of the menu (enabling/disabling some menu items)
updateMenu(event.node.data as TreeItemData)
//cm.current.props.model = menu
diff --git a/plc4j/tools/ui/frontend/frontend/src/generated/plc4j-tools-ui-frontend.ts b/plc4j/tools/ui/frontend/frontend/src/generated/plc4j-tools-ui-frontend.ts
index 71e59b4c25..07105c5f4e 100644
--- a/plc4j/tools/ui/frontend/frontend/src/generated/plc4j-tools-ui-frontend.ts
+++ b/plc4j/tools/ui/frontend/frontend/src/generated/plc4j-tools-ui-frontend.ts
@@ -19,7 +19,7 @@
*/
/* tslint:disable */
/* eslint-disable */
-// Generated using typescript-generator version 3.2.1263 on 2024-01-15 21:38:43.
+// Generated using typescript-generator version 3.2.1263 on 2024-01-19 18:01:48.
export interface Device {
id: number;
diff --git a/plc4j/tools/ui/frontend/frontend/src/model/TreeItemData.ts b/plc4j/tools/ui/frontend/frontend/src/model/TreeItemData.ts
index d015ebeb86..b361cedf01 100644
--- a/plc4j/tools/ui/frontend/frontend/src/model/TreeItemData.ts
+++ b/plc4j/tools/ui/frontend/frontend/src/model/TreeItemData.ts
@@ -17,12 +17,16 @@
* under the License.
*/
+import {Device, Driver} from "../generated/plc4j-tools-ui-frontend.ts";
+
export type TreeItemType = "ROOT" | "DRIVER" | "CONNECTION" | "DEVICE";
export interface TreeItemData {
id: string,
name: string,
type: TreeItemType,
+ driver?: Driver,
+ device?: Device,
supportsDiscovery: boolean,
supportsBrowsing: boolean,
supportsReading: boolean,
diff --git a/plc4j/tools/ui/frontend/frontend/src/pages/Inspect.tsx b/plc4j/tools/ui/frontend/frontend/src/pages/Inspect.tsx
index 3cba7242a4..f00735425b 100644
--- a/plc4j/tools/ui/frontend/frontend/src/pages/Inspect.tsx
+++ b/plc4j/tools/ui/frontend/frontend/src/pages/Inspect.tsx
@@ -36,6 +36,7 @@ function getByDriverTree(driverList: Driver[], deviceList: Device[]):TreeItemDat
id: value.code,
name: value.name,
type: "DRIVER",
+ driver: value,
supportsDiscovery: value.supportsDiscovery,
supportsBrowsing: false,
supportsReading: false,
@@ -56,6 +57,7 @@ function getByDriverTree(driverList: Driver[], deviceList: Device[]):TreeItemDat
id: value.id?.toString(),
name: value.name,
type: "DEVICE",
+ device: value,
// Even if most connections will support reading/writing, in order to really know, we need a
// connection first. As we're not offering any connection-actions here anyway we just set all
// to false.
diff --git a/plc4j/tools/ui/frontend/frontend/src/model/TreeItemData.ts b/plc4j/tools/ui/frontend/frontend/src/utils/Counter.ts
similarity index 67%
copy from plc4j/tools/ui/frontend/frontend/src/model/TreeItemData.ts
copy to plc4j/tools/ui/frontend/frontend/src/utils/Counter.ts
index d015ebeb86..4f44ad300c 100644
--- a/plc4j/tools/ui/frontend/frontend/src/model/TreeItemData.ts
+++ b/plc4j/tools/ui/frontend/frontend/src/utils/Counter.ts
@@ -17,17 +17,12 @@
* under the License.
*/
-export type TreeItemType = "ROOT" | "DRIVER" | "CONNECTION" | "DEVICE";
+export class Counter {
+
+ private _value:number = 0;
+
+ public getAndIncrement():number {
+ return this._value++
+ }
-export interface TreeItemData {
- id: string,
- name: string,
- type: TreeItemType,
- supportsDiscovery: boolean,
- supportsBrowsing: boolean,
- supportsReading: boolean,
- supportsWriting: boolean,
- supportsSubscribing: boolean,
- supportsPublishing: boolean,
- children?: readonly TreeItemData[]
}