From d93e6a996e60fb6abce9a870cef6b2d57bfa70fd Mon Sep 17 00:00:00 2001 From: Herbert Eiselt Date: Fri, 7 Jun 2019 17:40:50 +0200 Subject: SDNR Add missing status bar to ODLUX Framework Modify framework and adapt all apps Issue-ID: SDNC-789 Signed-off-by: Herbert Eiselt Change-Id: I1ea0a3df6c3f6db08f2bd7a21eb3b4cbf230a08a Signed-off-by: Herbert Eiselt --- .../src/actions/configurationActions.ts | 4 +- .../src/handlers/configurationAppRootHandler.ts | 14 ++++- sdnr/wt/odlux/apps/configurationApp/src/plugin.tsx | 4 +- .../src/services/configurationService.ts | 4 +- .../src/views/configurationApplication.tsx | 14 +++-- .../apps/faultApp/src/actions/statusActions.ts | 26 +++++++++ .../apps/faultApp/src/components/faultStatus.tsx | 54 +++++++++++++++++++ .../faultApp/src/handlers/faultAppRootHandler.ts | 5 +- .../faultApp/src/handlers/faultStatusHandler.ts | 29 ++++++++++ sdnr/wt/odlux/apps/faultApp/src/index.html | 12 +++-- sdnr/wt/odlux/apps/faultApp/src/plugin.tsx | 19 ++++++- .../faultApp/src/services/faultStatusService.ts | 22 ++++++++ sdnr/wt/odlux/apps/faultApp/webpack.config.js | 22 +++++++- .../apps/helpApp/src/components/helpStatus.tsx | 63 ++++++++++++++++++++++ sdnr/wt/odlux/apps/helpApp/src/index.html | 14 +++-- sdnr/wt/odlux/apps/helpApp/src/models/tocNode.ts | 3 +- sdnr/wt/odlux/apps/helpApp/src/plugin.tsx | 2 + .../odlux/apps/helpApp/src/services/helpService.ts | 1 + sdnr/wt/odlux/apps/helpApp/webpack.config.js | 1 - 19 files changed, 286 insertions(+), 27 deletions(-) create mode 100644 sdnr/wt/odlux/apps/faultApp/src/actions/statusActions.ts create mode 100644 sdnr/wt/odlux/apps/faultApp/src/components/faultStatus.tsx create mode 100644 sdnr/wt/odlux/apps/faultApp/src/handlers/faultStatusHandler.ts create mode 100644 sdnr/wt/odlux/apps/faultApp/src/services/faultStatusService.ts create mode 100644 sdnr/wt/odlux/apps/helpApp/src/components/helpStatus.tsx (limited to 'sdnr/wt/odlux/apps') diff --git a/sdnr/wt/odlux/apps/configurationApp/src/actions/configurationActions.ts b/sdnr/wt/odlux/apps/configurationApp/src/actions/configurationActions.ts index 82055a761..b0ffc4c19 100644 --- a/sdnr/wt/odlux/apps/configurationApp/src/actions/configurationActions.ts +++ b/sdnr/wt/odlux/apps/configurationApp/src/actions/configurationActions.ts @@ -96,7 +96,7 @@ export const updateLpIdAsyncActionCreator = (lpId: string | undefined) => async export const updateViewDataAsyncActionCreator = (viewId: string | undefined, indexValues: string[] = []) => async (dispatch: Dispatch, getState: () => IApplicationStoreState) => { const { configuration: { nodeId, lpId, capability, conditionalPackage, viewSpecifications } } = getState(); if (!viewId || !capability || !nodeId || !lpId || !conditionalPackage) { - dispatch(new AddSnackbarNotification({ message: `Error invalid parameter !${JSON.stringify({viewId ,capability ,nodeId ,lpId ,conditionalPackage}, null,2)}`, options: { variant: 'error' } })); + // dispatch(new AddSnackbarNotification({ message: `Error invalid parameter !${JSON.stringify({capability ,nodeId ,lpId ,conditionalPackage}, null,2)}`, options: { variant: 'error' } })); dispatch(new UpdateViewData()); return; } @@ -131,7 +131,7 @@ export const updateViewDataAsyncActionCreator = (viewId: string | undefined, ind viewData = viewData[path]; } - return viewData ? + return viewData != null ? dispatch(new UpdateViewData(viewId, indexValues.length > 0 ? indexValues.join("/") : "", viewData)) : dispatch(new UpdateViewData()); } \ No newline at end of file diff --git a/sdnr/wt/odlux/apps/configurationApp/src/handlers/configurationAppRootHandler.ts b/sdnr/wt/odlux/apps/configurationApp/src/handlers/configurationAppRootHandler.ts index 4b982149a..f82d08a1b 100644 --- a/sdnr/wt/odlux/apps/configurationApp/src/handlers/configurationAppRootHandler.ts +++ b/sdnr/wt/odlux/apps/configurationApp/src/handlers/configurationAppRootHandler.ts @@ -44,7 +44,14 @@ export const configurationAppRootHandler: IActionHandler { const capFile = capability && revision && `${capability}@${revision}.json`; - const coreModelResponse = capFile && await requestRest<{ views: ViewSpecification[] } >(`assets/${capFile}`, { method: "GET" }); - return coreModelResponse && coreModelResponse.views || null; + const coreModelResponse = capFile && await requestRest<{ views: ViewSpecification[] }>(`assets/${capFile}`, { method: "GET" }, false, true); + return coreModelResponse && coreModelResponse.views || null; } } diff --git a/sdnr/wt/odlux/apps/configurationApp/src/views/configurationApplication.tsx b/sdnr/wt/odlux/apps/configurationApp/src/views/configurationApplication.tsx index 5865c10e5..65fbd70a5 100644 --- a/sdnr/wt/odlux/apps/configurationApp/src/views/configurationApplication.tsx +++ b/sdnr/wt/odlux/apps/configurationApp/src/views/configurationApplication.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; -import { MaterialTable, ColumnType, MaterialTableCtorType } from '../../../../framework/src/components/material-table'; +import { MaterialTable, MaterialTableCtorType } from '../../../../framework/src/components/material-table'; import connect, { Connect, IDispatcher } from '../../../../framework/src/flux/connect'; import { IApplicationStoreState } from '../../../../framework/src/store/applicationStore'; import { IConnectAppStoreState } from '../../../connectApp/src/handlers/connectAppRootHandler'; @@ -70,11 +70,12 @@ class ConfigurationApplicationComponent extends React.Component ); } else if (!this.props.lpId) { - return ( + return this.props.coreModel && this.props.coreModel.ltp && this.props.coreModel.ltp.length + ? ( <>

Please select an existing LP first !

    - { this.props.coreModel && this.props.coreModel.ltp.map(ltp => { + { this.props.coreModel.ltp.map(ltp => { return
  • { this.props.changeLp(ltp.lp[0].uuid); @@ -83,6 +84,11 @@ class ConfigurationApplicationComponent extends React.Component + ) + : ( + <> +

    No LTP / LP found !

    + ); } else if (!this.props.capability && !this.props.viewId) { return ( @@ -113,7 +119,7 @@ class ConfigurationApplicationComponent extends React.Component ) - :

    View Not Found

    ; + :

    View [{this.props.viewId || this.props.conditionalPackage}] Not Found ! {this.props.viewSpecifications.length}

    ; } private static keyPropertyParser = /\$\$INDEX:(\d+):?([a-z\-]+)?\$\$$/; diff --git a/sdnr/wt/odlux/apps/faultApp/src/actions/statusActions.ts b/sdnr/wt/odlux/apps/faultApp/src/actions/statusActions.ts new file mode 100644 index 000000000..48f501ba8 --- /dev/null +++ b/sdnr/wt/odlux/apps/faultApp/src/actions/statusActions.ts @@ -0,0 +1,26 @@ +import { FaultApplicationBaseAction } from './notificationActions'; +import { getFaultStateFromDatabase } from '../services/faultStatusService'; +import { Dispatch } from '../../../../framework/src/flux/store'; + + +export class SetFaultStatusAction extends FaultApplicationBaseAction { + constructor (public criticalFaults: number, public majorFaults: number, public minorFaults: number, public warnings: number) { + super(); + } +} + + +export const refreshFaultStatusAsyncAction = async (dispatch: Dispatch ) => { + const result = await getFaultStateFromDatabase().catch(_=>null); + if (result) { + const statusAction = new SetFaultStatusAction( + result["Critical"] || 0, + result["Major"] || 0, + result["Minor"] || 0, + result["Warning"] || 0 + ); + dispatch(statusAction); + return; + } + dispatch(new SetFaultStatusAction(0, 0, 0, 0)); +} diff --git a/sdnr/wt/odlux/apps/faultApp/src/components/faultStatus.tsx b/sdnr/wt/odlux/apps/faultApp/src/components/faultStatus.tsx new file mode 100644 index 000000000..e83720f0b --- /dev/null +++ b/sdnr/wt/odlux/apps/faultApp/src/components/faultStatus.tsx @@ -0,0 +1,54 @@ +import * as React from 'react'; + +import { withStyles, WithStyles, createStyles, Theme } from '@material-ui/core/styles'; +import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons'; // select app icon + +import connect, { Connect } from '../../../../framework/src/flux/connect'; +import { IApplicationStoreState } from '../../../../framework/src/store/applicationStore'; + +import Typography from '@material-ui/core/Typography'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; + +const styles = (theme: Theme) => createStyles({ + icon: { + marginLeft: 8, + marginRight: 8 + }, + critical: { + color: "red" + }, + major: { + color: "orange" + }, + minor: { + color: "#f7f700" + }, + warning: { + color: "#428bca" + } +}); + +const mapProps = (state: IApplicationStoreState) => ({ + faultStatus: state.fault.faultStatus, +}); + + +type FaultStatusComponentProps = & WithStyles & Connect; + +class FaultStatusComponent extends React.Component { + render(): JSX.Element { + const { classes, faultStatus } = this.props; + + return ( + + Alarm status: { faultStatus.critical } | + { faultStatus.major } | + { faultStatus.minor } | + { faultStatus.warning } | + + ); + }; +} + +export const FaultStatus = withStyles(styles)(connect(mapProps)(FaultStatusComponent)); +export default FaultStatus; \ No newline at end of file diff --git a/sdnr/wt/odlux/apps/faultApp/src/handlers/faultAppRootHandler.ts b/sdnr/wt/odlux/apps/faultApp/src/handlers/faultAppRootHandler.ts index a887a3327..e97383e10 100644 --- a/sdnr/wt/odlux/apps/faultApp/src/handlers/faultAppRootHandler.ts +++ b/sdnr/wt/odlux/apps/faultApp/src/handlers/faultAppRootHandler.ts @@ -10,12 +10,14 @@ import { IFaultNotifications, faultNotificationsHandler } from './notificationsH import { ICurrentProblemsState, currentProblemsActionHandler } from './currentProblemsHandler'; import { IAlarmLogEntriesState, alarmLogEntriesActionHandler } from './alarmLogEntriesHandler'; import { SetPanelAction } from '../actions/panelChangeActions'; +import { IFaultStatus, faultStatusHandler } from './faultStatusHandler'; export interface IFaultAppStoreState { currentProblems: ICurrentProblemsState; faultNotifications: IFaultNotifications; alarmLogEntries: IAlarmLogEntriesState; currentOpenPanel: string|null; + faultStatus: IFaultStatus; } const currentOpenPanelHandler: IActionHandler = (state = null, action) => { @@ -35,7 +37,8 @@ const actionHandlers = { currentProblems: currentProblemsActionHandler, faultNotifications: faultNotificationsHandler, alarmLogEntries: alarmLogEntriesActionHandler, - currentOpenPanel: currentOpenPanelHandler + currentOpenPanel: currentOpenPanelHandler, + faultStatus: faultStatusHandler }; export const faultAppRootHandler = combineActionHandler(actionHandlers); diff --git a/sdnr/wt/odlux/apps/faultApp/src/handlers/faultStatusHandler.ts b/sdnr/wt/odlux/apps/faultApp/src/handlers/faultStatusHandler.ts new file mode 100644 index 000000000..0a084df6b --- /dev/null +++ b/sdnr/wt/odlux/apps/faultApp/src/handlers/faultStatusHandler.ts @@ -0,0 +1,29 @@ +import { IActionHandler } from "../../../../framework/src/flux/action"; +import { SetFaultStatusAction } from "../actions/statusActions"; + +export interface IFaultStatus { + critical: number, + major: number, + minor: number, + warning: number +} + +const faultStatusInit: IFaultStatus = { + critical: 0, + major: 0, + minor: 0, + warning: 0 +}; + +export const faultStatusHandler: IActionHandler = (state = faultStatusInit, action) => { + if (action instanceof SetFaultStatusAction) { + state = { + critical: action.criticalFaults, + major: action.majorFaults, + minor: action.minorFaults, + warning: action.warnings + } + } + + return state; +} \ No newline at end of file diff --git a/sdnr/wt/odlux/apps/faultApp/src/index.html b/sdnr/wt/odlux/apps/faultApp/src/index.html index 5f6794f33..a2a0830b3 100644 --- a/sdnr/wt/odlux/apps/faultApp/src/index.html +++ b/sdnr/wt/odlux/apps/faultApp/src/index.html @@ -15,10 +15,14 @@ diff --git a/sdnr/wt/odlux/apps/faultApp/src/plugin.tsx b/sdnr/wt/odlux/apps/faultApp/src/plugin.tsx index c4545ad1a..be1e075fc 100644 --- a/sdnr/wt/odlux/apps/faultApp/src/plugin.tsx +++ b/sdnr/wt/odlux/apps/faultApp/src/plugin.tsx @@ -20,7 +20,9 @@ import { PanelId } from "./models/panelId"; import { SetPanelAction } from "./actions/panelChangeActions"; import { AddFaultNotificationAction } from "./actions/notificationActions"; -import { createCurrentProblemsProperties, createCurrentProblemsActions } from "./handlers/currentProblemsHandler"; +import { createCurrentProblemsProperties, createCurrentProblemsActions, currentProblemsReloadAction } from "./handlers/currentProblemsHandler"; +import { FaultStatus } from "./components/faultStatus"; +import { refreshFaultStatusAsyncAction } from "./actions/statusActions"; let currentMountId: string | undefined = undefined; @@ -65,6 +67,7 @@ export function register() { icon: faBell, rootComponent: App, rootActionHandler: faultAppRootHandler, + statusBarElement: FaultStatus, menuEntry: "Fault" }); @@ -75,4 +78,18 @@ export function register() { store.dispatch(new AddFaultNotificationAction(fault)); } })); + + applicationApi.applicationStoreInitialized.then(store => { + store.dispatch(currentProblemsReloadAction); + }); + + applicationApi.applicationStoreInitialized.then(store => { + store.dispatch(refreshFaultStatusAsyncAction); + }); + window.setInterval(() => { + applicationApi.applicationStoreInitialized.then(store => { + store.dispatch(refreshFaultStatusAsyncAction); + }); + }, 15000); + } diff --git a/sdnr/wt/odlux/apps/faultApp/src/services/faultStatusService.ts b/sdnr/wt/odlux/apps/faultApp/src/services/faultStatusService.ts new file mode 100644 index 000000000..ad0d394ce --- /dev/null +++ b/sdnr/wt/odlux/apps/faultApp/src/services/faultStatusService.ts @@ -0,0 +1,22 @@ +import { requestRest } from "../../../../framework/src/services/restService"; +import { Result } from "../../../../framework/src/models/elasticSearch"; + +export const getFaultStateFromDatabase = async (): Promise < { [key: string]: number } | null > => { + const path = 'database/sdnevents/faultcurrent/_search'; + const query = { + "size": 0, + "aggregations": { + "severity": { + "terms": { + "field": "faultCurrent.severity" + } + } + } + }; + + const result = await requestRest>(path, { method: "POST", body: JSON.stringify(query) }); + return result && result.aggregations && result.aggregations["severity"].buckets.reduce<{ [key: string]: number }>((acc, cur) => { + acc[cur.key] = cur.doc_count; + return acc; + }, {}) || null; +} \ No newline at end of file diff --git a/sdnr/wt/odlux/apps/faultApp/webpack.config.js b/sdnr/wt/odlux/apps/faultApp/webpack.config.js index a0284c5dd..bbf33ea2f 100644 --- a/sdnr/wt/odlux/apps/faultApp/webpack.config.js +++ b/sdnr/wt/odlux/apps/faultApp/webpack.config.js @@ -124,8 +124,26 @@ module.exports = (env) => { colors: true }, proxy: { - "/database": { - target: "http://localhost:8181", + "/oauth2/": { + target: "http://localhost:3000", + secure: false + }, + "/database/": { + target: "http://localhost:3000", + secure: false + }, + "/restconf/": { + target: "http://localhost:3000", + secure: false + }, + "/help/": { + target: "http://localhost:3000", + secure: false + }, + "/websocket/": { + target: "http://localhost:3000", + ws: true, + changeOrigin: true, secure: false } } diff --git a/sdnr/wt/odlux/apps/helpApp/src/components/helpStatus.tsx b/sdnr/wt/odlux/apps/helpApp/src/components/helpStatus.tsx new file mode 100644 index 000000000..813fffd19 --- /dev/null +++ b/sdnr/wt/odlux/apps/helpApp/src/components/helpStatus.tsx @@ -0,0 +1,63 @@ +import * as React from 'react'; + +import { withStyles, WithStyles, createStyles, Theme } from '@material-ui/core/styles'; +import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons'; // select app icon + +import connect, { Connect } from '../../../../framework/src/flux/connect'; +import { IApplicationStoreState } from '../../../../framework/src/store/applicationStore'; + +import Typography from '@material-ui/core/Typography'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faQuestionCircle } from '@fortawesome/free-solid-svg-icons'; +import { withRouter, RouteComponentProps } from 'react-router'; + +const styles = (theme: Theme) => createStyles({ + icon: { + marginLeft: 8, + marginRight: 8 + }, + disabled: { + color: theme.palette.grey[400] + }, + link: { + cursor: "pointer", + '&:hover': { + textDecoration: "underline" + } + } +}); + +const mapProps = (state: IApplicationStoreState) => ({ + appId: state.framework.applicationState.appId, + toc: state.help.toc +}); + + +type HelpStatusComponentProps = & RouteComponentProps & WithStyles & Connect; + +class HelpStatusComponent extends React.Component { + render() { + const { classes, history, toc, appId } = this.props; + const rootNode = toc && toc.find(t => t.id === "sdnr"); + const helpNode = appId + ? rootNode && rootNode.nodes && rootNode.nodes.find(n => n.id === appId || n.id === appId+"App") + : rootNode; + return helpNode + ? ( + { event.stopPropagation(); history.push(`/help/${helpNode.uri}`) }} > + + Help + + ) + : ( + + + Help + + ); + }; + +} + +export const HelpStatus = withRouter(withStyles(styles)(connect(mapProps)(HelpStatusComponent))); +export default HelpStatus; \ No newline at end of file diff --git a/sdnr/wt/odlux/apps/helpApp/src/index.html b/sdnr/wt/odlux/apps/helpApp/src/index.html index 6865db051..e76109fd8 100644 --- a/sdnr/wt/odlux/apps/helpApp/src/index.html +++ b/sdnr/wt/odlux/apps/helpApp/src/index.html @@ -14,11 +14,15 @@ diff --git a/sdnr/wt/odlux/apps/helpApp/src/models/tocNode.ts b/sdnr/wt/odlux/apps/helpApp/src/models/tocNode.ts index ae73ec43d..ddb5e729e 100644 --- a/sdnr/wt/odlux/apps/helpApp/src/models/tocNode.ts +++ b/sdnr/wt/odlux/apps/helpApp/src/models/tocNode.ts @@ -5,7 +5,7 @@ export type VersionInfo = { } export type TocNode = { - label: string; + label: string; versions: { [versionKey: string]: VersionInfo, current: VersionInfo @@ -17,6 +17,7 @@ export type TocNodeCollection = { [tocNodeKey: string]: TocNode }; export type TocTreeNode = { + id: string; label: string; uri: string; nodes?: TocTreeNode[]; diff --git a/sdnr/wt/odlux/apps/helpApp/src/plugin.tsx b/sdnr/wt/odlux/apps/helpApp/src/plugin.tsx index f871ab9d9..94f65b870 100644 --- a/sdnr/wt/odlux/apps/helpApp/src/plugin.tsx +++ b/sdnr/wt/odlux/apps/helpApp/src/plugin.tsx @@ -14,6 +14,7 @@ import { helpAppRootHandler } from './handlers/helpAppRootHandler'; import { HelpApplication } from './views/helpApplication'; import { SubMenuEntry } from "./components/subMenuEntry"; +import { HelpStatus } from "./components/helpStatus"; import '!style-loader!css-loader!highlight.js/styles/default.css'; @@ -58,6 +59,7 @@ export async function register() { icon: faFirstAid, rootComponent: App, rootActionHandler: helpAppRootHandler, + statusBarElement: HelpStatus, menuEntry: "Help", subMenuEntry: SubMenuEntry }); diff --git a/sdnr/wt/odlux/apps/helpApp/src/services/helpService.ts b/sdnr/wt/odlux/apps/helpApp/src/services/helpService.ts index 800e0b47f..aa0b0ed43 100644 --- a/sdnr/wt/odlux/apps/helpApp/src/services/helpService.ts +++ b/sdnr/wt/odlux/apps/helpApp/src/services/helpService.ts @@ -29,6 +29,7 @@ class HelpService { return Object.keys(col).reduce ((acc, key) => { const current = col[key]; acc.push({ + id: key, label: current.label, uri: current.versions.current.path, nodes: current.nodes && mapNodesCollection(current.nodes) || undefined diff --git a/sdnr/wt/odlux/apps/helpApp/webpack.config.js b/sdnr/wt/odlux/apps/helpApp/webpack.config.js index f9448a310..3a56d8bea 100644 --- a/sdnr/wt/odlux/apps/helpApp/webpack.config.js +++ b/sdnr/wt/odlux/apps/helpApp/webpack.config.js @@ -123,7 +123,6 @@ module.exports = (env) => { }]), ] ], - devServer: { public: "http://localhost:3100", contentBase: frameworkPath, -- cgit 1.2.3-korg