From 97fa6d943c57a784a52462aaacb329ce93cf42d6 Mon Sep 17 00:00:00 2001 From: Herbert Eiselt Date: Wed, 3 Apr 2019 17:12:30 +0200 Subject: SDN-R odlux configuration Add odlux configuration app Change-Id: Ifecd3f6e1e3060a1fd1008f1f625a70cb2475a8a Issue-ID: SDNC-584 Signed-off-by: Herbert Eiselt --- .../src/views/configurationApplication.tsx | 297 +++++++++++++++++++++ 1 file changed, 297 insertions(+) create mode 100644 sdnr/wt/odlux/apps/configurationApp/src/views/configurationApplication.tsx (limited to 'sdnr/wt/odlux/apps/configurationApp/src/views/configurationApplication.tsx') diff --git a/sdnr/wt/odlux/apps/configurationApp/src/views/configurationApplication.tsx b/sdnr/wt/odlux/apps/configurationApp/src/views/configurationApplication.tsx new file mode 100644 index 000000000..5865c10e5 --- /dev/null +++ b/sdnr/wt/odlux/apps/configurationApp/src/views/configurationApplication.tsx @@ -0,0 +1,297 @@ +import * as React from 'react'; + +import { MaterialTable, ColumnType, MaterialTableCtorType } from '../../../../framework/src/components/material-table'; +import connect, { Connect, IDispatcher } from '../../../../framework/src/flux/connect'; +import { IApplicationStoreState } from '../../../../framework/src/store/applicationStore'; +import { IConnectAppStoreState } from '../../../connectApp/src/handlers/connectAppRootHandler'; +import { MountedNetworkElementType } from '../../../connectApp/src/models/mountedNetworkElements'; +import { NavigateToApplication } from '../../../../framework/src/actions/navigationActions'; +import { Dispatch } from '../../../../framework/src/flux/store'; + +import TextField from '@material-ui/core/TextField'; +import { Tooltip, Button, FormControl, InputLabel, Select, MenuItem, InputAdornment } from '@material-ui/core'; +import Link from '@material-ui/core/Link'; + +import Table from '@material-ui/core/Table'; +import TableBody from '@material-ui/core/TableBody'; +import TableCell from '@material-ui/core/TableCell'; +import TableHead from '@material-ui/core/TableHead'; +import TableRow from '@material-ui/core/TableRow'; + +import { ViewSpecification } from '../models/uiModels'; + +const NetworkElementTable = MaterialTable as MaterialTableCtorType; + +const mapProps = (state: IApplicationStoreState) => ({ + ...state.configuration, + avaliableDevices: state.connect.mountedNetworkElements.elements.filter(el => el.connectionStatus === "connected") +}); +const mapDisp = (dispatcher: IDispatcher) => ({ + navigateTo: (viewId: string, index?: string | number) => dispatcher.dispatch((dispatch: Dispatch, getState: () => IApplicationStoreState) => { + const { configuration: { nodeId, lpId, indexValues } } = getState(); + const newIndexValues = typeof index === 'number' && indexValues + ? indexValues.split('/').slice(0, index).join("/") + : indexValues + ? `${indexValues}${index ? `/${index}` : ''}` + : index; + dispatch(new NavigateToApplication("configuration", `${nodeId}/${lpId}/${viewId}${newIndexValues ? `/${newIndexValues}` : ''}`)); + + }), + changeNode: (ndoeId: string) => dispatcher.dispatch((dispatch: Dispatch) => { + dispatch(new NavigateToApplication("configuration", ndoeId)); + }), + changeLp: (lpId: string) => dispatcher.dispatch((dispatch: Dispatch, getState: () => IApplicationStoreState) => { + const { configuration: { nodeId } } = getState(); + dispatch(new NavigateToApplication("configuration", `${nodeId}/${lpId}`)); + }) +}); + +type ConfigurationApplicationProps = Connect; + +type ConfigurationApplicationState = { + +} + +class ConfigurationApplicationComponent extends React.Component { + + render() { + if (this.props.loading) { + return ( +

Collecting data from network element. Please wait ...

+ ); + } else if (!this.props.nodeId) { + return ( + <> +

Please select an network element to configure !

+ { this.props.changeNode(rowData.mountId) }} columns={ + [{ property:"mountId" }] + } /> + + ); + } else if (!this.props.lpId) { + return ( + <> +

Please select an existing LP first !

+
    + { this.props.coreModel && this.props.coreModel.ltp.map(ltp => { + return
  • + { + this.props.changeLp(ltp.lp[0].uuid); + }}>{ltp.lp[0].label[0].value} +
  • + }) || null} +
+ + ); + } else if (!this.props.capability && !this.props.viewId) { + return ( +

Please select a capability or viewId first !

+ ); + } + const viewData = this.props.viewData; + const viewSpecification = this.props.viewId + ? this.props.viewSpecifications.find(d => d.id === this.props.viewId) + : this.props.viewSpecifications.find(d => d.name === this.props.conditionalPackage); + + return viewSpecification + ? ( + <> +
+

{`${this.props.nodeId} - ${this.props.lpId}`}

+ {this.createBreadCrump(viewSpecification.id, this.props.viewSpecifications)} +
+
+ { + + (this.props.viewData && this.props.viewData instanceof Array) + ? this.renderUIList(viewSpecification, viewData as { [key: string]: string | number }[]) + : this.renderUIElement(viewSpecification, viewData as { [key: string]: string | number }) + } + {/* {
{JSON.stringify(this.props.viewData, null, 2)} 
} */} + +
+ + ) + :

View Not Found

; + } + + private static keyPropertyParser = /\$\$INDEX:(\d+):?([a-z\-]+)?\$\$$/; + private renderUIList = (viewSpecification: ViewSpecification, viewData: { [key: string]: string | number }[]) => { + const keyMatch = ConfigurationApplicationComponent.keyPropertyParser.exec(viewSpecification.dataPath); + const keyProperty = keyMatch && keyMatch[2]; + return ( + + + + {viewSpecification.elements.map(uiElement => { + switch (uiElement.uiType) { + case "number": + return ( + {uiElement.label} + ); + case "selection": + case "object": + case "list": + case "string": + case "boolean": + return ( + {uiElement.label} + ); + default: + if (process.env.NODE_ENV !== "production") { + console.error(`Unknown column type - ${(uiElement as any).uiType} in ${(uiElement as any).id}.`) + } + return null; + } + }) + } + Actions + + + + {viewData.map((row, ind) => ( + + {viewSpecification.elements.map(uiElement => { + switch (uiElement.uiType) { + case "string": + case "number": + return ( + {row[uiElement.id] == null ? "---" : row[uiElement.id] } + ); + case "boolean": + return ( + {row[uiElement.id] == null ? "---" : row[uiElement.id] ? uiElement.trueValue || 'True' : uiElement.falseValue || 'False'} + ); + case "list": + case "object": + return ( + + + { + this.props.navigateTo(uiElement.viewId, String(ind)); + }}>{uiElement.label} + + ); + case "selection": + const option = row[uiElement.id] ? uiElement.options.find(opt => opt.key === row[uiElement.id]) : null; + return ( + {option ? option.value : row[uiElement.id] == null ? "---" : row[uiElement.id] } + ); + default: + if (process.env.NODE_ENV !== "production") { + console.error(`Unknown column type - ${(uiElement as any).uiType} in ${(uiElement as any).id}.`) + } + return null; + } + })} + + + + ))} + +
+ ); + } + + private renderUIElement = (viewSpecification: ViewSpecification, viewData: { [key: string]: string | number }) => ( + viewSpecification.elements.map(uiElement => { + if (uiElement.leafrefPath) { + return null; + } + switch (uiElement.uiType) { + case "selection": + return (viewData[uiElement.id] != null + ? ( + {uiElement.label} + + ) + : null + ); + case "boolean": + return (viewData[uiElement.id] != null + ? ( + {uiElement.label} + + ) + : null + ); + case "string": + return ( + + + + ); + case "number": + return ( + + {uiElement.unit} : undefined }} spellCheck={false} autoFocus margin="dense" + id={uiElement.id} label={uiElement.label} type="text" value={viewData[uiElement.id] || ''} style={{ width: 485, marginLeft: 20, marginRight: 20 }} /> + + ); + case "list": + case "object": + return ( + + { + this.props.navigateTo(uiElement.viewId); + }}>{uiElement.label} + + ); + default: + if (process.env.NODE_ENV !== "production") { + console.error(`Unknown type - ${(uiElement as any).uiType} in ${(uiElement as any).id}.`) + } + return null; + } + }) + ) + + private createBreadCrump = (viewId: string, viewSpecifications: ViewSpecification[]) => { + const result: JSX.Element[] = []; + const hasIndex = /\/\$\$INDEX:(\d+):?([a-z\-]+)?\$\$/i; + let currentViewSpecification = viewSpecifications.find(s => s.id === viewId); + let indexCounter = 0; + while (currentViewSpecification != null) { + const currentViewId = currentViewSpecification.id; + const currentDataPathHasIndex = hasIndex.test(currentViewSpecification.dataPath); + result.unshift(( + + { + this.props.navigateTo(currentViewId, currentDataPathHasIndex ? ++indexCounter : indexCounter); + }}>{currentViewSpecification.name} + {viewId === currentViewId ? null : " | "} + + )); + currentViewSpecification = viewSpecifications.find(s => s.id === (currentViewSpecification && currentViewSpecification.parentView || '')); + } + return result; + } +} + +export const ConfigurationApplication = connect(mapProps, mapDisp)(ConfigurationApplicationComponent); +export default ConfigurationApplication; \ No newline at end of file -- cgit 1.2.3-korg