aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAijana Schumann <aijana.schumann@highstreet-technologies.com>2020-02-28 15:15:26 +0100
committerAijana Schumann <aijana.schumann@highstreet-technologies.com>2020-02-28 15:15:26 +0100
commit889c7fbc0f78eadc302e8849ea7e6cad795e0d6e (patch)
treeda4cb3a08d06520497f1ed584fbdf70afcc22edb
parent4eed58ba1a434261510c996316d2d201a40eb760 (diff)
update odlux stage 3
PerformanceApp: Add filter to chart view add scrolling header to tables, add basic validation to editNetworkElementDialog bugfixes Issue-ID: SDNC-1087 Signed-off-by: Aijana Schumann <aijana.schumann@highstreet-technologies.com> Change-Id: I585bd6cfeb11b867cd630e96e6479170d2f92fe8
-rw-r--r--sdnr/wt/data-provider/provider/pom.xml2
-rw-r--r--sdnr/wt/odlux/apps/configurationApp/src/views/configurationApplication.tsx15
-rw-r--r--sdnr/wt/odlux/apps/configurationApp/src/views/networkElementSelector.tsx2
-rw-r--r--sdnr/wt/odlux/apps/connectApp/src/components/editNetworkElementDialog.tsx79
-rw-r--r--sdnr/wt/odlux/apps/connectApp/src/components/networkElements.tsx4
-rw-r--r--sdnr/wt/odlux/apps/connectApp/src/models/networkElementConnection.ts9
-rw-r--r--sdnr/wt/odlux/apps/eventLogApp/src/views/eventLog.tsx4
-rw-r--r--sdnr/wt/odlux/apps/faultApp/src/actions/panelChangeActions.ts6
-rw-r--r--sdnr/wt/odlux/apps/faultApp/src/handlers/faultAppRootHandler.ts13
-rw-r--r--sdnr/wt/odlux/apps/faultApp/src/pluginFault.tsx16
-rw-r--r--sdnr/wt/odlux/apps/faultApp/src/views/faultApplication.tsx25
-rw-r--r--sdnr/wt/odlux/apps/inventoryApp/src/fakeData/index.ts60
-rw-r--r--sdnr/wt/odlux/apps/inventoryApp/src/models/inventory.ts11
-rw-r--r--sdnr/wt/odlux/apps/inventoryApp/src/services/inventoryService.ts37
-rw-r--r--sdnr/wt/odlux/apps/inventoryApp/src/views/dashboard.tsx44
-rw-r--r--sdnr/wt/odlux/apps/inventoryApp/webpack.config.js10
-rw-r--r--sdnr/wt/odlux/apps/maintenanceApp/src/views/maintenenceView.tsx24
-rw-r--r--sdnr/wt/odlux/apps/mediatorApp/src/views/mediatorApplication.tsx2
-rw-r--r--sdnr/wt/odlux/apps/mediatorApp/src/views/mediatorServerSelection.tsx2
-rw-r--r--sdnr/wt/odlux/apps/performanceHistoryApp/src/actions/ltpAction.ts16
-rw-r--r--sdnr/wt/odlux/apps/performanceHistoryApp/src/actions/toggleActions.ts24
-rw-r--r--sdnr/wt/odlux/apps/performanceHistoryApp/src/components/adaptiveModulation.tsx22
-rw-r--r--sdnr/wt/odlux/apps/performanceHistoryApp/src/components/chartFilter.tsx50
-rw-r--r--sdnr/wt/odlux/apps/performanceHistoryApp/src/components/crossPolarDiscrimination.tsx20
-rw-r--r--sdnr/wt/odlux/apps/performanceHistoryApp/src/components/ltpSelection.tsx22
-rw-r--r--sdnr/wt/odlux/apps/performanceHistoryApp/src/components/performanceData.tsx20
-rw-r--r--sdnr/wt/odlux/apps/performanceHistoryApp/src/components/receiveLevel.tsx23
-rw-r--r--sdnr/wt/odlux/apps/performanceHistoryApp/src/components/signalToInterference.tsx20
-rw-r--r--sdnr/wt/odlux/apps/performanceHistoryApp/src/components/temperature.tsx22
-rw-r--r--sdnr/wt/odlux/apps/performanceHistoryApp/src/components/toggleContainer.tsx70
-rw-r--r--sdnr/wt/odlux/apps/performanceHistoryApp/src/components/transmissionPower.tsx22
-rw-r--r--sdnr/wt/odlux/apps/performanceHistoryApp/src/handlers/availableLtpsActionHandler.ts34
-rw-r--r--sdnr/wt/odlux/apps/performanceHistoryApp/src/handlers/performanceHistoryRootHandler.ts48
-rw-r--r--sdnr/wt/odlux/apps/performanceHistoryApp/src/services/performanceHistoryService.ts2
-rw-r--r--sdnr/wt/odlux/apps/performanceHistoryApp/src/views/performanceHistoryApplication.tsx21
-rw-r--r--sdnr/wt/odlux/framework/pom.xml2
-rw-r--r--sdnr/wt/odlux/framework/src/components/material-table/index.tsx3
-rw-r--r--sdnr/wt/odlux/framework/src/components/material-table/tableFilter.tsx6
-rw-r--r--sdnr/wt/odlux/framework/src/components/material-ui/index.ts2
-rw-r--r--sdnr/wt/odlux/framework/src/components/material-ui/treeView.tsx102
-rw-r--r--sdnr/wt/odlux/framework/src/components/navigationMenu.tsx7
-rw-r--r--sdnr/wt/odlux/framework/src/views/test.tsx25
-rw-r--r--sdnr/wt/odlux/package.json7
43 files changed, 714 insertions, 241 deletions
diff --git a/sdnr/wt/data-provider/provider/pom.xml b/sdnr/wt/data-provider/provider/pom.xml
index 384aba682..0fd61913c 100644
--- a/sdnr/wt/data-provider/provider/pom.xml
+++ b/sdnr/wt/data-provider/provider/pom.xml
@@ -52,7 +52,7 @@
<maven.build.timestamp.format>yyyy-MM-dd HH:mm</maven.build.timestamp.format>
<buildtime>${maven.build.timestamp}</buildtime>
<databaseport>49402</databaseport>
- <odlux.buildno>45.7f0c660(20/02/28)</odlux.buildno>
+ <odlux.buildno>46.9d666e7(20/02/28)</odlux.buildno>
</properties>
<dependencies>
diff --git a/sdnr/wt/odlux/apps/configurationApp/src/views/configurationApplication.tsx b/sdnr/wt/odlux/apps/configurationApp/src/views/configurationApplication.tsx
index 9c92ceb6b..06de39b9d 100644
--- a/sdnr/wt/odlux/apps/configurationApp/src/views/configurationApplication.tsx
+++ b/sdnr/wt/odlux/apps/configurationApp/src/views/configurationApplication.tsx
@@ -65,7 +65,7 @@ const styles = (theme: Theme) => createStyles({
},
outer: {
"flex": "1",
- "heigh": "100%",
+ "height": "100%",
"display": "flex",
"alignItems": "center",
"justifyContent": "center",
@@ -73,6 +73,11 @@ const styles = (theme: Theme) => createStyles({
inner: {
},
+ container: {
+ "height": "100%",
+ "display": "flex",
+ "flexDirection": "column",
+ },
"icon": {
"marginRight": theme.spacing(0.5),
"width": 20,
@@ -440,7 +445,7 @@ class ConfigurationApplicationComponent extends React.Component<ConfigurationApp
const { classes } = this.props;
return (
- <SelectElementTable idProperty={listKeyProperty} rows={listData} customActionButtons={[addNewElementAction]} columns={
+ <SelectElementTable stickyHeader idProperty={listKeyProperty} rows={listData} customActionButtons={[addNewElementAction]} columns={
Object.keys(listElements).reduce<ColumnModel<{ [key: string]: any }>[]>((acc, cur) => {
const elm = listElements[cur];
if (elm.uiType !== "object" && listData.every(entry => entry[elm.label] != null)) {
@@ -571,8 +576,8 @@ class ConfigurationApplicationComponent extends React.Component<ConfigurationApp
}
return (
- <div>
- <SelectElementTable idProperty={listKeyProperty} rows={listData} columns={
+ <div className={this.props.classes.container}>
+ <SelectElementTable stickyHeader idProperty={listKeyProperty} rows={listData} columns={
Object.keys(listSpecification.elements).reduce<ColumnModel<{ [key: string]: any }>[]>((acc, cur) => {
const elm = listSpecification.elements[cur];
if (elm.uiType !== "object" && listData.every(entry => entry[elm.label] != null)) {
@@ -594,7 +599,7 @@ class ConfigurationApplicationComponent extends React.Component<ConfigurationApp
const { viewData, editMode, isNew } = this.state;
return (
- <div>
+ <div className={this.props.classes.container}>
{this.renderBreadCrumps()}
{displayAsList && viewData instanceof Array
? this.renderUIViewList(viewSpecification, keyProperty!, viewData)
diff --git a/sdnr/wt/odlux/apps/configurationApp/src/views/networkElementSelector.tsx b/sdnr/wt/odlux/apps/configurationApp/src/views/networkElementSelector.tsx
index 8155becbb..c153ed5a1 100644
--- a/sdnr/wt/odlux/apps/configurationApp/src/views/networkElementSelector.tsx
+++ b/sdnr/wt/odlux/apps/configurationApp/src/views/networkElementSelector.tsx
@@ -47,7 +47,7 @@ class NetworkElementSelectorComponent extends React.Component<NetworkElementSele
render() {
return (
- <ConnectedElementTable onHandleClick={(e, row) => { this.props.history.push(`${this.props.match.path}/${row.nodeId}`) }} columns={[
+ <ConnectedElementTable stickyHeader onHandleClick={(e, row) => { this.props.history.push(`${this.props.match.path}/${row.nodeId}`) }} columns={[
{ property: "nodeId", title: "Name", type: ColumnType.text },
{ property: "isRequired", title: "Required ?", type: ColumnType.boolean },
{ property: "host", title: "Host", type: ColumnType.text },
diff --git a/sdnr/wt/odlux/apps/connectApp/src/components/editNetworkElementDialog.tsx b/sdnr/wt/odlux/apps/connectApp/src/components/editNetworkElementDialog.tsx
index ce7f48cc9..e3b640120 100644
--- a/sdnr/wt/odlux/apps/connectApp/src/components/editNetworkElementDialog.tsx
+++ b/sdnr/wt/odlux/apps/connectApp/src/components/editNetworkElementDialog.tsx
@@ -24,7 +24,7 @@ import DialogActions from '@material-ui/core/DialogActions';
import DialogContent from '@material-ui/core/DialogContent';
import DialogContentText from '@material-ui/core/DialogContentText';
import DialogTitle from '@material-ui/core/DialogTitle';
-import { FormControl, InputLabel, Select, MenuItem } from '@material-ui/core';
+import { FormControl, InputLabel, Select, MenuItem, Typography } from '@material-ui/core';
import { IDispatcher, connect, Connect } from '../../../../framework/src/flux/connect';
@@ -35,7 +35,7 @@ import {
} from '../actions/networkElementsActions';
import { unmountNetworkElementAsyncActionCreator, mountNetworkElementAsyncActionCreator } from '../actions/mountedNetworkElementsActions';
-import { NetworkElementConnection, UpdateNetworkElement } from '../models/networkElementConnection';
+import { NetworkElementConnection, UpdateNetworkElement, propertyOf } from '../models/networkElementConnection';
import { removeWebUriAction } from '../actions/commonNetworkElementsActions';
export enum EditNetworkElementDialogMode {
@@ -47,6 +47,8 @@ export enum EditNetworkElementDialogMode {
UnmountNetworkElement = "unmountNetworkElement",
}
+
+
const mapDispatch = (dispatcher: IDispatcher) => ({
addNewNetworkElement: async (element: NetworkElementConnection) => {
await dispatcher.dispatch(addNewNetworkElementAsyncActionCreator(element));
@@ -57,8 +59,21 @@ const mapDispatch = (dispatcher: IDispatcher) => ({
dispatcher.dispatch(unmountNetworkElementAsyncActionCreator(element && element.nodeId));
},
editNetworkElement: async (element: UpdateNetworkElement, mountElement: NetworkElementConnection) => {
- await dispatcher.dispatch(editNetworkElementAsyncActionCreator(element));
- await dispatcher.dispatch(mountNetworkElementAsyncActionCreator(mountElement));
+
+ const values = Object.keys(element);
+
+ //make sure properties are there in case they get renamed
+ const idProperty = propertyOf<UpdateNetworkElement>("id");
+ const isRequiredProperty = propertyOf<UpdateNetworkElement>("isRequired");
+
+ if (values.length === 2 && values.includes(idProperty as string) && values.includes(isRequiredProperty as string)) {
+ // do not mount network element, if only isRequired is changed
+ await dispatcher.dispatch(editNetworkElementAsyncActionCreator(element));
+
+ } else {
+ await dispatcher.dispatch(editNetworkElementAsyncActionCreator(element));
+ await dispatcher.dispatch(mountNetworkElementAsyncActionCreator(mountElement));
+ }
},
removeNetworkElement: async (element: UpdateNetworkElement) => {
await dispatcher.dispatch(removeNetworkElementAsyncActionCreator(element));
@@ -140,7 +155,7 @@ type EditNetworkElementDialogComponentProps = Connect<undefined, typeof mapDispa
onClose: () => void;
};
-type EditNetworkElementDialogComponentState = NetworkElementConnection;
+type EditNetworkElementDialogComponentState = NetworkElementConnection & { isNameValid: boolean, isHostSet: boolean };
class EditNetworkElementDialogComponent extends React.Component<EditNetworkElementDialogComponentProps, EditNetworkElementDialogComponentState> {
constructor(props: EditNetworkElementDialogComponentProps) {
@@ -151,6 +166,8 @@ class EditNetworkElementDialogComponent extends React.Component<EditNetworkEleme
isRequired: false,
host: this.props.initialNetworkElement.host,
port: this.props.initialNetworkElement.port,
+ isNameValid: true,
+ isHostSet: true
};
}
@@ -164,7 +181,9 @@ class EditNetworkElementDialogComponent extends React.Component<EditNetworkEleme
{setting.dialogDescription}
</DialogContentText>
<TextField disabled={!setting.enableMountIdEditor} spellCheck={false} autoFocus margin="dense" id="name" label="Name" aria-label="name" type="text" fullWidth value={this.state.nodeId} onChange={(event) => { this.setState({ nodeId: event.target.value }); }} />
+ {!this.state.isNameValid && <Typography variant="body1" color="error">Name cannot be empty.</Typography>}
<TextField disabled={!setting.enableMountIdEditor} spellCheck={false} margin="dense" id="ipaddress" label="IP address" aria-label="ip adress" type="text" fullWidth value={this.state.host} onChange={(event) => { this.setState({ host: event.target.value }); }} />
+ {!this.state.isHostSet && <Typography variant="body1" color="error">IP Adress cannot be empty.</Typography>}
<TextField disabled={!setting.enableMountIdEditor} spellCheck={false} margin="dense" id="netconfport" label="NetConf port" aria-label="netconf port" type="number" fullWidth value={this.state.port.toString()} onChange={(event) => { this.setState({ port: +event.target.value }); }} />
{setting.enableUsernameEditor && <TextField disabled={!setting.enableUsernameEditor} spellCheck={false} margin="dense" id="username" label="Username" aria-label="username" type="text" fullWidth value={this.state.username} onChange={(event) => { this.setState({ username: event.target.value }); }} /> || null}
{setting.enableUsernameEditor && <TextField disabled={!setting.enableUsernameEditor} spellCheck={false} margin="dense" id="password" label="Password" aria-label="password" type="password" fullWidth value={this.state.password} onChange={(event) => { this.setState({ password: event.target.value }); }} /> || null}
@@ -180,15 +199,18 @@ class EditNetworkElementDialogComponent extends React.Component<EditNetworkEleme
</DialogContent>
<DialogActions>
<Button aria-label="dialog-confirm-button" onClick={(event) => {
- this.onApply({
- isRequired: this.state.isRequired,
- id: this.state.nodeId,
- nodeId: this.state.nodeId,
- host: this.state.host,
- port: this.state.port,
- username: this.state.username,
- password: this.state.password,
- });
+
+ if (this.areRequieredFieldsValid()) {
+ this.onApply({
+ isRequired: this.state.isRequired,
+ id: this.state.nodeId,
+ nodeId: this.state.nodeId,
+ host: this.state.host,
+ port: this.state.port,
+ username: this.state.username,
+ password: this.state.password,
+ });
+ }
event.preventDefault();
event.stopPropagation();
}} > {setting.applyButtonText} </Button>
@@ -230,10 +252,39 @@ class EditNetworkElementDialogComponent extends React.Component<EditNetworkEleme
element && this.props.removeNetworkElement(updateElement);
break;
}
+
+ this.setState({ password: '', username: '' });
+ this.resetRequieredFields();
};
private onCancel = () => {
this.props.onClose && this.props.onClose();
+ this.setState({ password: '', username: '' });
+ this.resetRequieredFields();
+ }
+
+ private resetRequieredFields() {
+ this.setState({ isNameValid: true, isHostSet: true });
+ }
+
+ private areRequieredFieldsValid() {
+ let areFieldsValid = true;
+
+ if (this.state.nodeId == undefined || this.state.nodeId.trim().length === 0) {
+ this.setState({ isNameValid: false });
+ areFieldsValid = false;
+ } else {
+ this.setState({ isNameValid: true });
+ }
+
+ if (this.state.host == undefined || this.state.host.trim().length === 0) {
+ this.setState({ isHostSet: false });
+ areFieldsValid = false;
+ } else {
+ this.setState({ isHostSet: true });
+ }
+
+ return areFieldsValid;
}
static getDerivedStateFromProps(props: EditNetworkElementDialogComponentProps, state: EditNetworkElementDialogComponentState & { _initialNetworkElement: NetworkElementConnection }): EditNetworkElementDialogComponentState & { _initialNetworkElement: NetworkElementConnection } {
diff --git a/sdnr/wt/odlux/apps/connectApp/src/components/networkElements.tsx b/sdnr/wt/odlux/apps/connectApp/src/components/networkElements.tsx
index 45003e741..d50a81ed5 100644
--- a/sdnr/wt/odlux/apps/connectApp/src/components/networkElements.tsx
+++ b/sdnr/wt/odlux/apps/connectApp/src/components/networkElements.tsx
@@ -110,9 +110,7 @@ export class NetworkElementsListComponent extends React.Component<NetworkElement
<Divider />,
<MenuItem aria-label={"info-button"} onClick={event => this.onOpenInfoNetworkElementDialog(event, rowData)} disabled={rowData.status === "Connecting" || rowData.status === "Disconnected"} ><Info /><Typography>Info</Typography></MenuItem>,
<MenuItem aria-label={"edit-button"} onClick={event => this.onOpenEditNetworkElementDialog(event, rowData)}><EditIcon /><Typography>Edit</Typography></MenuItem>,
- !rowData.isRequired
- ? <MenuItem aria-label={"add-button"} onClick={event => this.onOpenAddNetworkElementDialog(event, rowData)} ><AddIcon /><Typography>Add</Typography></MenuItem>
- : <MenuItem aria-label={"remove-button"} onClick={event => this.onOpenRemoveNetworkElementDialog(event, rowData)} ><RemoveIcon /><Typography>Remove</Typography></MenuItem>,
+ <MenuItem aria-label={"remove-button"} onClick={event => this.onOpenRemoveNetworkElementDialog(event, rowData)} ><RemoveIcon /><Typography>Remove</Typography></MenuItem>,
<Divider />,
<MenuItem aria-label={"inventory-button"} onClick={event => this.props.navigateToApplication("inventory", rowData.nodeId)}><Typography>Inventory</Typography></MenuItem>,
<Divider />,
diff --git a/sdnr/wt/odlux/apps/connectApp/src/models/networkElementConnection.ts b/sdnr/wt/odlux/apps/connectApp/src/models/networkElementConnection.ts
index f58dc58ab..b3586d693 100644
--- a/sdnr/wt/odlux/apps/connectApp/src/models/networkElementConnection.ts
+++ b/sdnr/wt/odlux/apps/connectApp/src/models/networkElementConnection.ts
@@ -51,4 +51,11 @@ export type UpdateNetworkElement = {
export type ConnectionStatus = {
status: string
-} \ No newline at end of file
+}
+
+/**
+ * Checks if a object has a given propertyname, if yes, the name is returned as string.
+ * @throws at compile time if property is not available
+ * @param name propertyname
+ */
+export const propertyOf = <TObj>(name: keyof TObj) => name; \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/eventLogApp/src/views/eventLog.tsx b/sdnr/wt/odlux/apps/eventLogApp/src/views/eventLog.tsx
index 535de1f1d..5993bb5c4 100644
--- a/sdnr/wt/odlux/apps/eventLogApp/src/views/eventLog.tsx
+++ b/sdnr/wt/odlux/apps/eventLogApp/src/views/eventLog.tsx
@@ -24,7 +24,7 @@ import { EventLogType } from '../models/eventLogType';
import { IApplicationStoreState } from "../../../../framework/src/store/applicationStore";
import { createEventLogProperties, createEventLogActions } from "../handlers/eventLogHandler";
-const EventLogTable = MaterialTable as MaterialTableCtorType<EventLogType & {_id: string}>;
+const EventLogTable = MaterialTable as MaterialTableCtorType<EventLogType & { _id: string }>;
const mapProps = (state: IApplicationStoreState) => ({
eventLogProperties: createEventLogProperties(state),
@@ -37,7 +37,7 @@ const mapDispatch = (dispatcher: IDispatcher) => ({
class EventLogComponent extends React.Component<Connect<typeof mapProps, typeof mapDispatch>> {
render() {
- return <EventLogTable title="Event Log" idProperty="_id" columns={[
+ return <EventLogTable stickyHeader title="Event Log" idProperty="_id" columns={[
{ property: "nodeId", title: "Node Name" },
{ property: "counter", title: "Counter" },
{ property: "timestamp", title: "Timestamp" },
diff --git a/sdnr/wt/odlux/apps/faultApp/src/actions/panelChangeActions.ts b/sdnr/wt/odlux/apps/faultApp/src/actions/panelChangeActions.ts
index 58da19d46..7cf02ac4f 100644
--- a/sdnr/wt/odlux/apps/faultApp/src/actions/panelChangeActions.ts
+++ b/sdnr/wt/odlux/apps/faultApp/src/actions/panelChangeActions.ts
@@ -24,6 +24,12 @@ export class SetPanelAction extends Action {
}
}
+export class RememberCurrentPanelAction extends Action {
+ constructor(public panelId: PanelId) {
+ super();
+ }
+}
+
export const setPanelAction = (panelId: PanelId) => {
return new SetPanelAction(panelId);
}
diff --git a/sdnr/wt/odlux/apps/faultApp/src/handlers/faultAppRootHandler.ts b/sdnr/wt/odlux/apps/faultApp/src/handlers/faultAppRootHandler.ts
index dddb4a247..a5cf928fc 100644
--- a/sdnr/wt/odlux/apps/faultApp/src/handlers/faultAppRootHandler.ts
+++ b/sdnr/wt/odlux/apps/faultApp/src/handlers/faultAppRootHandler.ts
@@ -26,21 +26,26 @@ import { IActionHandler } from '../../../../framework/src/flux/action';
import { IFaultNotifications, faultNotificationsHandler } from './notificationsHandler';
import { ICurrentProblemsState, currentProblemsActionHandler } from './currentProblemsHandler';
import { IAlarmLogEntriesState, alarmLogEntriesActionHandler } from './alarmLogEntriesHandler';
-import { SetPanelAction } from '../actions/panelChangeActions';
+import { SetPanelAction, RememberCurrentPanelAction } from '../actions/panelChangeActions';
import { IFaultStatus, faultStatusHandler } from './faultStatusHandler';
import { stuckAlarmHandler } from './clearStuckAlarmsHandler';
+import { PanelId } from 'models/panelId';
export interface IFaultAppStoreState {
currentProblems: ICurrentProblemsState;
faultNotifications: IFaultNotifications;
alarmLogEntries: IAlarmLogEntriesState;
- currentOpenPanel: string | null;
+ currentOpenPanel: ICurrentOpenPanelState;
faultStatus: IFaultStatus;
}
-const currentOpenPanelHandler: IActionHandler<string | null> = (state = null, action) => {
+type ICurrentOpenPanelState = { openPanel: string | null, savedPanel: PanelId | null };
+const panelInitState = { openPanel: null, savedPanel: null };
+const currentOpenPanelHandler: IActionHandler<ICurrentOpenPanelState> = (state = panelInitState, action) => {
if (action instanceof SetPanelAction) {
- state = action.panelId;
+ state = { ...state, openPanel: action.panelId };
+ } else if (action instanceof RememberCurrentPanelAction) {
+ state = { ...state, savedPanel: action.panelId };
}
return state;
}
diff --git a/sdnr/wt/odlux/apps/faultApp/src/pluginFault.tsx b/sdnr/wt/odlux/apps/faultApp/src/pluginFault.tsx
index 02dde90f7..666667e40 100644
--- a/sdnr/wt/odlux/apps/faultApp/src/pluginFault.tsx
+++ b/sdnr/wt/odlux/apps/faultApp/src/pluginFault.tsx
@@ -40,6 +40,7 @@ import { AddFaultNotificationAction } from "./actions/notificationActions";
import { createCurrentProblemsProperties, createCurrentProblemsActions, currentProblemsReloadAction } from "./handlers/currentProblemsHandler";
import { FaultStatus } from "./components/faultStatus";
import { refreshFaultStatusAsyncAction } from "./actions/statusActions";
+import { alarmLogEntriesReloadAction } from "./handlers/alarmLogEntriesHandler";
let currentMountId: string | undefined = undefined;
@@ -49,7 +50,7 @@ const mapProps = (state: IApplicationStoreState) => ({
const mapDisp = (dispatcher: IDispatcher) => ({
currentProblemsActions: createCurrentProblemsActions(dispatcher.dispatch, true),
- setCurrentPanel: (panelId: PanelId) => dispatcher.dispatch(new SetPanelAction(panelId))
+ setCurrentPanel: (panelId: PanelId) => dispatcher.dispatch(new SetPanelAction(panelId)),
});
const FaultApplicationRouteAdapter = connect(mapProps, mapDisp)((props: RouteComponentProps<{ mountId?: string }> & Connect<typeof mapProps, typeof mapDisp>) => {
@@ -73,9 +74,9 @@ const FaultApplicationRouteAdapter = connect(mapProps, mapDisp)((props: RouteCom
const App = withRouter((props: RouteComponentProps) => (
<Switch>
- <Route path={ `${ props.match.path }/:mountId?` } component={ FaultApplicationRouteAdapter } />
- <Redirect to={ `${ props.match.path }` } />
- </Switch>
+ <Route path={`${props.match.path}/:mountId?`} component={FaultApplicationRouteAdapter} />
+ <Redirect to={`${props.match.path}`} />
+ </Switch>
));
export function register() {
@@ -93,6 +94,13 @@ export function register() {
const store = applicationApi && applicationApi.applicationStore;
if (fault && store) {
store.dispatch(new AddFaultNotificationAction(fault));
+
+ //reload fault data if tab is open
+ if (store.state.fault.currentOpenPanel.openPanel === "AlarmLog") {
+ store.dispatch(alarmLogEntriesReloadAction);
+ } else if (store.state.fault.currentOpenPanel.openPanel === "CurrentProblem") {
+ store.dispatch(currentProblemsReloadAction);
+ }
}
}));
diff --git a/sdnr/wt/odlux/apps/faultApp/src/views/faultApplication.tsx b/sdnr/wt/odlux/apps/faultApp/src/views/faultApplication.tsx
index cbcfd84d6..ed395d2e4 100644
--- a/sdnr/wt/odlux/apps/faultApp/src/views/faultApplication.tsx
+++ b/sdnr/wt/odlux/apps/faultApp/src/views/faultApplication.tsx
@@ -33,13 +33,14 @@ import { PanelId } from '../models/panelId';
import { createCurrentProblemsProperties, createCurrentProblemsActions, currentProblemsReloadAction } from '../handlers/currentProblemsHandler';
import { createAlarmLogEntriesProperties, createAlarmLogEntriesActions, alarmLogEntriesReloadAction } from '../handlers/alarmLogEntriesHandler';
-import { setPanelAction } from '../actions/panelChangeActions';
+import { setPanelAction, RememberCurrentPanelAction } from '../actions/panelChangeActions';
import { Tooltip, IconButton, AppBar, Tabs, Tab } from '@material-ui/core';
import RefreshIcon from '@material-ui/icons/Refresh';
import ClearStuckAlarmsDialog, { ClearStuckAlarmsDialogMode } from '../components/clearStuckAlarmsDialog';
const mapProps = (state: IApplicationStoreState) => ({
- panelId: state.fault.currentOpenPanel,
+ panelId: state.fault.currentOpenPanel.openPanel,
+ savedPanel: state.fault.currentOpenPanel.savedPanel,
currentProblemsProperties: createCurrentProblemsProperties(state),
faultNotifications: state.fault.faultNotifications,
alarmLogEntriesProperties: createAlarmLogEntriesProperties(state)
@@ -52,7 +53,8 @@ const mapDisp = (dispatcher: IDispatcher) => ({
reloadAlarmLogEntries: () => dispatcher.dispatch(alarmLogEntriesReloadAction),
switchActivePanel: (panelId: PanelId) => {
dispatcher.dispatch(setPanelAction(panelId));
- }
+ },
+ rememberCurrentPanel: (panelId: PanelId) => dispatcher.dispatch(new RememberCurrentPanelAction(panelId))
});
type FaultApplicationComponentProps = RouteComponentProps & Connect<typeof mapProps, typeof mapDisp>;
@@ -146,7 +148,7 @@ class FaultApplicationComponent extends React.Component<FaultApplicationComponen
{ property: "icon", title: "", type: ColumnType.custom, customControl: this.renderIcon },
{ property: "timeStamp", title: "Time Stamp" },
{ property: "nodeName", title: "Node Name" },
- { property: "counter", title: "Count", width: "100px" },
+ { property: "counter", title: "Count", width: "100px", type: ColumnType.numeric },
{ property: "objectId", title: "Object Id" },
{ property: "problem", title: "Alarm Type" },
{ property: "severity", title: "Severity", width: "140px" },
@@ -174,11 +176,22 @@ class FaultApplicationComponent extends React.Component<FaultApplicationComponen
};
+ componentWillUnmount() {
+ if (this.props.panelId) {
+ this.props.rememberCurrentPanel(this.props.panelId as PanelId);
+ this.props.switchActivePanel(null);
+ }
+ }
+
public componentDidMount() {
- if (this.props.panelId === null) { //don't change tabs, if one is selected already
+ if (this.props.panelId === null && this.props.savedPanel === null) { //set default tab if none is set
this.onToggleTabs("CurrentProblem");
- }
+ } else // load saved tab if possible
+ if (this.props.panelId === null && this.props.savedPanel !== null) {
+ this.onToggleTabs(this.props.savedPanel);
+ this.props.rememberCurrentPanel(null);
+ }
this.props.alarmLogEntriesActions.onToggleFilter();
this.props.currentProblemsActions.onToggleFilter();
diff --git a/sdnr/wt/odlux/apps/inventoryApp/src/fakeData/index.ts b/sdnr/wt/odlux/apps/inventoryApp/src/fakeData/index.ts
new file mode 100644
index 000000000..692ea82c7
--- /dev/null
+++ b/sdnr/wt/odlux/apps/inventoryApp/src/fakeData/index.ts
@@ -0,0 +1,60 @@
+import { InventoryTreeNode, InventoryType } from "models/inventory";
+import { convertPropertyNames, replaceHyphen } from "../../../../framework/src/utilities/yangHelper";
+
+// Tree mittels tree-level und parent UUID (incl)
+// einzelabfrage mit db-id
+const data = [
+ { "manufacturer-identifier": "ONF-Wireless-Transport", "version": "a2.module-newest", "uuid": "a2.module-1.1.1.5", "part-type-id": "3FE25774AA01", "model-identifier": "VAUIAEYAAA", "tree-level": 2, "node-id": "robot_sim_2_equipment", "description": "WS/CORE-MAIN/a2.module#5", "type-name": "a2.module", "serial": "0003548168", "id": "robot_sim_2_equipment/a2.module-1.1.1.5", "parent-uuid": "CARD-1.1.1.0", "contained-holder": ["SUBRACK-1.15.0.0"], "date": "2005-11-09T00:00:00.0Z" },
+ { "manufacturer-identifier": "SAN", "version": "234", "uuid": "CARD-1.1.6.0", "part-type-id": "part-number-12", "model-identifier": "model-id-12", "tree-level": 1, "node-id": "robot_sim_2_equipment", "description": "WS/p8.module", "type-name": "p8.module", "serial": "serial-number-124", "id": "robot_sim_2_equipment/CARD-1.1.6.0", "parent-uuid": "SHELF-1.1.0.0", "contained-holder": ["PORT-1.1.6.5", "PORT-1.1.6.8", "PORT-1.1.6.7", "PORT-1.1.6.6"], "date": "2013-11-23T00:00:00.0Z" },
+ { "manufacturer-identifier": "ONF-Wireless-Transport", "version": "a2.module-newest", "uuid": "a2.module-1.1.6.5", "part-type-id": "3EM23141AD01", "model-identifier": "CRPQABVFAA", "tree-level": 2, "node-id": "robot_sim_2_equipment", "description": "WS/p8.module/a2.module#5", "type-name": "a2.module", "serial": "310330008", "id": "robot_sim_2_equipment/a2.module-1.1.6.5", "parent-uuid": "CARD-1.1.6.0", "contained-holder": ["SUBRACK-1.65.0.0"], "date": "2013-04-13T00:00:00.0Z" },
+ { "manufacturer-identifier": "ONF-Wireless-Transport", "version": "2017", "uuid": "CARD-1.55.1.4", "part-type-id": "partNo2017-12", "model-identifier": "model-id-s3s", "tree-level": 1, "node-id": "robot_sim_2_equipment", "description": "MWR#55Ch#1/RxDiv", "type-name": "RxDiv", "serial": "Serie2017-12", "id": "robot_sim_2_equipment/CARD-1.55.1.4", "parent-uuid": "IDU-1.55.0.0", "date": "2014-01-07T00:00:00.0Z" },
+ { "manufacturer-identifier": "ONF-Wireless-Transport", "version": "a2.module-newest", "uuid": "a2.module-1.56.1.2", "part-type-id": "Partnumber", "model-identifier": "model-id", "tree-level": 1, "node-id": "robot_sim_2_equipment", "description": "MWR#56Ch#1/a2.moduletraff", "type-name": "a2.module", "serial": "Serial1", "id": "robot_sim_2_equipment/a2.module-1.56.1.2", "parent-uuid": "ODU-1.56.0.0", "date": "2017-09-09T00:00:00.0Z" },
+ { "manufacturer-identifier": "SAN", "version": "123", "uuid": "CARD-1.1.1.0", "part-type-id": "part-number-2", "model-identifier": "model-id-2", "tree-level": 1, "node-id": "robot_sim_2_equipment", "description": "WS/CORE-MAIN", "type-name": "latest", "serial": "asdf-asdasd-asd", "id": "robot_sim_2_equipment/CARD-1.1.1.0", "parent-uuid": "SHELF-1.1.0.0", "contained-holder": ["PORT-1.1.1.8", "PORT-1.1.1.7", "PORT-1.1.1.6", "PORT-1.1.1.5"], "date": "2015-08-17T00:00:00.0Z" },
+ { "manufacturer-identifier": "ONF-Wireless-Transport", "version": "a2.module-newest", "uuid": "a2.module-1.1.1.8", "part-type-id": "1AB376720002", "model-identifier": "NGI7AMLMAA", "tree-level": 2, "node-id": "robot_sim_2_equipment", "description": "WS/CORE-MAIN/a2.module#8", "type-name": "a2.module", "serial": "01T441601301", "id": "robot_sim_2_equipment/a2.module-1.1.1.8", "parent-uuid": "CARD-1.1.1.0", "contained-holder": ["SUBRACK-1.18.0.0"], "date": "2010-02-05T00:00:00.0Z" },
+ { "manufacturer-identifier": "SAN", "version": "234", "uuid": "CARD-1.1.5.0", "part-type-id": "part-number-12", "model-identifier": "model-id-12", "tree-level": 1, "node-id": "robot_sim_2_equipment", "description": "WS/p8.module", "type-name": "p8.module", "serial": "africa", "id": "robot_sim_2_equipment/CARD-1.1.5.0", "parent-uuid": "SHELF-1.1.0.0", "contained-holder": ["PORT-1.1.5.6", "PORT-1.1.5.5", "PORT-1.1.5.8", "PORT-1.1.5.7"], "date": "2013-10-21T00:00:00.0Z" },
+ { "manufacturer-identifier": "", "version": "", "uuid": "a2.module-1.1.5.6", "part-type-id": "", "model-identifier": "", "tree-level": 2, "node-id": "robot_sim_2_equipment", "description": "WS/p8.module/a2.module#6", "type-name": "a2.module", "serial": "", "id": "robot_sim_2_equipment/a2.module-1.1.5.6", "parent-uuid": "CARD-1.1.5.0", "contained-holder": ["SUBRACK-1.56.0.0"] }, { "manufacturer-identifier": "ONF-Wireless-Transport", "version": "MWR-ng", "uuid": "IDU-1.65.0.0", "part-type-id": "3DB76047BAAA02", "model-identifier": "model-id-s3s", "tree-level": 0, "node-id": "robot_sim_2_equipment", "description": "MWR-ng Dir#6.5-Ch#1", "type-name": "MWR-ng", "serial": "WAUZZI", "id": "robot_sim_2_equipment/IDU-1.65.0.0", "parent-uuid": "network-element", "contained-holder": ["PORT-1.65.1.4", "PORT-1.65.1.2"], "date": "2014-01-16T00:00:00.0Z" },
+ { "manufacturer-identifier": "ONF-Wireless-Transport", "version": "a2.module-newest", "uuid": "a2.module-1.65.1.2", "part-type-id": "3EM23141AD01", "model-identifier": "CRPQABVFAA", "tree-level": 1, "node-id": "robot_sim_2_equipment", "description": "MWR#65Ch#1/a2.moduletraff", "type-name": "a2.module", "serial": "310330008", "id": "robot_sim_2_equipment/a2.module-1.65.1.2", "parent-uuid": "IDU-1.65.0.0", "date": "2013-04-13T00:00:00.0Z" },
+ { "manufacturer-identifier": "ONF-Wireless-Transport", "version": "a2.module-newest", "uuid": "a2.module-1.1.5.5", "part-type-id": "3EM23141AD01", "model-identifier": "CRPQABVFAA", "tree-level": 2, "node-id": "robot_sim_2_equipment", "description": "WS/p8.module/a2.module#5", "type-name": "a2.module", "serial": "310330015", "id": "robot_sim_2_equipment/a2.module-1.1.5.5", "parent-uuid": "CARD-1.1.5.0", "contained-holder": ["SUBRACK-1.55.0.0"], "date": "2013-04-13T00:00:00.0Z" },
+ { "manufacturer-identifier": "ONF-Wireless-Transport", "version": "unknown", "uuid": "CARD-1.1.8.0", "part-type-id": "unknown", "model-identifier": "model-id-s3s", "tree-level": 1, "node-id": "robot_sim_2_equipment", "description": "WS/DS3", "type-name": "p4.module", "serial": "sd-dsa-eqw", "id": "robot_sim_2_equipment/CARD-1.1.8.0", "parent-uuid": "SHELF-1.1.0.0", "date": "2008-10-21T00:00:00.0Z" },
+ { "manufacturer-identifier": "CIT", "version": "wind", "uuid": "CARD-1.1.9.0", "part-type-id": "party-yea", "model-identifier": "model-id-s3s", "tree-level": 1, "node-id": "robot_sim_2_equipment", "description": "WS/wind", "type-name": "wind", "serial": "proto-type", "id": "robot_sim_2_equipment/CARD-1.1.9.0", "parent-uuid": "SHELF-1.1.0.0", "date": "2007-02-19T00:00:00.0Z" },
+ { "manufacturer-identifier": "ONF-Wireless-Transport", "version": "a2.module-newest", "uuid": "a2.module-1.55.1.2", "part-type-id": "3EM23141AD01", "model-identifier": "CRPQABVFAA", "tree-level": 1, "node-id": "robot_sim_2_equipment", "description": "MWR#55Ch#1/a2.moduletraff", "type-name": "a2.module", "serial": "310330015", "id": "robot_sim_2_equipment/a2.module-1.55.1.2", "parent-uuid": "IDU-1.55.0.0", "date": "2013-04-13T00:00:00.0Z" },
+ { "manufacturer-identifier": "ONF-Wireless-Transport", "version": "a2.module-newest", "uuid": "SHELF-1.1.0.0", "part-type-id": "Partnumber", "model-identifier": "model-id", "tree-level": 0, "node-id": "robot_sim_2_equipment", "description": "WS-8", "type-name": "WS-8", "serial": "Serial1", "id": "robot_sim_2_equipment/SHELF-1.1.0.0", "parent-uuid": "network-element", "contained-holder": ["SLOT-1.1.9.0", "SLOT-1.1.7.0", "SLOT-1.1.8.0", "SLOT-1.1.5.0", "SLOT-1.1.6.0", "SLOT-1.1.3.0", "SLOT-1.1.4.0", "SLOT-1.1.2.0", "SLOT-1.1.1.0"], "date": "2017-09-09T00:00:00.0Z" },
+ { "manufacturer-identifier": "ONF-Wireless-Transport", "version": "MWR-ng", "uuid": "IDU-1.55.0.0", "part-type-id": "3DB76047BAAA02", "model-identifier": "model-id-s3s", "tree-level": 0, "node-id": "robot_sim_2_equipment", "description": "MWR-ng Dir#5.5-Ch#1", "type-name": "MWR-ng", "serial": "Serie2017-14", "id": "robot_sim_2_equipment/IDU-1.55.0.0", "parent-uuid": "network-element", "contained-holder": ["PORT-1.55.1.2", "PORT-1.55.1.4"], "date": "2014-01-15T00:00:00.0Z" },
+ { "manufacturer-identifier": "ONF-Wireless-Transport", "version": "2017", "uuid": "CARD-1.65.1.4", "part-type-id": "partNo2017-12", "model-identifier": "model-id-s3s", "tree-level": 1, "node-id": "robot_sim_2_equipment", "description": "MWR#55Ch#0/RxDiv", "type-name": "RxDiv", "serial": "Serie2017-13", "id": "robot_sim_2_equipment/CARD-1.65.1.4", "parent-uuid": "IDU-1.65.0.0", "date": "2014-01-08T00:00:00.0Z" }, { "manufacturer-identifier": "ONF-Wireless-Transport", "version": "a2.module-newest", "uuid": "a2.module-1.1.1.7", "part-type-id": "1AB187280031", "model-identifier": "mod2", "tree-level": 2, "node-id": "robot_sim_2_equipment", "description": "WS/CORE-MAIN/a2.module#7", "type-name": "a2.module", "serial": "91T403003322", "id": "robot_sim_2_equipment/a2.module-1.1.1.7", "parent-uuid": "CARD-1.1.1.0", "contained-holder": ["SUBRACK-1.17.0.0"], "date": "2009-01-19T00:00:00.0Z" },
+ { "manufacturer-identifier": "CIT", "version": "p1.module", "uuid": "CARD-1.1.7.0", "part-type-id": "part-number-s3s", "model-identifier": "model-id-s3s", "tree-level": 1, "node-id": "robot_sim_2_equipment", "description": "WS/DS1", "type-name": "p1.module_A", "serial": "serial-number-s3s", "id": "robot_sim_2_equipment/CARD-1.1.7.0", "parent-uuid": "SHELF-1.1.0.0", "date": "2007-08-27T00:00:00.0Z" },
+ { "manufacturer-identifier": "", "version": "extrem-hyper", "uuid": "ODU-1.56.0.0", "part-type-id": "", "model-identifier": "", "tree-level": 0, "node-id": "robot_sim_2_equipment", "description": "MWR-hyper Dir#5.6-Ch#1", "type-name": "MWR-hyper", "serial": "", "id": "robot_sim_2_equipment/ODU-1.56.0.0", "parent-uuid": "network-element", "contained-holder": ["PORT-1.56.1.3", "PORT-1.56.1.4", "PORT-1.56.1.2"] }
+];
+
+const deleay = (time: number) => () => new Promise<number>(resolve => setTimeout(resolve, time, time));
+
+const getTreeElements = (searchTerm: string | null, treeLevel: number = 0, parentUUID: string | null = null): [InventoryTreeNode, boolean] => {
+ const elements = (data.filter(e => e["tree-level"] === treeLevel && (!parentUUID || e["parent-uuid"] === parentUUID)) || [])
+ let elementMatch = false;
+ const treeeNode = elements.reduce<InventoryTreeNode>((acc, cur) => {
+ const [children, childMatch] = getTreeElements(searchTerm, treeLevel + 1, cur["node-id"]);
+ const isMatch = searchTerm ? Object.keys(cur).some(k => String((cur as any)[k]).indexOf(searchTerm)) : false;
+ elementMatch = elementMatch || isMatch || childMatch;
+ if (!searchTerm || isMatch || childMatch) {
+ acc[cur["node-id"]] = {
+ label: cur["node-id"],
+ children: children,
+ isMatch: false,
+ };
+ }
+ return acc;
+ }, {});
+
+ return [treeeNode, elementMatch]
+};
+
+export const getTree = async (searchTerm: string | null = null) : Promise<InventoryTreeNode> => {
+ await deleay(600);
+ const [node] = getTreeElements(searchTerm);
+ return node;
+};
+
+export const getElement = async (id: string ): Promise<InventoryType | undefined> => {
+ await deleay(600);
+ const res = data.find(e => e.id === id);
+ return res && convertPropertyNames(res, replaceHyphen) as unknown as InventoryType;
+};
diff --git a/sdnr/wt/odlux/apps/inventoryApp/src/models/inventory.ts b/sdnr/wt/odlux/apps/inventoryApp/src/models/inventory.ts
index 9d747415f..c6b6c91cb 100644
--- a/sdnr/wt/odlux/apps/inventoryApp/src/models/inventory.ts
+++ b/sdnr/wt/odlux/apps/inventoryApp/src/models/inventory.ts
@@ -16,6 +16,7 @@
* ============LICENSE_END==========================================================================
*/
export { HitEntry, Result } from '../../../../framework/src/models';
+
export type InventoryType = {
treeLevel: number;
parentUuid: string;
@@ -32,3 +33,13 @@ export type InventoryType = {
modelIdentifier: string;
typeName: string;
}
+
+export type InventoryTreeNode = {
+ [key: string]: {
+ label: string;
+ children?: InventoryTreeNode;
+ isMatch?: boolean;
+ ownSeverity?: string;
+ childrenSeveritySummary?: string;
+ }
+} \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/inventoryApp/src/services/inventoryService.ts b/sdnr/wt/odlux/apps/inventoryApp/src/services/inventoryService.ts
new file mode 100644
index 000000000..252d6d425
--- /dev/null
+++ b/sdnr/wt/odlux/apps/inventoryApp/src/services/inventoryService.ts
@@ -0,0 +1,37 @@
+/**
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt odlux
+ * =================================================================================================
+ * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * Licensed 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.
+ * ============LICENSE_END==========================================================================
+ */
+import { requestRest } from '../../../../framework/src/services/restService';
+
+import { InventoryTreeNode, InventoryType } from '../models/inventory';
+import { getTree, getElement } from '../fakeData';
+
+/**
+ * Represents a web api accessor service for all maintenence entries related actions.
+ */
+class InventoryService {
+ public async getInventoryTree(searchTerm?: string): Promise<InventoryTreeNode> {
+ return await getTree(searchTerm);
+ }
+
+ public async getInventoryEntry(id: string): Promise<InventoryType| undefined> {
+ return await getElement(id);
+ }
+
+}
+
+export const inventoryService = new InventoryService(); \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/inventoryApp/src/views/dashboard.tsx b/sdnr/wt/odlux/apps/inventoryApp/src/views/dashboard.tsx
index bd182ed5d..b63f628a3 100644
--- a/sdnr/wt/odlux/apps/inventoryApp/src/views/dashboard.tsx
+++ b/sdnr/wt/odlux/apps/inventoryApp/src/views/dashboard.tsx
@@ -16,14 +16,33 @@
* ============LICENSE_END==========================================================================
*/
import * as React from "react";
+import { withStyles, WithStyles, createStyles, Theme } from '@material-ui/core/styles';
import { Connect, connect, IDispatcher } from '../../../../framework/src/flux/connect';
import { MaterialTable, MaterialTableCtorType } from '../../../../framework/src/components/material-table';
+import { TreeView, TreeItem, TreeViewCtorType } from '../../../../framework/src/components/material-ui/treeView';
import { InventoryType } from '../models/inventory';
import { IApplicationStoreState } from "../../../../framework/src/store/applicationStore";
import { createInventoryElementsProperties, createInventoryElementsActions } from "../handlers/inventoryElementsHandler";
+const styles = (theme: Theme) => createStyles({
+ root: {
+ flex: "1 0 0%",
+ display: "flex",
+ flexDirection: "row",
+ },
+ tree: {
+ flex: "1 0 0%",
+ minWidth: "250px",
+ padding: `0px ${theme.spacing(1)}px`
+ },
+ details: {
+ flex: "5 0 0%",
+ padding: `0px ${theme.spacing(1)}px`
+ }
+});
+
const InventoryTable = MaterialTable as MaterialTableCtorType<InventoryType & {_id: string}>;
const mapProps = (state: IApplicationStoreState) => ({
@@ -35,9 +54,28 @@ const mapDispatch = (dispatcher: IDispatcher) => ({
inventoryElementsActions: createInventoryElementsActions(dispatcher.dispatch)
});
-class DashboardComponent extends React.Component<Connect<typeof mapProps, typeof mapDispatch>> {
+const SampleTree = TreeView as any as TreeViewCtorType<string>;
+
+
+type TreeDemoItem = TreeItem<string>;
+
+const treeData: TreeDemoItem[] = [
+ {
+ content: "Erste Ebene", children: [
+ {
+ content: "Zweite Ebene", children: [
+ { content: "Dritte Ebene" },
+ ]
+ },
+ { content: "Zweite Ebene 2" },
+ ]
+ },
+ { content: "Erste Ebene 3" },
+];
+
+class DashboardComponent extends React.Component<& WithStyles<typeof styles> & Connect<typeof mapProps, typeof mapDispatch>> {
render() {
- return <InventoryTable title="Inventory" idProperty="_id" columns={[
+ return <InventoryTable stickyHeader title="Inventory" idProperty="_id" columns={[
{ property: "nodeId", title: "Node Name" },
{ property: "manufacturerIdentifier", title: "Manufacturer" },
{ property: "parentUuid", title: "Parent" },
@@ -60,5 +98,5 @@ class DashboardComponent extends React.Component<Connect<typeof mapProps, typeof
}
}
-export const Dashboard = connect(mapProps, mapDispatch)(DashboardComponent);
+export const Dashboard = connect(mapProps, mapDispatch)(withStyles(styles)(DashboardComponent));
export default Dashboard; \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/inventoryApp/webpack.config.js b/sdnr/wt/odlux/apps/inventoryApp/webpack.config.js
index 426763803..889bb4d8e 100644
--- a/sdnr/wt/odlux/apps/inventoryApp/webpack.config.js
+++ b/sdnr/wt/odlux/apps/inventoryApp/webpack.config.js
@@ -126,11 +126,14 @@ module.exports = (env) => {
colors: true
},
proxy: {
-
"/oauth2/": {
target: "http://localhost:48181",
secure: false
},
+ "/yang-schema/": {
+ target: "http://localhost:48181",
+ secure: false
+ },
"/database/": {
target: "http://localhost:48181",
secure: false
@@ -143,14 +146,13 @@ module.exports = (env) => {
target: "http://localhost:48181",
secure: false
},
- "/websocket/": {
+ "/websocket": {
target: "http://localhost:48181",
ws: true,
- changeOrigin: true,
+ changeOrigin: false,
secure: false
}
}
-
}
}];
}
diff --git a/sdnr/wt/odlux/apps/maintenanceApp/src/views/maintenenceView.tsx b/sdnr/wt/odlux/apps/maintenanceApp/src/views/maintenenceView.tsx
index f557e5399..350bac221 100644
--- a/sdnr/wt/odlux/apps/maintenanceApp/src/views/maintenenceView.tsx
+++ b/sdnr/wt/odlux/apps/maintenanceApp/src/views/maintenenceView.tsx
@@ -37,7 +37,7 @@ import { MaintenenceEntry, spoofSymbol } from '../models/maintenenceEntryType';
import EditMaintenenceEntryDialog, { EditMaintenenceEntryDialogMode } from '../components/editMaintenenceEntryDialog';
import { convertToLocaleString } from '../utils/timeUtils';
-import { createmaintenanceEntriesActions, createmaintenanceEntriesProperties,maintenanceEntriesReloadAction } from '../handlers/maintenenceEntriesHandler';
+import { createmaintenanceEntriesActions, createmaintenanceEntriesProperties, maintenanceEntriesReloadAction } from '../handlers/maintenenceEntriesHandler';
const styles = (theme: Theme) => createStyles({
button: {
@@ -60,7 +60,7 @@ const mapProps = (state: IApplicationStoreState) => ({
const mapDispatcher = (dispatcher: IDispatcher) => ({
maintenanceEntriesActions: createmaintenanceEntriesActions(dispatcher.dispatch),
- onLoadMaintenanceEntries: async() => {
+ onLoadMaintenanceEntries: async () => {
await dispatcher.dispatch(maintenanceEntriesReloadAction)
}
});
@@ -104,8 +104,8 @@ class MaintenenceViewComponent extends React.Component<MaintenenceViewComponentP
this.setState({
maintenenceEntryToEdit: {
...emptyMaintenenceEntry,
- start: convertToLocaleString(startTime),
- end: convertToLocaleString(endTime),
+ start: convertToLocaleString(startTime),
+ end: convertToLocaleString(endTime),
},
maintenenceEntryEditorMode: EditMaintenenceEntryDialogMode.AddMaintenenceEntry
});
@@ -114,13 +114,13 @@ class MaintenenceViewComponent extends React.Component<MaintenenceViewComponentP
const now = new Date().valueOf();
return (
<>
- <MaintenenceEntriesTable title={"Maintenance"} customActionButtons={[addMaintenenceEntryAction]} columns={
+ <MaintenenceEntriesTable stickyHeader title={"Maintenance"} customActionButtons={[addMaintenenceEntryAction]} columns={
[
{ property: "nodeId", title: "Node Name", type: ColumnType.text },
{
property: "notifications", title: "Notification", width: 50, align: "center", type: ColumnType.custom, customControl: ({ rowData }) => (
rowData.active && (Date.parse(rowData.start).valueOf() <= now) && (Date.parse(rowData.end).valueOf() >= now) && <FontAwesomeIcon icon={faBan} /> || null
- )
+ )
},
{ property: "active", title: "Activation State", type: ColumnType.boolean, labels: { "true": "active", "false": "not active" }, },
{ property: "start", title: "Start Date (UTC)", type: ColumnType.text },
@@ -140,7 +140,7 @@ class MaintenenceViewComponent extends React.Component<MaintenenceViewComponentP
)
},
]
- } idProperty={'_id'}{...this.props.maintenanceEntriesActions} {...this.props.maintenanceEntriesProperties} asynchronus > </MaintenenceEntriesTable>
+ } idProperty={'_id'}{...this.props.maintenanceEntriesActions} {...this.props.maintenanceEntriesProperties} asynchronus > </MaintenenceEntriesTable>
<EditMaintenenceEntryDialog initialMaintenenceEntry={this.state.maintenenceEntryToEdit} mode={this.state.maintenenceEntryEditorMode}
onClose={this.onCloseEditMaintenenceEntryDialog} />
</>
@@ -160,8 +160,8 @@ class MaintenenceViewComponent extends React.Component<MaintenenceViewComponentP
this.setState({
maintenenceEntryToEdit: {
...entry,
- start: convertToLocaleString(startTime),
- end: convertToLocaleString(endTime),
+ start: convertToLocaleString(startTime),
+ end: convertToLocaleString(endTime),
},
maintenenceEntryEditorMode: EditMaintenenceEntryDialogMode.EditMaintenenceEntry
});
@@ -175,8 +175,8 @@ class MaintenenceViewComponent extends React.Component<MaintenenceViewComponentP
this.setState({
maintenenceEntryToEdit: {
...entry,
- start: convertToLocaleString(startTime),
- end: convertToLocaleString(endTime),
+ start: convertToLocaleString(startTime),
+ end: convertToLocaleString(endTime),
},
maintenenceEntryEditorMode: EditMaintenenceEntryDialogMode.EditMaintenenceEntry
});
@@ -190,7 +190,7 @@ class MaintenenceViewComponent extends React.Component<MaintenenceViewComponentP
this.setState({
maintenenceEntryToEdit: {
...entry,
- ...(entry.start && endTime)
+ ...(entry.start && endTime)
? { start: convertToLocaleString(entry.start), end: convertToLocaleString(entry.end) }
: { start: convertToLocaleString(startTime), end: convertToLocaleString(endTime) }
},
diff --git a/sdnr/wt/odlux/apps/mediatorApp/src/views/mediatorApplication.tsx b/sdnr/wt/odlux/apps/mediatorApp/src/views/mediatorApplication.tsx
index 945e13507..d422a0c3b 100644
--- a/sdnr/wt/odlux/apps/mediatorApp/src/views/mediatorApplication.tsx
+++ b/sdnr/wt/odlux/apps/mediatorApp/src/views/mediatorApplication.tsx
@@ -161,7 +161,7 @@ class MediatorApplicationComponent extends React.Component<MediatorApplicationCo
this.props.isReachable ?
- <MediatorServerConfigurationsTable title={this.props.serverName || ''} customActionButtons={[addMediatorConfigAction]} idProperty={"Name"} rows={this.props.configurations} asynchronus columns={[
+ <MediatorServerConfigurationsTable stickyHeader title={this.props.serverName || ''} customActionButtons={[addMediatorConfigAction]} idProperty={"Name"} rows={this.props.configurations} asynchronus columns={[
{ property: "Name", title: "Mediator", type: ColumnType.text },
{ property: "Status", title: "Status", type: ColumnType.custom, customControl: ({ rowData }) => rowData.pid ? (<span>Running</span>) : (<span>Stopped</span>) },
{ property: "DeviceIp", title: "IP Adress", type: ColumnType.text },
diff --git a/sdnr/wt/odlux/apps/mediatorApp/src/views/mediatorServerSelection.tsx b/sdnr/wt/odlux/apps/mediatorApp/src/views/mediatorServerSelection.tsx
index a5b34a2dc..aaade65db 100644
--- a/sdnr/wt/odlux/apps/mediatorApp/src/views/mediatorServerSelection.tsx
+++ b/sdnr/wt/odlux/apps/mediatorApp/src/views/mediatorServerSelection.tsx
@@ -94,7 +94,7 @@ class MediatorServerSelectionComponent extends React.Component<MediatorServerSel
};
return (
<>
- <MediatorServersTable title={"Mediator"} customActionButtons={[addMediatorServerActionButton]} idProperty={"id"}
+ <MediatorServersTable stickyHeader title={"Mediator"} customActionButtons={[addMediatorServerActionButton]} idProperty={"id"}
{...this.props.mediatorServersActions} {...this.props.mediatorServersProperties} columns={[
{ property: "name", title: "Name", type: ColumnType.text },
{ property: "url", title: "Url", type: ColumnType.text },
diff --git a/sdnr/wt/odlux/apps/performanceHistoryApp/src/actions/ltpAction.ts b/sdnr/wt/odlux/apps/performanceHistoryApp/src/actions/ltpAction.ts
index 375617593..a678ed78c 100644
--- a/sdnr/wt/odlux/apps/performanceHistoryApp/src/actions/ltpAction.ts
+++ b/sdnr/wt/odlux/apps/performanceHistoryApp/src/actions/ltpAction.ts
@@ -50,6 +50,18 @@ export class SetInitialLoadedAction extends BaseAction {
}
}
+export class NoLtpsFoundAction extends BaseAction {
+ constructor() {
+ super();
+ }
+}
+
+export class ResetLtpsAction extends BaseAction {
+ constructor() {
+ super();
+ }
+}
+
/**
* Represents an asynchronous thunk action to load available distinctLtps by networkElement from the database and set the returned first Ltp as default.
@@ -65,6 +77,10 @@ export const loadDistinctLtpsbyNetworkElementAsync = (networkElement: string, se
if (distinctLtps) {
const ltps = getDistinctLtps(distinctLtps, selectedLtp, selectFirstLtp, resetLtp);
dispatch(new AllAvailableLtpsLoadedAction(ltps));
+ } else {
+ if (resetLtp)
+ resetLtp();
+ dispatch(new NoLtpsFoundAction());
}
}).catch(error => {
dispatch(new AllAvailableLtpsLoadedAction(null, error));
diff --git a/sdnr/wt/odlux/apps/performanceHistoryApp/src/actions/toggleActions.ts b/sdnr/wt/odlux/apps/performanceHistoryApp/src/actions/toggleActions.ts
index 1f53a5806..0efaaae92 100644
--- a/sdnr/wt/odlux/apps/performanceHistoryApp/src/actions/toggleActions.ts
+++ b/sdnr/wt/odlux/apps/performanceHistoryApp/src/actions/toggleActions.ts
@@ -1,3 +1,21 @@
+/**
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt odlux
+ * =================================================================================================
+ * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property. All rights reserved.
+ * =================================================================================================
+ * Licensed 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.
+ * ============LICENSE_END==========================================================================
+ */
+
import { Action } from "../../../../framework/src/flux/action";
import { currentViewType } from "../models/toggleDataType";
@@ -12,4 +30,10 @@ export class ResetAllSubViewsAction extends Action {
constructor() {
super();
}
+}
+
+export class SetFilterVisibility extends Action {
+ constructor(public currentView: currentViewType, public isVisible: boolean) {
+ super();
+ }
} \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/performanceHistoryApp/src/components/adaptiveModulation.tsx b/sdnr/wt/odlux/apps/performanceHistoryApp/src/components/adaptiveModulation.tsx
index c62698630..ca00d8214 100644
--- a/sdnr/wt/odlux/apps/performanceHistoryApp/src/components/adaptiveModulation.tsx
+++ b/sdnr/wt/odlux/apps/performanceHistoryApp/src/components/adaptiveModulation.tsx
@@ -29,17 +29,19 @@ import { createAdaptiveModulationProperties, createAdaptiveModulationActions } f
import { lineChart, sortDataByTimeStamp } from '../utils/chartUtils';
import { addColumnLabels } from '../utils/tableUtils';
import ToggleContainer from './toggleContainer';
-import { SetSubViewAction } from '../actions/toggleActions';
+import { SetSubViewAction, SetFilterVisibility } from '../actions/toggleActions';
const mapProps = (state: IApplicationStoreState) => ({
adaptiveModulationProperties: createAdaptiveModulationProperties(state),
- currentView: state.performanceHistory.subViews.adaptiveModulation,
-
+ currentView: state.performanceHistory.subViews.adaptiveModulation.subView,
+ isFilterVisible: state.performanceHistory.subViews.adaptiveModulation.isFilterVisible,
+ existingFilter: state.performanceHistory.adaptiveModulation.filter
});
const mapDisp = (dispatcher: IDispatcher) => ({
adaptiveModulationActions: createAdaptiveModulationActions(dispatcher.dispatch),
setSubView: (value: "chart" | "table") => dispatcher.dispatch(new SetSubViewAction("adaptiveModulation", value)),
+ toggleFilterButton: (value: boolean) => { dispatcher.dispatch(new SetFilterVisibility("adaptiveModulation", value)) },
});
type AdaptiveModulationComponentProps = RouteComponentProps & Connect<typeof mapProps, typeof mapDisp> & {
@@ -52,6 +54,11 @@ const AdaptiveModulationTable = MaterialTable as MaterialTableCtorType<AdaptiveM
* The Component which gets the adaptiveModulation data from the database based on the selected time period.
*/
class AdaptiveModulationComponent extends React.Component<AdaptiveModulationComponentProps>{
+
+ onToggleFilterButton = () => {
+ this.props.toggleFilterButton(!this.props.isFilterVisible);
+ }
+
onChange = (value: "chart" | "table") => {
this.props.setSubView(value);
}
@@ -66,10 +73,7 @@ class AdaptiveModulationComponent extends React.Component<AdaptiveModulationComp
{ property: "scannerId", title: "Scanner ID", type: ColumnType.text },
{ property: "timeStamp", title: "End Time", type: ColumnType.text },
{
- property: "suspectIntervalFlag", title: "Suspect Interval", customControl: ({ rowData }) => {
- const suspectIntervalFlag = rowData["suspectIntervalFlag"].toString();
- return <div >{suspectIntervalFlag} </div>
- }
+ property: "suspectIntervalFlag", title: "Suspect Interval", type: ColumnType.boolean
}];
chartPagedData.datasets.forEach(ds => {
@@ -78,9 +82,9 @@ class AdaptiveModulationComponent extends React.Component<AdaptiveModulationComp
return (
<>
- <ToggleContainer selectedValue={this.props.currentView} onChange={this.onChange}>
+ <ToggleContainer onToggleFilterButton={this.onToggleFilterButton} showFilter={this.props.isFilterVisible} existingFilter={this.props.adaptiveModulationProperties.filter} onFilterChanged={this.props.adaptiveModulationActions.onFilterChanged} selectedValue={this.props.currentView} onChange={this.onChange}>
{lineChart(chartPagedData)}
- <AdaptiveModulationTable idProperty={"_id"} columns={adaptiveModulationColumns} {...properties} {...actions} />
+ <AdaptiveModulationTable stickyHeader idProperty={"_id"} columns={adaptiveModulationColumns} {...properties} {...actions} />
</ToggleContainer>
</>
);
diff --git a/sdnr/wt/odlux/apps/performanceHistoryApp/src/components/chartFilter.tsx b/sdnr/wt/odlux/apps/performanceHistoryApp/src/components/chartFilter.tsx
new file mode 100644
index 000000000..280a1dac8
--- /dev/null
+++ b/sdnr/wt/odlux/apps/performanceHistoryApp/src/components/chartFilter.tsx
@@ -0,0 +1,50 @@
+import * as React from 'react';
+import { makeStyles, TextField, Typography, Select, MenuItem, FormControl, InputLabel } from '@material-ui/core';
+
+const styles = makeStyles({
+ filterInput: {
+ marginRight: "15px"
+ },
+ filterContainer: {
+ marginLeft: "90px"
+ }
+});
+
+type filterProps = { isVisible: boolean, onFilterChanged: (property: string, filterTerm: string) => void, filters: any };
+//put chart visibility into redux
+const ChartFilter: React.FunctionComponent<filterProps> = (props) => {
+
+ //get filter from redux state (just pass da object?), onfilterchange
+ const classes = styles();
+
+ return (
+ <>
+ {
+ props.isVisible &&
+ <div className={classes.filterContainer}>
+ <TextField className={classes.filterInput} label="Radio Signal" value={props.filters.radioSignalId || ''} onChange={(event) => props.onFilterChanged("radioSignalId", event.target.value)} InputLabelProps={{
+ shrink: true,
+ }} />
+ <TextField className={classes.filterInput} label="Scanner ID" value={props.filters.scannerId || ''} onChange={(event) => props.onFilterChanged("scannerId", event.target.value)} InputLabelProps={{
+ shrink: true,
+ }} />
+ <TextField className={classes.filterInput} label="End Time" value={props.filters.timeStamp || ''} onChange={(event) => props.onFilterChanged("timeStamp", event.target.value)} InputLabelProps={{
+ shrink: true,
+ }} />
+ <FormControl>
+ <InputLabel id="suspect-interval-label" shrink>Suspect Interval</InputLabel>
+
+ <Select labelId="suspect-interval-label" value={props.filters.suspectIntervalFlag || ''} onChange={(event) => props.onFilterChanged("suspectIntervalFlag", event.target.value as string)}>
+ <MenuItem value={undefined}>None</MenuItem>
+ <MenuItem value={"true"}>true</MenuItem>
+ <MenuItem value={"false"}>false</MenuItem>
+ </Select>
+ </FormControl>
+ </ div>
+ }
+ </>
+ )
+
+}
+
+export default ChartFilter; \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/performanceHistoryApp/src/components/crossPolarDiscrimination.tsx b/sdnr/wt/odlux/apps/performanceHistoryApp/src/components/crossPolarDiscrimination.tsx
index 7489757f5..a8c6ed78d 100644
--- a/sdnr/wt/odlux/apps/performanceHistoryApp/src/components/crossPolarDiscrimination.tsx
+++ b/sdnr/wt/odlux/apps/performanceHistoryApp/src/components/crossPolarDiscrimination.tsx
@@ -28,19 +28,22 @@ import { IDataSet, IDataSetsObject } from '../models/chartTypes';
import { createCrossPolarDiscriminationProperties, createCrossPolarDiscriminationActions } from '../handlers/crossPolarDiscriminationHandler';
import { lineChart, sortDataByTimeStamp } from '../utils/chartUtils';
import { addColumnLabels } from '../utils/tableUtils';
-import { SetSubViewAction } from '../actions/toggleActions';
+import { SetSubViewAction, SetFilterVisibility } from '../actions/toggleActions';
import ToggleContainer from './toggleContainer';
const mapProps = (state: IApplicationStoreState) => ({
crossPolarDiscriminationProperties: createCrossPolarDiscriminationProperties(state),
- currentView: state.performanceHistory.subViews.CPD,
+ currentView: state.performanceHistory.subViews.CPD.subView,
+ isFilterVisible: state.performanceHistory.subViews.CPD.isFilterVisible,
+ existingFilter: state.performanceHistory.crossPolarDiscrimination.filter
});
const mapDisp = (dispatcher: IDispatcher) => ({
crossPolarDiscriminationActions: createCrossPolarDiscriminationActions(dispatcher.dispatch),
setSubView: (value: "chart" | "table") => dispatcher.dispatch(new SetSubViewAction("CPD", value)),
+ toggleFilterButton: (value: boolean) => { dispatcher.dispatch(new SetFilterVisibility("CPD", value)) },
});
type CrossPolarDiscriminationComponentProps = RouteComponentProps & Connect<typeof mapProps, typeof mapDisp> & {
@@ -54,6 +57,10 @@ const CrossPolarDiscriminationTable = MaterialTable as MaterialTableCtorType<Cro
*/
class CrossPolarDiscriminationComponent extends React.Component<CrossPolarDiscriminationComponentProps>{
+ onToggleFilterButton = () => {
+ this.props.toggleFilterButton(!this.props.isFilterVisible);
+ }
+
onChange = (value: "chart" | "table") => {
this.props.setSubView(value);
}
@@ -69,10 +76,7 @@ class CrossPolarDiscriminationComponent extends React.Component<CrossPolarDiscri
{ property: "scannerId", title: "Scanner ID", type: ColumnType.text },
{ property: "timeStamp", title: "End Time", type: ColumnType.text },
{
- property: "suspectIntervalFlag", title: "Suspect Interval", customControl: ({ rowData }) => {
- const suspectIntervalFlag = rowData["suspectIntervalFlag"].toString();
- return <div >{suspectIntervalFlag} </div>
- }
+ property: "suspectIntervalFlag", title: "Suspect Interval", type: ColumnType.boolean
}
];
@@ -81,9 +85,9 @@ class CrossPolarDiscriminationComponent extends React.Component<CrossPolarDiscri
});
return (
<>
- <ToggleContainer selectedValue={this.props.currentView} onChange={this.onChange}>
+ <ToggleContainer onToggleFilterButton={this.onToggleFilterButton} showFilter={this.props.isFilterVisible} existingFilter={this.props.crossPolarDiscriminationProperties.filter} onFilterChanged={this.props.crossPolarDiscriminationActions.onFilterChanged} selectedValue={this.props.currentView} onChange={this.onChange}>
{lineChart(chartPagedData)}
- <CrossPolarDiscriminationTable idProperty={"_id"} columns={cpdColumns} {...properties} {...actions} />
+ <CrossPolarDiscriminationTable stickyHeader idProperty={"_id"} columns={cpdColumns} {...properties} {...actions} />
</ToggleContainer>
</>
);
diff --git a/sdnr/wt/odlux/apps/performanceHistoryApp/src/components/ltpSelection.tsx b/sdnr/wt/odlux/apps/performanceHistoryApp/src/components/ltpSelection.tsx
index 8327ec4ed..b0aebd208 100644
--- a/sdnr/wt/odlux/apps/performanceHistoryApp/src/components/ltpSelection.tsx
+++ b/sdnr/wt/odlux/apps/performanceHistoryApp/src/components/ltpSelection.tsx
@@ -17,7 +17,7 @@
*/
import * as React from 'react';
-import { MenuItem, Select, FormControl } from '@material-ui/core';
+import { MenuItem, Select, FormControl, Typography } from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
import { LtpIds } from 'models/availableLtps';
import { Loader } from '../../../../framework/src/components/material-ui';
@@ -43,10 +43,11 @@ const useStyles = makeStyles(theme => ({
"display": "flex",
"alignItems": "center",
"justifyContent": "center",
+ flexDirection: "column"
}
}));
-type LtpSelectionProps = { selectedNE: string, finishedLoading: boolean, selectedLtp: string, availableLtps: LtpIds[], onChangeLtp(event: React.ChangeEvent<HTMLSelectElement>): void, selectedTimePeriod: string, onChangeTimePeriod(event: React.ChangeEvent<HTMLSelectElement>): void };
+type LtpSelectionProps = { selectedNE: string, error?: string, finishedLoading: boolean, selectedLtp: string, availableLtps: LtpIds[], onChangeLtp(event: React.ChangeEvent<HTMLSelectElement>): void, selectedTimePeriod: string, onChangeTimePeriod(event: React.ChangeEvent<HTMLSelectElement>): void };
export const LtpSelection = (props: LtpSelectionProps) => {
const classes = useStyles();
@@ -69,18 +70,29 @@ export const LtpSelection = (props: LtpSelectionProps) => {
</Select>
</FormControl>
{
- !props.finishedLoading &&
+ !props.finishedLoading && !props.error &&
<div className={classes.center}>
<Loader />
<h3>Collecting Data ...</h3>
</div>
}
{
- props.selectedLtp === "-1" && props.finishedLoading &&
+ props.finishedLoading && props.error &&
<div className={classes.center}>
- <h3>Please select a LTP</h3>
+ <h3>Data couldn't be loaded</h3>
+ <Typography variant="body1">{props.error}</Typography>
</div>
}
+ {
+ props.selectedLtp === "-1" && props.finishedLoading && !props.error && (props.availableLtps.length > 0 ?
+ <div className={classes.center}>
+ <h3>Please select a LTP</h3>
+ </div>
+ :
+ <div className={classes.center}>
+ <h3>No performance data found</h3>
+ </div>)
+ }
</>)
}
diff --git a/sdnr/wt/odlux/apps/performanceHistoryApp/src/components/performanceData.tsx b/sdnr/wt/odlux/apps/performanceHistoryApp/src/components/performanceData.tsx
index d0caa6fd6..0a4f03273 100644
--- a/sdnr/wt/odlux/apps/performanceHistoryApp/src/components/performanceData.tsx
+++ b/sdnr/wt/odlux/apps/performanceHistoryApp/src/components/performanceData.tsx
@@ -28,16 +28,19 @@ import { createPerformanceDataProperties, createPerformanceDataActions } from '.
import { lineChart, sortDataByTimeStamp } from '../utils/chartUtils';
import { addColumnLabels } from '../utils/tableUtils';
import ToggleContainer from './toggleContainer';
-import { SetSubViewAction } from '../actions/toggleActions';
+import { SetSubViewAction, SetFilterVisibility } from '../actions/toggleActions';
const mapProps = (state: IApplicationStoreState) => ({
performanceDataProperties: createPerformanceDataProperties(state),
- currentView: state.performanceHistory.subViews.performanceDataSelection,
+ currentView: state.performanceHistory.subViews.performanceData.subView,
+ isFilterVisible: state.performanceHistory.subViews.performanceData.isFilterVisible,
+ existingFilter: state.performanceHistory.performanceData.filter
});
const mapDisp = (dispatcher: IDispatcher) => ({
performanceDataActions: createPerformanceDataActions(dispatcher.dispatch),
setSubView: (value: "chart" | "table") => dispatcher.dispatch(new SetSubViewAction("performanceData", value)),
+ toggleFilterButton: (value: boolean) => { dispatcher.dispatch(new SetFilterVisibility("performanceData", value)) }
});
type PerformanceDataComponentProps = RouteComponentProps & Connect<typeof mapProps, typeof mapDisp> & {
@@ -51,8 +54,8 @@ const PerformanceDataTable = MaterialTable as MaterialTableCtorType<PerformanceD
*/
class PerformanceDataComponent extends React.Component<PerformanceDataComponentProps>{
- onChange = (value: "chart" | "table") => {
- this.props.setSubView(value);
+ onToggleFilterButton = () => {
+ this.props.toggleFilterButton(!this.props.isFilterVisible);
}
render(): JSX.Element {
@@ -65,10 +68,7 @@ class PerformanceDataComponent extends React.Component<PerformanceDataComponentP
{ property: "scannerId", title: "Scanner ID", type: ColumnType.text },
{ property: "timeStamp", title: "End Time", type: ColumnType.text },
{
- property: "suspectIntervalFlag", title: "Suspect Interval", customControl: ({ rowData }) => {
- const suspectIntervalFlag = rowData["suspectIntervalFlag"].toString();
- return <div >{suspectIntervalFlag} </div>
- }
+ property: "suspectIntervalFlag", title: "Suspect Interval", type: ColumnType.boolean
}
];
@@ -77,9 +77,9 @@ class PerformanceDataComponent extends React.Component<PerformanceDataComponentP
});
return (
<>
- <ToggleContainer selectedValue={this.props.currentView} onChange={this.onChange}>
+ <ToggleContainer onToggleFilterButton={() => this.props.toggleFilterButton(!this.props.isFilterVisible)} existingFilter={this.props.existingFilter} onFilterChanged={this.props.performanceDataActions.onFilterChanged} selectedValue={this.props.currentView} showFilter={this.props.isFilterVisible} onChange={this.props.setSubView}>
{lineChart(chartPagedData)}
- <PerformanceDataTable idProperty={"_id"} columns={performanceColumns} {...properties} {...actions} />
+ <PerformanceDataTable stickyHeader idProperty={"_id"} columns={performanceColumns} {...properties} {...actions} />
</ToggleContainer>
</>
);
diff --git a/sdnr/wt/odlux/apps/performanceHistoryApp/src/components/receiveLevel.tsx b/sdnr/wt/odlux/apps/performanceHistoryApp/src/components/receiveLevel.tsx
index 4b0a835d4..ae729306b 100644
--- a/sdnr/wt/odlux/apps/performanceHistoryApp/src/components/receiveLevel.tsx
+++ b/sdnr/wt/odlux/apps/performanceHistoryApp/src/components/receiveLevel.tsx
@@ -28,19 +28,20 @@ import { IDataSet, IDataSetsObject } from '../models/chartTypes';
import { createReceiveLevelProperties, createReceiveLevelActions } from '../handlers/receiveLevelHandler';
import { lineChart, sortDataByTimeStamp } from '../utils/chartUtils';
import { addColumnLabels } from '../utils/tableUtils';
-import { SetSubViewAction } from '../actions/toggleActions';
+import { SetSubViewAction, SetFilterVisibility } from '../actions/toggleActions';
import ToggleContainer from './toggleContainer';
const mapProps = (state: IApplicationStoreState) => ({
receiveLevelProperties: createReceiveLevelProperties(state),
- currentView: state.performanceHistory.subViews.receiveLevelDataSelection,
-
+ currentView: state.performanceHistory.subViews.receiveLevel.subView,
+ isFilterVisible: state.performanceHistory.subViews.receiveLevel.isFilterVisible,
+ existingFilter: state.performanceHistory.receiveLevel.filter
});
const mapDisp = (dispatcher: IDispatcher) => ({
receiveLevelActions: createReceiveLevelActions(dispatcher.dispatch),
setSubView: (value: "chart" | "table") => dispatcher.dispatch(new SetSubViewAction("receiveLevel", value)),
-
+ toggleFilterButton: (value: boolean) => { dispatcher.dispatch(new SetFilterVisibility("receiveLevel", value)) },
});
type ReceiveLevelComponentProps = RouteComponentProps & Connect<typeof mapProps, typeof mapDisp> & {
@@ -54,6 +55,11 @@ const ReceiveLevelTable = MaterialTable as MaterialTableCtorType<ReceiveLevelDat
*/
class ReceiveLevelComponent extends React.Component<ReceiveLevelComponentProps>{
+ onToggleFilterButton = () => {
+ this.props.toggleFilterButton(!this.props.isFilterVisible);
+ }
+
+
onChange = (value: "chart" | "table") => {
this.props.setSubView(value);
}
@@ -68,10 +74,7 @@ class ReceiveLevelComponent extends React.Component<ReceiveLevelComponentProps>{
{ property: "scannerId", title: "Scanner ID", type: ColumnType.text },
{ property: "timeStamp", title: "End Time", type: ColumnType.text },
{
- property: "suspectIntervalFlag", title: "Suspect Interval", customControl: ({ rowData }) => {
- const suspectIntervalFlag = rowData["suspectIntervalFlag"].toString();
- return <div >{suspectIntervalFlag} </div>
- }
+ property: "suspectIntervalFlag", title: "Suspect Interval", type: ColumnType.boolean
}
];
@@ -81,9 +84,9 @@ class ReceiveLevelComponent extends React.Component<ReceiveLevelComponentProps>{
return (
<>
- <ToggleContainer selectedValue={this.props.currentView} onChange={this.onChange}>
+ <ToggleContainer onToggleFilterButton={this.onToggleFilterButton} showFilter={this.props.isFilterVisible} existingFilter={this.props.receiveLevelProperties.filter} onFilterChanged={this.props.receiveLevelActions.onFilterChanged} selectedValue={this.props.currentView} onChange={this.onChange}>
{lineChart(chartPagedData)}
- <ReceiveLevelTable idProperty={"_id"} columns={receiveLevelColumns} {...properties} {...actions} />
+ <ReceiveLevelTable stickyHeader idProperty={"_id"} columns={receiveLevelColumns} {...properties} {...actions} />
</ToggleContainer>
</>
);
diff --git a/sdnr/wt/odlux/apps/performanceHistoryApp/src/components/signalToInterference.tsx b/sdnr/wt/odlux/apps/performanceHistoryApp/src/components/signalToInterference.tsx
index ba480d57d..00eba5fe3 100644
--- a/sdnr/wt/odlux/apps/performanceHistoryApp/src/components/signalToInterference.tsx
+++ b/sdnr/wt/odlux/apps/performanceHistoryApp/src/components/signalToInterference.tsx
@@ -28,17 +28,20 @@ import { IDataSet, IDataSetsObject } from '../models/chartTypes';
import { createSignalToInterferenceProperties, createSignalToInterferenceActions } from '../handlers/signalToInterferenceHandler';
import { lineChart, sortDataByTimeStamp } from '../utils/chartUtils';
import { addColumnLabels } from '../utils/tableUtils';
-import { SetSubViewAction } from '../actions/toggleActions';
+import { SetSubViewAction, SetFilterVisibility } from '../actions/toggleActions';
import ToggleContainer from './toggleContainer';
const mapProps = (state: IApplicationStoreState) => ({
signalToInterferenceProperties: createSignalToInterferenceProperties(state),
- currentView: state.performanceHistory.subViews.SINR,
+ currentView: state.performanceHistory.subViews.SINR.subView,
+ isFilterVisible: state.performanceHistory.subViews.SINR.isFilterVisible,
+ existingFilter: state.performanceHistory.signalToInterference.filter
});
const mapDisp = (dispatcher: IDispatcher) => ({
signalToInterferenceActions: createSignalToInterferenceActions(dispatcher.dispatch),
setSubView: (value: "chart" | "table") => dispatcher.dispatch(new SetSubViewAction("SINR", value)),
+ toggleFilterButton: (value: boolean) => { dispatcher.dispatch(new SetFilterVisibility("SINR", value)) },
});
type SignalToInterferenceComponentProps = RouteComponentProps & Connect<typeof mapProps, typeof mapDisp> & {
@@ -52,6 +55,10 @@ const SignalToInterferenceTable = MaterialTable as MaterialTableCtorType<SignalT
*/
class SignalToInterferenceComponent extends React.Component<SignalToInterferenceComponentProps>{
+ onToggleFilterButton = () => {
+ this.props.toggleFilterButton(!this.props.isFilterVisible);
+ }
+
onChange = (value: "chart" | "table") => {
this.props.setSubView(value);
}
@@ -67,10 +74,7 @@ class SignalToInterferenceComponent extends React.Component<SignalToInterference
{ property: "scannerId", title: "Scanner ID", type: ColumnType.text },
{ property: "timeStamp", title: "End Time", type: ColumnType.text },
{
- property: "suspectIntervalFlag", title: "Suspect Interval", customControl: ({ rowData }) => {
- const suspectIntervalFlag = rowData["suspectIntervalFlag"].toString();
- return <div >{suspectIntervalFlag} </div>
- }
+ property: "suspectIntervalFlag", title: "Suspect Interval", type: ColumnType.boolean
}
];
@@ -79,9 +83,9 @@ class SignalToInterferenceComponent extends React.Component<SignalToInterference
});
return (
<>
- <ToggleContainer selectedValue={this.props.currentView} onChange={this.onChange}>
+ <ToggleContainer onToggleFilterButton={this.onToggleFilterButton} showFilter={this.props.isFilterVisible} existingFilter={this.props.signalToInterferenceProperties.filter} onFilterChanged={this.props.signalToInterferenceActions.onFilterChanged} selectedValue={this.props.currentView} onChange={this.onChange}>
{lineChart(chartPagedData)}
- <SignalToInterferenceTable idProperty={"_id"} columns={sinrColumns} {...properties} {...actions}
+ <SignalToInterferenceTable stickyHeader idProperty={"_id"} columns={sinrColumns} {...properties} {...actions}
/>
</ToggleContainer>
</>
diff --git a/sdnr/wt/odlux/apps/performanceHistoryApp/src/components/temperature.tsx b/sdnr/wt/odlux/apps/performanceHistoryApp/src/components/temperature.tsx
index 28f75d84c..c0d12ee47 100644
--- a/sdnr/wt/odlux/apps/performanceHistoryApp/src/components/temperature.tsx
+++ b/sdnr/wt/odlux/apps/performanceHistoryApp/src/components/temperature.tsx
@@ -29,16 +29,20 @@ import { createTemperatureProperties, createTemperatureActions } from '../handle
import { lineChart, sortDataByTimeStamp } from '../utils/chartUtils';
import { addColumnLabels } from '../utils/tableUtils';
import ToggleContainer from './toggleContainer';
-import { SetSubViewAction } from '../actions/toggleActions';
+import { SetSubViewAction, SetFilterVisibility } from '../actions/toggleActions';
const mapProps = (state: IApplicationStoreState) => ({
temperatureProperties: createTemperatureProperties(state),
- currentView: state.performanceHistory.subViews.temperatur,
+ currentView: state.performanceHistory.subViews.temperatur.subView,
+ isFilterVisible: state.performanceHistory.subViews.temperatur.isFilterVisible,
+ existingFilter: state.performanceHistory.temperature.filter
});
const mapDisp = (dispatcher: IDispatcher) => ({
temperatureActions: createTemperatureActions(dispatcher.dispatch),
setSubView: (value: "chart" | "table") => dispatcher.dispatch(new SetSubViewAction("Temp", value)),
+ toggleFilterButton: (value: boolean) => { dispatcher.dispatch(new SetFilterVisibility("Temp", value)) },
+
});
type TemperatureComponentProps = RouteComponentProps & Connect<typeof mapProps, typeof mapDisp> & {
@@ -52,6 +56,11 @@ const TemperatureTable = MaterialTable as MaterialTableCtorType<TemperatureDataT
*/
class TemperatureComponent extends React.Component<TemperatureComponentProps>{
+ onToggleFilterButton = () => {
+ this.props.toggleFilterButton(!this.props.isFilterVisible);
+ }
+
+
onChange = (value: "chart" | "table") => {
this.props.setSubView(value);
}
@@ -66,10 +75,7 @@ class TemperatureComponent extends React.Component<TemperatureComponentProps>{
{ property: "scannerId", title: "Scanner ID", type: ColumnType.text },
{ property: "timeStamp", title: "End Time", type: ColumnType.text },
{
- property: "suspectIntervalFlag", title: "Suspect Interval", customControl: ({ rowData }) => {
- const suspectIntervalFlag = rowData["suspectIntervalFlag"].toString();
- return <div >{suspectIntervalFlag} </div>
- }
+ property: "suspectIntervalFlag", title: "Suspect Interval", type: ColumnType.boolean
}
];
@@ -79,9 +85,9 @@ class TemperatureComponent extends React.Component<TemperatureComponentProps>{
return (
<>
- <ToggleContainer selectedValue={this.props.currentView} onChange={this.onChange}>
+ <ToggleContainer onToggleFilterButton={this.onToggleFilterButton} showFilter={this.props.isFilterVisible} existingFilter={this.props.temperatureProperties.filter} onFilterChanged={this.props.temperatureActions.onFilterChanged} selectedValue={this.props.currentView} onChange={this.onChange}>
{lineChart(chartPagedData)}
- <TemperatureTable idProperty={"_id"} columns={temperatureColumns} {...properties} {...actions} />
+ <TemperatureTable stickyHeader idProperty={"_id"} columns={temperatureColumns} {...properties} {...actions} />
</ToggleContainer>
</>
);
diff --git a/sdnr/wt/odlux/apps/performanceHistoryApp/src/components/toggleContainer.tsx b/sdnr/wt/odlux/apps/performanceHistoryApp/src/components/toggleContainer.tsx
index 97a2006f7..618dddfc8 100644
--- a/sdnr/wt/odlux/apps/performanceHistoryApp/src/components/toggleContainer.tsx
+++ b/sdnr/wt/odlux/apps/performanceHistoryApp/src/components/toggleContainer.tsx
@@ -23,16 +23,34 @@ import BarChartIcon from '@material-ui/icons/BarChart';
import TableChartIcon from '@material-ui/icons/TableChart';
import { makeStyles } from '@material-ui/core';
import Tooltip from '@material-ui/core/Tooltip';
+import ChartFilter from './chartFilter'
+import FilterListIcon from '@material-ui/icons/FilterList';
const styles = makeStyles({
- toggleButton: {
+ toggleButtonContainer: {
+ display: "flex",
alignItems: "center",
justifyContent: "center",
padding: "10px",
+ },
+ subViewGroup: {
+ padding: "10px"
+ },
+ filterGroup: {
+ marginLeft: "10px"
}
});
-type toggleProps = { selectedValue: string, onChange(value: string): void };
+type filterType = {
+ onRefresh: () => void;
+ onHandleRequestSort: (orderBy: string) => void;
+ onToggleFilter: () => void;
+ onFilterChanged: (property: string, filterTerm: string) => void;
+ onHandleChangePage: (page: number) => void;
+ onHandleChangeRowsPerPage: (rowsPerPage: number | null) => void;
+};
+
+type toggleProps = { selectedValue: string, onChange(value: string): void, showFilter: boolean, onToggleFilterButton(): void, onFilterChanged: (property: string, filterTerm: string) => void, existingFilter: any };
const ToggleContainer: React.FunctionComponent<toggleProps> = (props) => {
@@ -44,22 +62,46 @@ const ToggleContainer: React.FunctionComponent<toggleProps> = (props) => {
}
};
+ const handleFilterChange = (event: React.MouseEvent<HTMLElement>, newView: string) => {
+ props.onToggleFilterButton();
+ };
+
const children = React.Children.toArray(props.children);
+ //hide filter if visible + table
+ //put current name into state, let container handle stuff itelf, register for togglestate, get right via set name
+
return (
<>
- <ToggleButtonGroup className={classes.toggleButton} size="medium" value={props.selectedValue} exclusive onChange={handleChange}>
- <ToggleButton aria-label="display-chart" key={1} value="chart">
- <Tooltip title="Chart">
- <BarChartIcon />
- </Tooltip>
- </ToggleButton>
- <ToggleButton aria-label="display-table" key={2} value="table">
- <Tooltip title="Table">
- <TableChartIcon />
- </Tooltip>
- </ToggleButton>
- </ToggleButtonGroup>
+ <div className={classes.toggleButtonContainer} >
+ <ToggleButtonGroup className={classes.subViewGroup} size="medium" value={props.selectedValue} exclusive onChange={handleChange}>
+ <ToggleButton aria-label="display-chart" key={1} value="chart">
+ <Tooltip title="Chart">
+ <BarChartIcon />
+ </Tooltip>
+ </ToggleButton>
+ <ToggleButton aria-label="display-table" key={2} value="table">
+ <Tooltip title="Table">
+ <TableChartIcon />
+ </Tooltip>
+ </ToggleButton>
+ </ToggleButtonGroup>
+
+ <ToggleButtonGroup className={classes.filterGroup} onChange={handleFilterChange} >
+ <ToggleButton aria-label="show-filter" selected={props.showFilter as boolean} disabled={props.selectedValue !== "chart"}>
+ <Tooltip title={props.showFilter ? 'Hide filter' : 'Show available filter'}>
+ <FilterListIcon />
+ </Tooltip>
+ </ToggleButton>
+ </ToggleButtonGroup>
+
+
+ </div>
+ {
+ props.selectedValue === "chart" &&
+ <ChartFilter filters={props.existingFilter} onFilterChanged={props.onFilterChanged} isVisible={props.showFilter} />
+
+ }
{props.selectedValue === "chart" ? children[0] : props.selectedValue === "table" && children[1]}
</>);
diff --git a/sdnr/wt/odlux/apps/performanceHistoryApp/src/components/transmissionPower.tsx b/sdnr/wt/odlux/apps/performanceHistoryApp/src/components/transmissionPower.tsx
index 6fe66d2b5..d89aca052 100644
--- a/sdnr/wt/odlux/apps/performanceHistoryApp/src/components/transmissionPower.tsx
+++ b/sdnr/wt/odlux/apps/performanceHistoryApp/src/components/transmissionPower.tsx
@@ -28,17 +28,22 @@ import { IDataSet, IDataSetsObject } from '../models/chartTypes';
import { createTransmissionPowerProperties, createTransmissionPowerActions } from '../handlers/transmissionPowerHandler';
import { lineChart, sortDataByTimeStamp } from '../utils/chartUtils';
import { addColumnLabels } from '../utils/tableUtils';
-import { SetSubViewAction } from '../actions/toggleActions';
+import { SetSubViewAction, SetFilterVisibility } from '../actions/toggleActions';
import ToggleContainer from './toggleContainer';
const mapProps = (state: IApplicationStoreState) => ({
transmissionPowerProperties: createTransmissionPowerProperties(state),
- currentView: state.performanceHistory.subViews.transmissionPower,
+ currentView: state.performanceHistory.subViews.transmissionPower.subView,
+ isFilterVisible: state.performanceHistory.subViews.transmissionPower.isFilterVisible,
+ existingFilter: state.performanceHistory.transmissionPower.filter
});
const mapDisp = (dispatcher: IDispatcher) => ({
transmissionPowerActions: createTransmissionPowerActions(dispatcher.dispatch),
setSubView: (value: "chart" | "table") => dispatcher.dispatch(new SetSubViewAction("transmissionPower", value)),
+ toggleFilterButton: (value: boolean) => { dispatcher.dispatch(new SetFilterVisibility("transmissionPower", value)) },
+
+
});
type TransmissionPowerComponentProps = RouteComponentProps & Connect<typeof mapProps, typeof mapDisp> & {
@@ -52,6 +57,10 @@ const TransmissionPowerTable = MaterialTable as MaterialTableCtorType<Transmissi
*/
class TransmissionPowerComponent extends React.Component<TransmissionPowerComponentProps>{
+ onToggleFilterButton = () => {
+ this.props.toggleFilterButton(!this.props.isFilterVisible);
+ }
+
onChange = (value: "chart" | "table") => {
this.props.setSubView(value);
}
@@ -67,10 +76,7 @@ class TransmissionPowerComponent extends React.Component<TransmissionPowerCompon
{ property: "scannerId", title: "Scanner ID", type: ColumnType.text },
{ property: "timeStamp", title: "End Time", type: ColumnType.text },
{
- property: "suspectIntervalFlag", title: "Suspect Interval", customControl: ({ rowData }) => {
- const suspectIntervalFlag = rowData["suspectIntervalFlag"].toString();
- return <div >{suspectIntervalFlag} </div>
- }
+ property: "suspectIntervalFlag", title: "Suspect Interval", type: ColumnType.boolean
}
];
@@ -80,9 +86,9 @@ class TransmissionPowerComponent extends React.Component<TransmissionPowerCompon
return (
<>
- <ToggleContainer selectedValue={this.props.currentView} onChange={this.onChange}>
+ <ToggleContainer onChange={this.onChange} onToggleFilterButton={this.onToggleFilterButton} showFilter={this.props.isFilterVisible} existingFilter={this.props.transmissionPowerProperties.filter} onFilterChanged={this.props.transmissionPowerActions.onFilterChanged} selectedValue={this.props.currentView} >
{lineChart(chartPagedData)}
- <TransmissionPowerTable idProperty={"_id"} columns={transmissionColumns} {...properties} {...actions} />
+ <TransmissionPowerTable stickyHeader idProperty={"_id"} columns={transmissionColumns} {...properties} {...actions} />
</ToggleContainer>
</>
);
diff --git a/sdnr/wt/odlux/apps/performanceHistoryApp/src/handlers/availableLtpsActionHandler.ts b/sdnr/wt/odlux/apps/performanceHistoryApp/src/handlers/availableLtpsActionHandler.ts
index fd137fe37..4605efdb0 100644
--- a/sdnr/wt/odlux/apps/performanceHistoryApp/src/handlers/availableLtpsActionHandler.ts
+++ b/sdnr/wt/odlux/apps/performanceHistoryApp/src/handlers/availableLtpsActionHandler.ts
@@ -21,6 +21,8 @@ import {
AllAvailableLtpsLoadedAction,
LoadAllAvailableLtpsAction,
SetInitialLoadedAction,
+ NoLtpsFoundAction,
+ ResetLtpsAction,
} from '../actions/ltpAction';
import { LtpIds } from '../models/availableLtps';
@@ -29,12 +31,14 @@ export interface IAvailableLtpsState {
distinctLtps: LtpIds[];
busy: boolean;
loadedOnce: boolean;
+ error: string | undefined;
}
const ltpListStateInit: IAvailableLtpsState = {
distinctLtps: [],
busy: false,
- loadedOnce: false
+ loadedOnce: false,
+ error: undefined
};
export const availableLtpsActionHandler: IActionHandler<IAvailableLtpsState> = (state = ltpListStateInit, action) => {
@@ -51,8 +55,16 @@ export const availableLtpsActionHandler: IActionHandler<IAvailableLtpsState> = (
...state,
distinctLtps: action.availableLtps,
busy: false,
+ error: undefined,
loadedOnce: true
};
+ } else if (action.error) {
+ state = {
+ ...state,
+ busy: false,
+ loadedOnce: true,
+ error: action.error
+ }
}
} else if (action instanceof SetInitialLoadedAction) {
@@ -60,7 +72,25 @@ export const availableLtpsActionHandler: IActionHandler<IAvailableLtpsState> = (
...state,
loadedOnce: action.initialLoaded
};
- } else {
+ } else if (action instanceof NoLtpsFoundAction) {
+ state = {
+ ...state,
+ busy: false,
+ error: undefined,
+ loadedOnce: true,
+ distinctLtps: []
+ }
+ } else if (action instanceof ResetLtpsAction) {
+ state = {
+ ...state,
+ busy: false,
+ error: undefined,
+ loadedOnce: false,
+ distinctLtps: []
+ }
+ }
+
+ else {
state = {
...state,
busy: false
diff --git a/sdnr/wt/odlux/apps/performanceHistoryApp/src/handlers/performanceHistoryRootHandler.ts b/sdnr/wt/odlux/apps/performanceHistoryApp/src/handlers/performanceHistoryRootHandler.ts
index e57f3860c..6b9081502 100644
--- a/sdnr/wt/odlux/apps/performanceHistoryApp/src/handlers/performanceHistoryRootHandler.ts
+++ b/sdnr/wt/odlux/apps/performanceHistoryApp/src/handlers/performanceHistoryRootHandler.ts
@@ -37,8 +37,8 @@ import { IAvailableLtpsState, availableLtpsActionHandler } from './availableLtps
import { PmDataInterval } from '../models/performanceDataType';
import { TimeChangeAction } from '../actions/timeChangeAction';
import { UpdateMountId } from '../actions/deviceListActions';
-import { SetSubViewAction, ResetAllSubViewsAction } from '../actions/toggleActions';
-import { SubTabType } from '../models/toggleDataType';
+import { SetSubViewAction, ResetAllSubViewsAction, SetFilterVisibility } from '../actions/toggleActions';
+import { SubTabType, currentViewType } from '../models/toggleDataType';
export interface IPerformanceHistoryStoreState {
nodeId: string;
@@ -81,24 +81,46 @@ const currentPMDataIntervalHandler: IActionHandler<PmDataInterval> = (state = Pm
return state;
}
+type filterableSubview = { subView: SubTabType, isFilterVisible: boolean };
+type toggleViewDataType = { currentSubView: currentViewType, performanceData: filterableSubview, receiveLevel: filterableSubview, transmissionPower: filterableSubview, adaptiveModulation: filterableSubview, temperatur: filterableSubview, SINR: filterableSubview, CPD: filterableSubview };
-type toggleViewDataType = { performanceDataSelection: SubTabType, receiveLevelDataSelection: SubTabType, transmissionPower: SubTabType, adaptiveModulation: SubTabType, temperatur: SubTabType, SINR: SubTabType, CPD: SubTabType };
-
-const toogleViewDataHandler: IActionHandler<toggleViewDataType> = (state = { performanceDataSelection: "chart", receiveLevelDataSelection: "chart", adaptiveModulation: "chart", transmissionPower: "chart", temperatur: "chart", SINR: "chart", CPD: "chart" }, action) => {
+const toogleViewDataHandler: IActionHandler<toggleViewDataType> = (state = { currentSubView: "performanceData", performanceData: { subView: "chart", isFilterVisible: true }, receiveLevel: { subView: "chart", isFilterVisible: true }, adaptiveModulation: { subView: "chart", isFilterVisible: true }, transmissionPower: { subView: "chart", isFilterVisible: true }, temperatur: { subView: "chart", isFilterVisible: true }, SINR: { subView: "chart", isFilterVisible: true }, CPD: { subView: "chart", isFilterVisible: true } }, action) => {
if (action instanceof SetSubViewAction) {
switch (action.currentView) {
- case "performanceData": state = { ...state, performanceDataSelection: action.selectedTab }; break;
- case "adaptiveModulation": state = { ...state, adaptiveModulation: action.selectedTab }; break;
- case "receiveLevel": state = { ...state, receiveLevelDataSelection: action.selectedTab }; break;
- case "transmissionPower": state = { ...state, transmissionPower: action.selectedTab }; break;
- case "Temp": state = { ...state, temperatur: action.selectedTab }; break;
- case "SINR": state = { ...state, SINR: action.selectedTab }; break;
- case "CPD": state = { ...state, CPD: action.selectedTab }; break;
+ case "performanceData": state = { ...state, performanceData: { ...state.performanceData, subView: action.selectedTab } }; break;
+ case "adaptiveModulation": state = { ...state, adaptiveModulation: { ...state.adaptiveModulation, subView: action.selectedTab } }; break;
+ case "receiveLevel": state = { ...state, receiveLevel: { ...state.receiveLevel, subView: action.selectedTab } }; break;
+ case "transmissionPower": state = { ...state, transmissionPower: { ...state.transmissionPower, subView: action.selectedTab } }; break;
+ case "Temp": state = { ...state, temperatur: { ...state.temperatur, subView: action.selectedTab } }; break;
+ case "SINR": state = { ...state, SINR: { ...state.SINR, subView: action.selectedTab } }; break;
+ case "CPD": state = { ...state, CPD: { ...state.CPD, subView: action.selectedTab } }; break;
+ }
+ }
+ else if (action instanceof SetFilterVisibility) {
+ switch (action.currentView) {
+ case "performanceData": state = {
+ ...state, performanceData: { ...state.performanceData, isFilterVisible: action.isVisible }
+ }; break;
+ case "adaptiveModulation": state = { ...state, adaptiveModulation: { ...state.performanceData, isFilterVisible: action.isVisible } }; break;
+ case "receiveLevel": state = { ...state, receiveLevel: { ...state.receiveLevel, isFilterVisible: action.isVisible } }; break;
+ case "transmissionPower": state = { ...state, transmissionPower: { ...state.transmissionPower, isFilterVisible: action.isVisible } }; break;
+ case "Temp": state = { ...state, temperatur: { ...state.temperatur, isFilterVisible: action.isVisible } }; break;
+ case "SINR": state = { ...state, SINR: { ...state.SINR, isFilterVisible: action.isVisible } }; break;
+ case "CPD": state = { ...state, CPD: { ...state.CPD, isFilterVisible: action.isVisible } }; break;
}
+
} else if (action instanceof ResetAllSubViewsAction) {
- state = { performanceDataSelection: "chart", adaptiveModulation: "chart", receiveLevelDataSelection: "chart", transmissionPower: "chart", temperatur: "chart", SINR: "chart", CPD: "chart" }
+ state = {
+ ...state, performanceData: { ...state.performanceData, subView: "chart" },
+ adaptiveModulation: { ...state.adaptiveModulation, subView: "chart" },
+ receiveLevel: { ...state.receiveLevel, subView: "chart" },
+ transmissionPower: { ...state.transmissionPower, subView: "chart" },
+ temperatur: { ...state.temperatur, subView: "chart" },
+ SINR: { ...state.SINR, subView: "chart" },
+ CPD: { ...state.CPD, subView: "chart" }
+ }
}
return state;
diff --git a/sdnr/wt/odlux/apps/performanceHistoryApp/src/services/performanceHistoryService.ts b/sdnr/wt/odlux/apps/performanceHistoryApp/src/services/performanceHistoryService.ts
index 2b03d1c2e..685859850 100644
--- a/sdnr/wt/odlux/apps/performanceHistoryApp/src/services/performanceHistoryService.ts
+++ b/sdnr/wt/odlux/apps/performanceHistoryApp/src/services/performanceHistoryService.ts
@@ -53,7 +53,7 @@ class PerformanceService {
}
const result = await requestRest<Result<string>>(path, { method: "POST", body: JSON.stringify(convertPropertyNames({ input: query }, replaceUpperCase)) });
- return result && result.output && result.output.data.map(ne => ({ key: ne })) || null;
+ return result && result.output && result.output.data && result.output.data.map(ne => ({ key: ne })) || null;
}
diff --git a/sdnr/wt/odlux/apps/performanceHistoryApp/src/views/performanceHistoryApplication.tsx b/sdnr/wt/odlux/apps/performanceHistoryApp/src/views/performanceHistoryApplication.tsx
index 4984e80c3..4a1c654fb 100644
--- a/sdnr/wt/odlux/apps/performanceHistoryApp/src/views/performanceHistoryApplication.tsx
+++ b/sdnr/wt/odlux/apps/performanceHistoryApp/src/views/performanceHistoryApplication.tsx
@@ -39,7 +39,7 @@ import SignalToInterference from '../components/signalToInterference';
import CrossPolarDiscrimination from '../components/crossPolarDiscrimination';
import { loadAllDeviceListAsync } from '../actions/deviceListActions';
import { TimeChangeAction } from '../actions/timeChangeAction';
-import { loadDistinctLtpsbyNetworkElementAsync, SetInitialLoadedAction } from '../actions/ltpAction';
+import { loadDistinctLtpsbyNetworkElementAsync, ResetLtpsAction } from '../actions/ltpAction';
import { SetPanelAction } from '../actions/panelChangeActions';
import { createPerformanceDataPreActions, performanceDataReloadAction, createPerformanceDataActions } from '../handlers/performanceDataHandler';
import { createReceiveLevelPreActions, receiveLevelReloadAction, createReceiveLevelActions } from '../handlers/receiveLevelHandler';
@@ -69,7 +69,8 @@ const mapProps = (state: IApplicationStoreState) => ({
activePanel: state.performanceHistory.currentOpenPanel,
availableLtps: state.performanceHistory.ltps.distinctLtps,
networkElements: state.performanceHistory.networkElements.deviceList,
- initialLoaded: state.performanceHistory.ltps.loadedOnce
+ initialLoaded: state.performanceHistory.ltps.loadedOnce,
+ error: state.performanceHistory.ltps.error
});
const mapDispatcher = (dispatcher: IDispatcher) => ({
@@ -103,7 +104,7 @@ const mapDispatcher = (dispatcher: IDispatcher) => ({
changeNode: (nodeId: string) => dispatcher.dispatch((dispatch: Dispatch) => {
dispatch(new NavigateToApplication("performanceHistory", nodeId));
}),
- setInitialLoaded: (isLoaded: boolean) => dispatcher.dispatch((dispatch: Dispatch) => { dispatch(new SetInitialLoadedAction(isLoaded)); }),
+ resetLtps: () => dispatcher.dispatch((dispatch: Dispatch) => { dispatch(new ResetLtpsAction()); }),
resetSubViews: () => dispatcher.dispatch(new ResetAllSubViewsAction())
});
@@ -138,7 +139,7 @@ class PerformanceHistoryComponent extends React.Component<PerformanceHistoryComp
constructor(props: PerformanceHistoryComponentProps) {
super(props);
this.state = {
- selectedNetworkElement: "-1",
+ selectedNetworkElement: props.nodeId !== "" ? props.nodeId : "-1",
selectedTimePeriod: "15min",
selectedLtp: "-1",
showNetworkElementsTable: true,
@@ -219,7 +220,7 @@ class PerformanceHistoryComponent extends React.Component<PerformanceHistoryComp
if (nodeId === "") {
return (
<>
- <NetworkElementTable title={"Please select the network element!"} idProperty={"nodeId"} rows={this.props.networkElements} asynchronus
+ <NetworkElementTable stickyHeader title={"Please select the network element!"} idProperty={"nodeId"} rows={this.props.networkElements} asynchronus
onHandleClick={(event, rowData) => { this.handleNetworkElementSelect(rowData.nodeId) }} columns={
[{ property: "nodeId", title: "Node Name" }]
} />
@@ -232,7 +233,7 @@ class PerformanceHistoryComponent extends React.Component<PerformanceHistoryComp
<>
{this.state.showLtps &&
- <LtpSelection selectedNE={this.state.selectedNetworkElement} selectedLtp={this.state.selectedLtp} selectedTimePeriod={this.state.selectedTimePeriod}
+ <LtpSelection error={this.props.error} selectedNE={this.state.selectedNetworkElement} selectedLtp={this.state.selectedLtp} selectedTimePeriod={this.state.selectedTimePeriod}
availableLtps={this.props.availableLtps} finishedLoading={this.props.initialLoaded} onChangeTimePeriod={this.handleTimePeriodChange}
onChangeLtp={this.handleLtpChange}
/>
@@ -293,6 +294,9 @@ class PerformanceHistoryComponent extends React.Component<PerformanceHistoryComp
public componentDidMount() {
+ this.props.resetSubViews();
+ this.props.resetLtps();
+ this.props.setCurrentPanel(null);
this.props.getAllDevicesPMdata();
this.props.enableFilterPerformanceData.onToggleFilter();
this.props.enableFilterReceiveLevel.onToggleFilter();
@@ -301,8 +305,6 @@ class PerformanceHistoryComponent extends React.Component<PerformanceHistoryComp
this.props.enableFilterAdaptiveModulation.onToggleFilter();
this.props.enableFilterSinr.onToggleFilter();
this.props.enableFilterCpd.onToggleFilter();
- this.props.setInitialLoaded(false);
- this.props.resetSubViews();
}
/**
@@ -377,8 +379,8 @@ class PerformanceHistoryComponent extends React.Component<PerformanceHistoryComp
selectedLtp: "-1"
});
- this.props.setInitialLoaded(false);
this.props.resetSubViews();
+ this.props.resetLtps();
this.setState({ preFilter: {} });
this.props.changeNode(selectedNetworkElement);
this.props.getDistinctLtpsIds(selectedNetworkElement, this.state.selectedTimePeriod, "-1", this.selectFirstLtp);
@@ -440,7 +442,6 @@ class PerformanceHistoryComponent extends React.Component<PerformanceHistoryComp
showPanels: false,
selectedLtp: event.target.value
});
- this.props.setCurrentPanel(null);
} else if (event.target.value !== this.state.selectedLtp) {
this.setState({
diff --git a/sdnr/wt/odlux/framework/pom.xml b/sdnr/wt/odlux/framework/pom.xml
index 15f71f20a..8c589ed20 100644
--- a/sdnr/wt/odlux/framework/pom.xml
+++ b/sdnr/wt/odlux/framework/pom.xml
@@ -46,7 +46,7 @@
<properties>
<buildtime>${maven.build.timestamp}</buildtime>
<distversion>ONAP Frankfurt (Neon, mdsal ${odl.mdsal.version})</distversion>
- <buildno>41.0f8da02(20/02/20)</buildno>
+ <buildno>46.9d666e7(20/02/28)</buildno>
<odlux.version>ONAP SDN-R | ONF Wireless for ${distversion} - Build: ${buildtime} ${buildno} ${project.version}</odlux.version>
</properties>
diff --git a/sdnr/wt/odlux/framework/src/components/material-table/index.tsx b/sdnr/wt/odlux/framework/src/components/material-table/index.tsx
index b85319b40..a80a5a58d 100644
--- a/sdnr/wt/odlux/framework/src/components/material-table/index.tsx
+++ b/sdnr/wt/odlux/framework/src/components/material-table/index.tsx
@@ -105,6 +105,7 @@ export type MaterialTableComponentState<TData = {}> = {
export type TableApi = { forceRefresh?: () => Promise<void> };
type MaterialTableComponentBaseProps<TData> = WithStyles<typeof styles> & {
+ className?: string;
columns: ColumnModel<TData>[];
idProperty: keyof TData | ((data: TData) => React.Key);
tableId?: string;
@@ -187,7 +188,7 @@ class MaterialTableComponent<TData extends {} = {}> extends React.Component<Mate
const getId = typeof this.props.idProperty !== "function" ? (data: TData) => ((data as { [key: string]: any })[this.props.idProperty as any as string] as string | number) : this.props.idProperty;
const toggleFilter = isMaterialTableComponentPropsWithRowsAndRequestData(this.props) ? this.props.onToggleFilter : () => { !this.props.disableFilter && this.setState({ showFilter: !showFilter }, this.update) }
return (
- <Paper className={classes.root}>
+ <Paper className={this.props.className ? `${classes.root} ${this.props.className}` : classes.root}>
<TableContainer className={classes.container}>
<TableToolbar tableId={this.props.tableId} numSelected={selected && selected.length} title={this.props.title} customActionButtons={this.props.customActionButtons} onExportToCsv={this.exportToCsv}
onToggleFilter={toggleFilter} />
diff --git a/sdnr/wt/odlux/framework/src/components/material-table/tableFilter.tsx b/sdnr/wt/odlux/framework/src/components/material-table/tableFilter.tsx
index 8ea0a93f4..464350a62 100644
--- a/sdnr/wt/odlux/framework/src/components/material-table/tableFilter.tsx
+++ b/sdnr/wt/odlux/framework/src/components/material-table/tableFilter.tsx
@@ -61,7 +61,7 @@ class EnhancedTableFilterComponent extends React.Component<IEnhancedTableFilterC
</TableCell>
: null
}
- {columns.map(col => {
+ {columns.map((col, ind) => {
const style = col.width ? { width: col.width } : {};
return (
<TableCell
@@ -73,14 +73,14 @@ class EnhancedTableFilterComponent extends React.Component<IEnhancedTableFilterC
{col.disableFilter || (col.type === ColumnType.custom)
? null
: (col.type === ColumnType.boolean)
- ? <Select className={classes.input} aria-label={(col.title as string).toLowerCase() + ' filter'} value={filter[col.property] !== undefined ? filter[col.property] : ''} onChange={this.createFilterHandler(col.property)} inputProps={{ name: `${col.property}-bool`, id: `${col.property}-bool` }} >
+ ? <Select className={classes.input} aria-label={col.title ? (col.title as string).toLowerCase() + ' filter' : `${ind + 1}-filter`} value={filter[col.property] !== undefined ? filter[col.property] : ''} onChange={this.createFilterHandler(col.property)} inputProps={{ name: `${col.property}-bool`, id: `${col.property}-bool` }} >
<MenuItem value={undefined} >
<em>None</em>
</MenuItem>
<MenuItem value={true as any as string}>{col.labels ? col.labels["true"] : "true"}</MenuItem>
<MenuItem value={false as any as string}>{col.labels ? col.labels["false"] : "false"}</MenuItem>
</Select>
- : <Input className={classes.input} inputProps={{ 'aria-label': (col.title as string).toLowerCase() + ' filter' }} value={filter[col.property] || ''} onChange={this.createFilterHandler(col.property)} />}
+ : <Input className={classes.input} inputProps={{ 'aria-label': col.title ? (col.title as string).toLowerCase() + ' filter' : `${ind + 1}-filter` }} value={filter[col.property] || ''} onChange={this.createFilterHandler(col.property)} />}
</TableCell>
);
}, this)}
diff --git a/sdnr/wt/odlux/framework/src/components/material-ui/index.ts b/sdnr/wt/odlux/framework/src/components/material-ui/index.ts
index e0e3fc943..096e4439d 100644
--- a/sdnr/wt/odlux/framework/src/components/material-ui/index.ts
+++ b/sdnr/wt/odlux/framework/src/components/material-ui/index.ts
@@ -18,5 +18,5 @@
export { ListItemLink } from './listItemLink';
export { Panel } from './panel';
export { ToggleButton, ToggleButtonClassKey } from './toggleButton';
-export { TreeView, ITreeItem, TreeViewCtorType} from './treeView';
+export { TreeView, TreeItem, TreeViewCtorType} from './treeView';
export { Loader } from './loader';
diff --git a/sdnr/wt/odlux/framework/src/components/material-ui/treeView.tsx b/sdnr/wt/odlux/framework/src/components/material-ui/treeView.tsx
index e4eb3a794..98ee291d1 100644
--- a/sdnr/wt/odlux/framework/src/components/material-ui/treeView.tsx
+++ b/sdnr/wt/odlux/framework/src/components/material-ui/treeView.tsx
@@ -16,33 +16,49 @@
* ============LICENSE_END==========================================================================
*/
import * as React from 'react';
+import { withStyles, WithStyles, createStyles, Theme } from '@material-ui/core/styles';
-import { SvgIconProps } from '@material-ui/core/SvgIcon';
import { List, ListItem, TextField, ListItemText, ListItemIcon, WithTheme, withTheme, Omit } from '@material-ui/core';
+import { SvgIconProps } from '@material-ui/core/SvgIcon';
import FileIcon from '@material-ui/icons/InsertDriveFile';
import CloseIcon from '@material-ui/icons/ExpandLess';
import OpenIcon from '@material-ui/icons/ExpandMore';
import FolderIcon from '@material-ui/icons/Folder';
-export interface ITreeItem {
+const styles = (theme: Theme) => createStyles({
+ root: {
+ padding: 0,
+ paddingBottom: 8,
+ paddingTop: 8,
+ },
+ search: {
+ padding: `0px ${theme.spacing(1)}px`
+ }
+});
+
+export type TreeItem<TData = { }> = {
disabled?: boolean;
icon?: React.ComponentType<SvgIconProps>;
+ iconClass?: string;
+ content: string;
+ contentClass?: string;
+ children?: TreeItem<TData>[];
+ value?: TData;
}
-type TreeViewComponentState<TData extends ITreeItem = ITreeItem> = {
+type TreeViewComponentState<TData = { }> = {
/** All indices of all expanded Items */
- expandedItems: TData[];
+ expandedItems: TreeItem<TData>[];
/** The index of the active iten or undefined if no item is active. */
- activeItem: undefined | TData;
+ activeItem: undefined | TreeItem<TData>;
/** The search term or undefined if search is corrently not active. */
searchTerm: undefined | string;
}
-type TreeViewComponentBaseProps<TData extends ITreeItem = ITreeItem> = WithTheme & {
- items: TData[];
- contentProperty: keyof Omit<TData, keyof ITreeItem>;
- childrenProperty: keyof Omit<TData, keyof ITreeItem>;
+type TreeViewComponentBaseProps<TData = {}> = WithTheme & WithStyles<typeof styles> & {
+ className?: string;
+ items: TreeItem<TData>[];
useFolderIcons?: boolean;
enableSearchBar?: boolean;
autoExpandFolder?: boolean;
@@ -51,23 +67,23 @@ type TreeViewComponentBaseProps<TData extends ITreeItem = ITreeItem> = WithTheme
depthOffset?: number;
}
-type TreeViewComponentWithInternalStateProps<TData extends ITreeItem = ITreeItem> = TreeViewComponentBaseProps<TData> & {
- onItemClick?: (item: TData) => void;
- onFolderClick?: (item: TData) => void;
+type TreeViewComponentWithInternalStateProps<TData = { }> = TreeViewComponentBaseProps<TData> & {
+ onItemClick?: (item: TreeItem<TData>) => void;
+ onFolderClick?: (item: TreeItem<TData>) => void;
}
-type TreeViewComponentWithExternalStateProps<TData extends ITreeItem = ITreeItem> = TreeViewComponentBaseProps<TData> & TreeViewComponentState<TData> & {
+type TreeViewComponentWithExternalStateProps<TData = { }> = TreeViewComponentBaseProps<TData> & TreeViewComponentState<TData> & {
onSearch: (searchTerm: string) => void;
- onItemClick: (item: TData) => void;
- onFolderClick: (item: TData) => void;
+ onItemClick: (item: TreeItem<TData>) => void;
+ onFolderClick: (item: TreeItem<TData>) => void;
}
-type TreeViewComponentProps<TData extends ITreeItem = ITreeItem> =
- TreeViewComponentWithInternalStateProps<TData> |
- TreeViewComponentWithExternalStateProps<TData>;
+type TreeViewComponentProps<TData = { }> =
+ | TreeViewComponentWithInternalStateProps<TData>
+ | TreeViewComponentWithExternalStateProps<TData>;
-function isTreeViewComponentWithExternalStateProps<TData extends ITreeItem = ITreeItem>(props: TreeViewComponentProps<TData>): props is TreeViewComponentWithExternalStateProps<TData> {
- const propsWithExternalState = (props as TreeViewComponentWithExternalStateProps<TData>)
+function isTreeViewComponentWithExternalStateProps(props: TreeViewComponentProps): props is TreeViewComponentWithExternalStateProps {
+ const propsWithExternalState = (props as TreeViewComponentWithExternalStateProps)
return (
propsWithExternalState.onSearch instanceof Function ||
propsWithExternalState.expandedItems !== undefined ||
@@ -76,7 +92,7 @@ function isTreeViewComponentWithExternalStateProps<TData extends ITreeItem = ITr
);
}
-class TreeViewComponent<TData extends ITreeItem> extends React.Component<TreeViewComponentProps<TData>, TreeViewComponentState> {
+class TreeViewComponent<TData = { }> extends React.Component<TreeViewComponentProps<TData>, TreeViewComponentState<TData>> {
/**
* Initializes a new instance.
@@ -95,21 +111,11 @@ class TreeViewComponent<TData extends ITreeItem> extends React.Component<TreeVie
this.itemIndex = 0;
const { searchTerm } = this.state;
const { children, items, enableSearchBar } = this.props;
- const styles = {
- root: {
- padding: 0,
- paddingBottom: 8,
- paddingTop: children ? 0 : 8,
- ...this.props.style
- },
- search: {
- padding: `0px ${this.props.theme.spacing(1)}px`
- }
- };
+
return (
- <div style={styles.root}>
+ <div className={this.props.className ? `${this.props.classes.root} ${this.props.className}` : this.props.classes.root} style={this.props.style}>
{children}
- {enableSearchBar && <TextField label={"Search"} fullWidth={true} style={styles.search} value={searchTerm} onChange={this.onChangeSearchText} /> || null}
+ {enableSearchBar && <TextField label={"Search"} fullWidth={true} className={ this.props.classes.search } value={searchTerm} onChange={this.onChangeSearchText} /> || null}
<List>
{this.renderItems(items, searchTerm && searchTerm.toLowerCase())}
</List>
@@ -118,30 +124,30 @@ class TreeViewComponent<TData extends ITreeItem> extends React.Component<TreeVie
}
private itemIndex: number = 0;
- private renderItems = (items: TData[], searchTerm: string | undefined, depth: number = 1) => {
+ private renderItems = (items: TreeItem<TData>[], searchTerm: string | undefined, depth: number = 1) => {
return items.reduce((acc, item) => {
- const children = this.props.childrenProperty && ((item as any)[this.props.childrenProperty] as TData[]);
+ const children = item.children; // this.props.childrenProperty && ((item as any)[this.props.childrenProperty] as TData[]);
const childrenJsx = children && this.renderItems(children, searchTerm, depth + 1);
const expanded = searchTerm
- ? children && childrenJsx.length > 0
+ ? childrenJsx && childrenJsx.length > 0
: !children
? false
: this.state.expandedItems.indexOf(item) > -1;
const isFolder = children !== undefined;
- const itemJsx = this.renderItem(item, searchTerm, depth, isFolder, expanded);
+ const itemJsx = this.renderItem(item, searchTerm, depth, isFolder, expanded || false);
itemJsx && acc.push(itemJsx);
- if (isFolder && expanded) {
+ if (isFolder && expanded && childrenJsx) {
acc.push(...childrenJsx);
}
return acc;
}, [] as JSX.Element[]);
}
- private renderItem = (item: TData, searchTerm: string | undefined, depth: number, isFolder: boolean, expanded: boolean): JSX.Element | null => {
+ private renderItem = (item: TreeItem<TData>, searchTerm: string | undefined, depth: number, isFolder: boolean, expanded: boolean): JSX.Element | null => {
const styles = {
item: {
paddingLeft: (((this.props.depthOffset || 0) + depth) * this.props.theme.spacing(3)),
@@ -154,7 +160,7 @@ class TreeViewComponent<TData extends ITreeItem> extends React.Component<TreeVie
}
};
- const text = (item as any)[this.props.contentProperty] as string || ''; // need to keep track of search
+ const text = item.content || ''; // need to keep track of search
const matchIndex = searchTerm ? text.toLowerCase().indexOf(searchTerm) : -1;
const searchTermLength = searchTerm && searchTerm.length || 0;
@@ -175,7 +181,7 @@ class TreeViewComponent<TData extends ITreeItem> extends React.Component<TreeVie
{ // display the left icon
(this.props.useFolderIcons && <ListItemIcon>{isFolder ? <FolderIcon /> : <FileIcon />}</ListItemIcon>) ||
- (item.icon && (<ListItemIcon><item.icon /></ListItemIcon>))}
+ (item.icon && (<ListItemIcon className={ item.iconClass }><item.icon /></ListItemIcon>))}
{ // highlight search result
@@ -193,10 +199,10 @@ class TreeViewComponent<TData extends ITreeItem> extends React.Component<TreeVie
</span>
{text.substring(matchIndex + searchTermLength)}
</span>)
- : (<ListItemText primary={text} />)
+ : (<ListItemText className={ item.contentClass } primary={text} />)
}
- { // display the right icon, depending on the state
+ { // display the right icon, depending on the state
!isFolder ? null : expanded ? (<OpenIcon onClick={handleClickCreator(true)} />) : (<CloseIcon onClick={handleClickCreator(true)} />)}
</ListItem>
)
@@ -204,7 +210,7 @@ class TreeViewComponent<TData extends ITreeItem> extends React.Component<TreeVie
);
}
- private onFolderClick = (item: TData) => {
+ private onFolderClick = (item: TreeItem<TData>) => {
// toggle items with children
if (this.state.searchTerm) return;
const indexOfItemToToggle = this.state.expandedItems.indexOf(item);
@@ -222,7 +228,7 @@ class TreeViewComponent<TData extends ITreeItem> extends React.Component<TreeVie
}
};
- private onItemClick = (item: TData) => {
+ private onItemClick = (item: TreeItem<TData>) => {
// activate items without children
this.setState({
activeItem: item,
@@ -262,7 +268,7 @@ class TreeViewComponent<TData extends ITreeItem> extends React.Component<TreeVie
}
}
-export type TreeViewCtorType<TData extends ITreeItem = ITreeItem> = new () => React.Component<Omit<TreeViewComponentProps<TData>, 'theme'>>;
+export type TreeViewCtorType<TData = { }> = new () => React.Component<Omit<TreeViewComponentProps<TData>, 'theme'|'classes'>>;
-export const TreeView = withTheme(TreeViewComponent);
+export const TreeView = withTheme(withStyles(styles)(TreeViewComponent));
export default TreeView; \ No newline at end of file
diff --git a/sdnr/wt/odlux/framework/src/components/navigationMenu.tsx b/sdnr/wt/odlux/framework/src/components/navigationMenu.tsx
index fee51621e..233c2fd61 100644
--- a/sdnr/wt/odlux/framework/src/components/navigationMenu.tsx
+++ b/sdnr/wt/odlux/framework/src/components/navigationMenu.tsx
@@ -133,6 +133,13 @@ export const NavigationMenu = withStyles(styles)(connect()(({ classes, state, di
}
<Divider />
<ListItemLink to="/about" primary="About" icon={<FontAwesomeIcon icon={faAddressBook} />} />
+ {(false && process.env.NODE_ENV === "development")
+ ? <>
+ <Divider />
+ <ListItemLink to="/test" primary="Test" icon={<FontAwesomeIcon icon={faHome} />} />
+ </>
+ : null
+ }
</List>
</> || null
}
diff --git a/sdnr/wt/odlux/framework/src/views/test.tsx b/sdnr/wt/odlux/framework/src/views/test.tsx
index 68b189340..763b79a1f 100644
--- a/sdnr/wt/odlux/framework/src/views/test.tsx
+++ b/sdnr/wt/odlux/framework/src/views/test.tsx
@@ -27,7 +27,7 @@ import Typography from '@material-ui/core/Typography';
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import { MaterialTable, MaterialTableCtorType, ColumnType } from '../components/material-table';
-import { TreeView, ITreeItem, TreeViewCtorType } from '../components/material-ui/treeView';
+import { TreeView, TreeItem, TreeViewCtorType } from '../components/material-ui/treeView';
import { SvgIconProps } from '@material-ui/core/SvgIcon';
const styles = (theme: Theme) => createStyles({
@@ -814,30 +814,25 @@ const components = {
'counter': 'demoApp.counter'
};
-class TreeDemoItem implements ITreeItem {
- title: string;
- children?: TreeDemoItem[];
- disabled?: boolean;
- icon?: React.ComponentType<SvgIconProps>;
-}
+type TreeDemoItem = TreeItem<string>;
const treeData: TreeDemoItem[] = [
{
- title: "Erste Ebene", children: [
+ content: "Erste Ebene", children: [
{
- title: "Zweite Ebene", children: [
- { title: "Dritte Ebene" },
+ content: "Zweite Ebene", children: [
+ { content: "Dritte Ebene" },
]
},
- { title: "Zweite Ebene 2" },
+ { content: "Zweite Ebene 2" },
]
},
- { title: "Erste Ebene 3" },
+ { content: "Erste Ebene 3" },
];
const SampleDataMaterialTable = MaterialTable as MaterialTableCtorType<SampleData>;
-const SampleTree = TreeView as any as TreeViewCtorType<TreeDemoItem>;
+const SampleTree = TreeView as any as TreeViewCtorType<string>;
const TestComponent = (props: WithComponents<typeof components> & WithStyles<typeof styles>) => {
@@ -867,11 +862,11 @@ const TestComponent = (props: WithComponents<typeof components> & WithStyles<typ
<Typography className={props.classes.heading}>Tree Demo</Typography>
</ExpansionPanelSummary>
<ExpansionPanelDetails>
- <SampleTree items={treeData} contentProperty={"title"} childrenProperty={"children"} useFolderIcons enableSearchBar />
+ <SampleTree items={treeData} useFolderIcons enableSearchBar />
</ExpansionPanelDetails>
</ExpansionPanel>
</div>
- )
+ );
};
export const Test = withComponents(components)(withStyles(styles)(TestComponent));
diff --git a/sdnr/wt/odlux/package.json b/sdnr/wt/odlux/package.json
index 12d18c14d..0ddc4c378 100644
--- a/sdnr/wt/odlux/package.json
+++ b/sdnr/wt/odlux/package.json
@@ -15,8 +15,8 @@
"@fortawesome/free-solid-svg-icons": "5.6.3",
"@fortawesome/react-fontawesome": "0.1.3",
"@material-ui/core": "4.9.0",
- "@material-ui/icons": "4.5.1",
"@material-ui/lab": "4.0.0-alpha.41",
+ "@material-ui/icons": "4.5.1",
"@types/classnames": "2.2.6",
"@types/flux": "3.1.8",
"@types/jquery": "3.3.10",
@@ -29,10 +29,9 @@
"@types/x2js": "3.1.0",
"classnames": "2.2.6",
"csstype": "2.6.8",
+ "jss": "10.0.3",
"jquery": "3.3.1",
"jsonwebtoken": "8.3.0",
- "jss": "10.0.3",
- "lerna": "3.13.1",
"notistack": "0.9.6",
"prop-types": "15.7.2",
"react": "16.12.0",
@@ -82,4 +81,4 @@
"webpack-cli": "3.2.1",
"webpack-dev-server": "3.1.14"
}
-}
+} \ No newline at end of file