diff options
Diffstat (limited to 'sdnr/wt/odlux/apps')
19 files changed, 286 insertions, 27 deletions
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<IConfigurationAppStoreS state = { ...state, nodeId: action.nodeId, - coreModel: action.coreModel + coreModel: action.coreModel, + lpId: undefined, + capability: undefined, + conditionalPackage: undefined, + viewSpecifications: [], + viewData: { }, + indexValues: undefined, + viewId: undefined, }; } else if (action instanceof UpdateLp) { state = { @@ -52,7 +59,10 @@ export const configurationAppRootHandler: IActionHandler<IConfigurationAppStoreS lpId: action.lpId, capability: action.capability, conditionalPackage: action.conditionalPackage, - viewSpecifications: action.viewSpecifications + viewSpecifications: action.viewSpecifications, + viewData: { }, + indexValues: undefined, + viewId: undefined, }; } else if (action instanceof UpdateViewData) { state = { diff --git a/sdnr/wt/odlux/apps/configurationApp/src/plugin.tsx b/sdnr/wt/odlux/apps/configurationApp/src/plugin.tsx index b7d44f70b..d2b18ea21 100644 --- a/sdnr/wt/odlux/apps/configurationApp/src/plugin.tsx +++ b/sdnr/wt/odlux/apps/configurationApp/src/plugin.tsx @@ -51,14 +51,14 @@ const ConfigurationApplicationRouteAdapter = connect(mapProps, mapDisp)((props: currentLpId = props.match.params.lpId || undefined; currentViewId = null; currentIndex = null; - currentLpId && await props.updateLpId(currentLpId); + currentMountId && await props.updateLpId(currentLpId); } // check if the viewId or the indices has changed if (currentViewId !== props.match.params.viewId || currentIndex !== props.match.params[0]) { currentViewId = props.match.params.viewId || undefined; currentIndex = props.match.params[0] || undefined; - currentViewId && await props.updateViewData(currentViewId || '', currentIndex && currentIndex.split("/") || [] ); + currentLpId && await props.updateViewData(currentViewId || '', currentIndex && currentIndex.split("/") || [] ); } }); diff --git a/sdnr/wt/odlux/apps/configurationApp/src/services/configurationService.ts b/sdnr/wt/odlux/apps/configurationApp/src/services/configurationService.ts index 707fed833..0802be59e 100644 --- a/sdnr/wt/odlux/apps/configurationApp/src/services/configurationService.ts +++ b/sdnr/wt/odlux/apps/configurationApp/src/services/configurationService.ts @@ -26,8 +26,8 @@ class ConfigurationService { /** Gets the UI description object for a capability of a network element. */ public async getUIDescriptionByCapability(capability: string, revision: string | null): Promise<ViewSpecification[] | null> { 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<ConfigurationApp </> ); } else if (!this.props.lpId) { - return ( + return this.props.coreModel && this.props.coreModel.ltp && this.props.coreModel.ltp.length + ? ( <> <h2>Please select an existing LP first !</h2> <ul> - { this.props.coreModel && this.props.coreModel.ltp.map(ltp => { + { this.props.coreModel.ltp.map(ltp => { return <li key={ltp.uuid}> <Link component="a" variant="body2" color="secondary" onClick={() => { this.props.changeLp(ltp.lp[0].uuid); @@ -83,6 +84,11 @@ class ConfigurationApplicationComponent extends React.Component<ConfigurationApp }) || null} </ul> </> + ) + : ( + <> + <h2>No LTP / LP found !</h2> + </> ); } else if (!this.props.capability && !this.props.viewId) { return ( @@ -113,7 +119,7 @@ class ConfigurationApplicationComponent extends React.Component<ConfigurationApp </div> </> ) - : <h2>View Not Found</h2>; + : <h2>View [{this.props.viewId || this.props.conditionalPackage}] Not Found ! {this.props.viewSpecifications.length} </h2>; } 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<typeof styles> & Connect<typeof mapProps>; + +class FaultStatusComponent extends React.Component<FaultStatusComponentProps> { + render(): JSX.Element { + const { classes, faultStatus } = this.props; + + return ( + <Typography variant="body1" color="inherit" > + Alarm status: <FontAwesomeIcon className={`${classes.icon} ${classes.critical}`} icon={faExclamationTriangle} /> { faultStatus.critical } | + <FontAwesomeIcon className={`${classes.icon} ${classes.major}`} icon={faExclamationTriangle} /> { faultStatus.major } | + <FontAwesomeIcon className={`${classes.icon} ${classes.minor}`} icon={faExclamationTriangle} /> { faultStatus.minor } | + <FontAwesomeIcon className={`${classes.icon} ${classes.warning}`} icon={faExclamationTriangle} /> { faultStatus.warning } | + </Typography> + ); + }; +} + +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<string | null> = (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<IFaultAppStoreState>(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<IFaultStatus> = (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 @@ <script type="text/javascript" src="./config.js"></script> <script> // run the application - require(["app", "faultApp"], function (app, faultApp) { - faultApp.register(); - app("./app.tsx"); - }); + require(["app", "connectApp", "faultApp", "maintenanceApp", "configurationApp", "helpApp"], function (app, connectApp, faultApp, maintenanceApp, configurationApp, helpApp) { + connectApp.register(); + faultApp.register(); + configurationApp.register(); + maintenanceApp.register(); + helpApp.register(); + app("./app.tsx").runApplication(); + }); </script> </body> 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<Result<{ severity: { buckets: { key: string, doc_count: number }[] } }>>(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<typeof styles> & Connect<typeof mapProps>; + +class HelpStatusComponent extends React.Component<HelpStatusComponentProps> { + 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 + ? ( + <Typography variant="body1" color="inherit" className={classes.link} onClick={(event) => { event.stopPropagation(); history.push(`/help/${helpNode.uri}`) }} > + <FontAwesomeIcon className={classes.icon} icon={faQuestionCircle} /> + Help + </Typography> + ) + : ( + <Typography variant="body1" className={classes.disabled}> + <FontAwesomeIcon className={classes.icon} icon={faQuestionCircle} /> + Help + </Typography> + ); + }; + +} + +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 @@ <script type="text/javascript" src="./require.js"></script> <script type="text/javascript" src="./config.js"></script> <script> - // run the application - require(["app", "helpApp"], function (app, helpApp) { - helpApp.register(); - app("./app.tsx").runApplication(); - }); + // run the application + require(["app", "connectApp", "faultApp", "maintenanceApp", "configurationApp", "helpApp"], function (app, connectApp, faultApp, maintenanceApp, configurationApp, helpApp) { + connectApp.register(); + faultApp.register(); + configurationApp.register(); + maintenanceApp.register(); + helpApp.register(); + app("./app.tsx").runApplication(); + }); </script> </body> 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 <TocTreeNode[]>((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, |