summaryrefslogtreecommitdiffstats
path: root/sdnr/wt/odlux/apps/connectApp/src
diff options
context:
space:
mode:
Diffstat (limited to 'sdnr/wt/odlux/apps/connectApp/src')
-rw-r--r--sdnr/wt/odlux/apps/connectApp/src/actions/commonNetworkElementsActions.ts70
-rw-r--r--sdnr/wt/odlux/apps/connectApp/src/components/connectionStatusLog.tsx36
-rw-r--r--sdnr/wt/odlux/apps/connectApp/src/components/networkElements.tsx73
-rw-r--r--sdnr/wt/odlux/apps/connectApp/src/components/refreshConnectionStatusLogDialog.tsx117
-rw-r--r--sdnr/wt/odlux/apps/connectApp/src/components/refreshNetworkElementsDialog.tsx117
-rw-r--r--sdnr/wt/odlux/apps/connectApp/src/handlers/connectAppRootHandler.ts2
-rw-r--r--sdnr/wt/odlux/apps/connectApp/src/handlers/networkElementsHandler.ts17
-rw-r--r--sdnr/wt/odlux/apps/connectApp/src/index.html1
-rw-r--r--sdnr/wt/odlux/apps/connectApp/src/models/guiCutTrough.ts5
-rw-r--r--sdnr/wt/odlux/apps/connectApp/src/models/networkElementConnection.ts2
-rw-r--r--sdnr/wt/odlux/apps/connectApp/src/pluginConnect.tsx29
-rw-r--r--sdnr/wt/odlux/apps/connectApp/src/services/connectService.ts115
-rw-r--r--sdnr/wt/odlux/apps/connectApp/src/views/connectView.tsx15
13 files changed, 481 insertions, 118 deletions
diff --git a/sdnr/wt/odlux/apps/connectApp/src/actions/commonNetworkElementsActions.ts b/sdnr/wt/odlux/apps/connectApp/src/actions/commonNetworkElementsActions.ts
index a3bdc6828..a83e00239 100644
--- a/sdnr/wt/odlux/apps/connectApp/src/actions/commonNetworkElementsActions.ts
+++ b/sdnr/wt/odlux/apps/connectApp/src/actions/commonNetworkElementsActions.ts
@@ -23,13 +23,13 @@ import { Action } from '../../../../framework/src/flux/action';
import { Dispatch } from '../../../../framework/src/flux/store';
import { IApplicationStoreState } from '../../../../framework/src/store/applicationStore';
-import { networkElementsReloadAction, networkElementsReloadActionAsync } from '../handlers/networkElementsHandler';
+import { networkElementsReloadAction } from '../handlers/networkElementsHandler';
import { connectionStatusLogReloadAction } from '../handlers/connectionStatusLogHandler';
import { PanelId } from '../models/panelId';
import { guiCutThrough } from '../models/guiCutTrough';
-import connectService from '../services/connectService';
-import { NetworkElementConnection } from '../models/networkElementConnection';
+import { connectService} from '../services/connectService';
+
export class SetPanelAction extends Action {
constructor(public panelId: PanelId) {
@@ -38,7 +38,7 @@ export class SetPanelAction extends Action {
}
export class AddWebUriList extends Action {
- constructor(public searchedElements: guiCutThrough[], public notSearchedElements: string[], public unsupportedElements: string[], public newlySearchedElements?: string[] ) {
+ constructor(public searchedElements: guiCutThrough[], public notSearchedElements: string[], public unsupportedElements: string[], public newlySearchedElements?: string[]) {
super();
}
}
@@ -60,49 +60,47 @@ export class SetWeburiSearchBusy extends Action {
}
let isBusy = false;
-export const findWebUrisForGuiCutThroughAsyncAction = (networkElements: NetworkElementConnection[]) => async (dispatcher: Dispatch, getState: () => IApplicationStoreState) => {
+export const findWebUrisForGuiCutThroughAsyncAction = (networkElementIds: string[]) => async (dispatcher: Dispatch, getState: () => IApplicationStoreState) => {
// keep method from executing simultanously; state not used because change of iu isn't needed
- if (isBusy)
- return;
- isBusy = true;
- const { connect: { guiCutThrough } } = getState();
+
+ const { connect: { guiCutThrough, networkElements } } = getState();
let notConnectedElements: string[] = [];
let elementsToSearch: string[] = [];
let prevFoundElements: string[] = [];
- let unsupportedElements: string[]= [];
+ let unsupportedElements: string[] = [];
-
- networkElements.forEach(item => {
- const id = item.id as string;
+ networkElementIds.forEach(id => {
+ const item = networkElements.rows.find((ne) => ne.id === id);
+ if (item) {
if (item.status === "Connected") {
- if(item.coreModelCapability!== "Unsupported"){
+ // if (item.coreModelCapability !== "Unsupported") {
// element is connected and is added to search list, if it doesn't exist already
- const exists = guiCutThrough.searchedElements.filter(element => element.nodeId === id).length > 0;
+ const exists = guiCutThrough.searchedElements.filter(element => element.id === id).length > 0;
if (!exists) {
elementsToSearch.push(id);
-
+
//element was found previously, but wasn't connected
if (guiCutThrough.notSearchedElements.length > 0 && guiCutThrough.notSearchedElements.includes(id)) {
prevFoundElements.push(id);
}
- }
- }else{
- // element does not support core model and must not be searched for a weburi
- const id = item.id as string;
- const exists = guiCutThrough.unsupportedElements.filter(element => element === id).length > 0;
- if(!exists){
- unsupportedElements.push(id);
-
- //element was found previously, but wasn't connected
- if (guiCutThrough.notSearchedElements.length > 0 && guiCutThrough.notSearchedElements.includes(id)) {
- prevFoundElements.push(id);
- }
}
- }
+ // } else {
+ // // element does not support core model and must not be searched for a weburi
+ // const id = item.id as string;
+ // const exists = guiCutThrough.unsupportedElements.filter(element => element === id).length > 0;
+ // if (!exists) {
+ // unsupportedElements.push(id);
+
+ // //element was found previously, but wasn't connected
+ // if (guiCutThrough.notSearchedElements.length > 0 && guiCutThrough.notSearchedElements.includes(id)) {
+ // prevFoundElements.push(id);
+ // }
+ // }
+ // }
}
else {
// element isn't connected and cannot be searched for a weburi
@@ -110,25 +108,25 @@ export const findWebUrisForGuiCutThroughAsyncAction = (networkElements: NetworkE
notConnectedElements.push(item.id as string);
}
}
+ }
});
-
- if (elementsToSearch.length > 0 || notConnectedElements.length > 0 || unsupportedElements.length>0 ) {
- const result = await connectService.getAllWebUriExtensionsForNetworkElementListAsync(elementsToSearch);
- dispatcher(new AddWebUriList(result, notConnectedElements, unsupportedElements, prevFoundElements));
+
+ if (elementsToSearch.length > 0 || notConnectedElements.length > 0 || unsupportedElements.length > 0) {
+ const result = await connectService.getAllWebUriExtensionsForNetworkElementListAsync(elementsToSearch);
+ dispatcher(new AddWebUriList(result, notConnectedElements, unsupportedElements, prevFoundElements));
}
- isBusy = false;
}
export const setPanelAction = (panelId: PanelId) => {
return new SetPanelAction(panelId);
}
-export const updateCurrentViewAsyncAction = () => async (dispatch: Dispatch, getState: () => IApplicationStoreState) => {
+export const updateCurrentViewAsyncAction = () => (dispatch: Dispatch, getState: () => IApplicationStoreState) => {
const { connect: { currentOpenPanel } } = getState();
if (currentOpenPanel === "NetworkElements") {
- return await dispatch(networkElementsReloadActionAsync);
+ return dispatch(networkElementsReloadAction);
}
else {
return dispatch(connectionStatusLogReloadAction);
diff --git a/sdnr/wt/odlux/apps/connectApp/src/components/connectionStatusLog.tsx b/sdnr/wt/odlux/apps/connectApp/src/components/connectionStatusLog.tsx
index f2fd2937d..94b4872dd 100644
--- a/sdnr/wt/odlux/apps/connectApp/src/components/connectionStatusLog.tsx
+++ b/sdnr/wt/odlux/apps/connectApp/src/components/connectionStatusLog.tsx
@@ -19,9 +19,11 @@ import * as React from 'react';
import connect, { IDispatcher, Connect } from '../../../../framework/src/flux/connect';
import { IApplicationStoreState } from '../../../../framework/src/store/applicationStore';
import { MaterialTable, ColumnType, MaterialTableCtorType } from '../../../../framework/src/components/material-table';
+import Refresh from '@material-ui/icons/Refresh';
import { createConnectionStatusLogActions, createConnectionStatusLogProperties } from '../handlers/connectionStatusLogHandler';
import { NetworkElementConnectionLog } from '../models/networkElementConnectionLog';
+import RefreshConnectionStatusLogDialog, { RefreshConnectionStatusLogDialogMode } from './refreshConnectionStatusLogDialog';
const mapProps = (state: IApplicationStoreState) => ({
connectionStatusLogProperties: createConnectionStatusLogProperties(state),
@@ -34,22 +36,52 @@ const mapDispatch = (dispatcher: IDispatcher) => ({
const ConnectionStatusTable = MaterialTable as MaterialTableCtorType<NetworkElementConnectionLog>;
type ConnectionStatusLogComponentProps = Connect<typeof mapProps, typeof mapDispatch>;
+type ConnectionStatusLogComponentState = {
+ refreshConnectionStatusLogEditorMode: RefreshConnectionStatusLogDialogMode
+}
let initialSorted = false;
-class ConnectionStatusLogComponent extends React.Component<ConnectionStatusLogComponentProps> {
+class ConnectionStatusLogComponent extends React.Component<ConnectionStatusLogComponentProps,ConnectionStatusLogComponentState > {
+ constructor(props: ConnectionStatusLogComponentProps) {
+ super(props);
+
+ this.state = {
+ refreshConnectionStatusLogEditorMode: RefreshConnectionStatusLogDialogMode.None
+ };
+ }
+
render(): JSX.Element {
+ const refreshConnectionStatusLogAction = {
+ icon: Refresh, tooltip: 'Refresh Connection Status Log Table', onClick: () => {
+ this.setState({
+ refreshConnectionStatusLogEditorMode: RefreshConnectionStatusLogDialogMode.RefreshConnectionStatusLogTable
+ });
+ }
+ };
+
return (
- <ConnectionStatusTable stickyHeader tableId="connection-status-table" columns={[
+ <>
+ <ConnectionStatusTable stickyHeader tableId="connection-status-table" customActionButtons={[refreshConnectionStatusLogAction]} columns={[
{ property: "timestamp", title: "Timestamp", type: ColumnType.text },
{ property: "nodeId", title: "Node Name", type: ColumnType.text },
{ property: "status", title: "Connection Status", type: ColumnType.text },
]} idProperty="id" {...this.props.connectionStatusLogActions} {...this.props.connectionStatusLogProperties} >
</ConnectionStatusTable>
+ <RefreshConnectionStatusLogDialog
+ mode={ this.state.refreshConnectionStatusLogEditorMode }
+ onClose={ this.onCloseRefreshConnectionStatusLogDialog }
+ />
+ </>
);
};
+ private onCloseRefreshConnectionStatusLogDialog = () => {
+ this.setState({
+ refreshConnectionStatusLogEditorMode: RefreshConnectionStatusLogDialogMode.None
+ });
+ }
componentDidMount() {
if (!initialSorted) {
initialSorted = true;
diff --git a/sdnr/wt/odlux/apps/connectApp/src/components/networkElements.tsx b/sdnr/wt/odlux/apps/connectApp/src/components/networkElements.tsx
index 53e10481a..84a22a99a 100644
--- a/sdnr/wt/odlux/apps/connectApp/src/components/networkElements.tsx
+++ b/sdnr/wt/odlux/apps/connectApp/src/components/networkElements.tsx
@@ -19,12 +19,14 @@ import * as React from 'react';
import { Theme, createStyles, withStyles, WithStyles } from '@material-ui/core/styles';
import AddIcon from '@material-ui/icons/Add';
+import Refresh from '@material-ui/icons/Refresh';
import LinkIcon from '@material-ui/icons/Link';
import LinkOffIcon from '@material-ui/icons/LinkOff';
import RemoveIcon from '@material-ui/icons/RemoveCircleOutline';
import EditIcon from '@material-ui/icons/Edit';
import Info from '@material-ui/icons/Info';
import ComputerIcon from '@material-ui/icons/Computer';
+import { MenuItem, Divider, Typography } from '@material-ui/core';
import { MaterialTable, ColumnType, MaterialTableCtorType } from '../../../../framework/src/components/material-table';
import { IApplicationStoreState } from '../../../../framework/src/store/applicationStore';
@@ -34,12 +36,14 @@ import { NavigateToApplication } from '../../../../framework/src/actions/navigat
import { createNetworkElementsActions, createNetworkElementsProperties } from '../handlers/networkElementsHandler';
import { NetworkElementConnection } from '../models/networkElementConnection';
+import { TopologyNode } from '../models/topologyNetconf';
import EditNetworkElementDialog, { EditNetworkElementDialogMode } from './editNetworkElementDialog';
+import RefreshNetworkElementsDialog, { RefreshNetworkElementsDialogMode } from './refreshNetworkElementsDialog';
import InfoNetworkElementDialog, { InfoNetworkElementDialogMode } from './infoNetworkElementDialog';
import { loadAllInfoElementAsync } from '../actions/infoNetworkElementActions';
-import { TopologyNode } from '../models/topologyNetconf';
-import { MenuItem, Divider, Typography } from '@material-ui/core';
+import { connectService } from '../services/connectService';
+import { getAccessPolicyByUrl } from '../../../../framework/src/services/restService';
const styles = (theme: Theme) => createStyles({
connectionStatusConnected: {
@@ -63,6 +67,22 @@ const styles = (theme: Theme) => createStyles({
}
});
+type GetStatelessComponentProps<T> = T extends (props: infer P & { children?: React.ReactNode }) => any ? P : any
+const MenuItemExt : React.FC<GetStatelessComponentProps<typeof MenuItem>> = (props) => {
+ const [disabled, setDisabled] = React.useState(true);
+ const onMouseDown = (ev: React.MouseEvent<HTMLElement>) => {
+ if (ev.button ===1){
+ setDisabled(!disabled);
+ ev.preventDefault();
+ }
+ };
+ return (
+ <div onMouseDown={onMouseDown} >
+ <MenuItem {...{...props, disabled: props.disabled && disabled }} />
+ </div>
+ );
+};
+
const mapProps = (state: IApplicationStoreState) => ({
networkElementsProperties: createNetworkElementsProperties(state),
applicationState: state,
@@ -78,6 +98,7 @@ type NetworkElementsListComponentProps = WithStyles<typeof styles> & Connect<typ
type NetworkElementsListComponentState = {
networkElementToEdit: NetworkElementConnection,
networkElementEditorMode: EditNetworkElementDialogMode,
+ refreshNetworkElementsEditorMode: RefreshNetworkElementsDialogMode,
infoNetworkElementEditorMode: InfoNetworkElementDialogMode,
elementInfo: TopologyNode | null
}
@@ -94,19 +115,21 @@ export class NetworkElementsListComponent extends React.Component<NetworkElement
this.state = {
networkElementToEdit: emptyRequireNetworkElement,
networkElementEditorMode: EditNetworkElementDialogMode.None,
+ refreshNetworkElementsEditorMode: RefreshNetworkElementsDialogMode.None,
elementInfo: null,
infoNetworkElementEditorMode: InfoNetworkElementDialogMode.None
};
}
-
+
getContextMenu(rowData: NetworkElementConnection): JSX.Element[] {
-
-
-
- const { configuration, fault, inventory } = this.props.applicationState as any;
- let buttonArray = [
- <MenuItem aria-label={"mount-button"} onClick={event => this.onOpenMountdNetworkElementsDialog(event, rowData)} ><LinkIcon /><Typography>Mount</Typography></MenuItem>,
- <MenuItem aria-label={"unmount-button"} onClick={event => this.onOpenUnmountdNetworkElementsDialog(event, rowData)}><LinkOffIcon /><Typography>Unmount</Typography></MenuItem>,
+ const mountUri = rowData.id && connectService.getNetworkElementUri(rowData.id);
+ const mountPolicy = mountUri && getAccessPolicyByUrl(mountUri);
+ const canMount = mountPolicy && mountPolicy.POST || false;
+
+ const { configuration} = this.props.applicationState as any;
+ const buttonArray = [
+ <MenuItemExt aria-label={"mount-button"} onClick={event => this.onOpenMountdNetworkElementsDialog(event, rowData)} disabled={!canMount} ><LinkIcon /><Typography>Mount</Typography></MenuItemExt>,
+ <MenuItemExt aria-label={"unmount-button"} onClick={event => this.onOpenUnmountdNetworkElementsDialog(event, rowData)} disabled={!canMount} ><LinkOffIcon /><Typography>Unmount</Typography></MenuItemExt>,
<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>,
@@ -121,9 +144,9 @@ export class NetworkElementsListComponent extends React.Component<NetworkElement
<MenuItem onClick={event => this.props.navigateToApplication("security", rowData.nodeId)} disabled={true} ><Typography>Security</Typography></MenuItem>,
];
- if (rowData.webUri) {
+ if (rowData.weburi) {
// add an icon for gui cuttrough, if weburi is available
- return [<MenuItem aria-label={"web-client-button"} onClick={event => window.open(rowData.webUri, "_blank")} ><ComputerIcon /><Typography>Web Client</Typography></MenuItem>].concat(buttonArray)
+ return [<MenuItem aria-label={"web-client-button"} onClick={event => window.open(rowData.weburi, "_blank")} ><ComputerIcon /><Typography>Web Client</Typography></MenuItem>].concat(buttonArray)
} else {
return buttonArray;
}
@@ -134,6 +157,12 @@ export class NetworkElementsListComponent extends React.Component<NetworkElement
render(): JSX.Element {
const { classes } = this.props;
const { networkElementToEdit } = this.state;
+
+ // const mountUri = rowData.id && connectService.getNetworkElementUri(rowData.id);
+ // const mountPolicy = mountUri && getAccessPolicyByUrl(mountUri);
+ // const canAdd = mountPolicy && mountPolicy.POST || false;
+ const canAdd = true;
+
const addRequireNetworkElementAction = {
icon: AddIcon, tooltip: 'Add', onClick: () => {
this.setState({
@@ -143,9 +172,17 @@ export class NetworkElementsListComponent extends React.Component<NetworkElement
}
};
+ const refreshNetworkElementsAction = {
+ icon: Refresh, tooltip: 'Refresh Network Elements table', onClick: () => {
+ this.setState({
+ refreshNetworkElementsEditorMode: RefreshNetworkElementsDialogMode.RefreshNetworkElementsTable
+ });
+ }
+ };
+
return (
<>
- <NetworkElementTable stickyHeader tableId="network-element-table" customActionButtons={[addRequireNetworkElementAction]} columns={[
+ <NetworkElementTable stickyHeader tableId="network-element-table" customActionButtons={[refreshNetworkElementsAction, ...canAdd ? [addRequireNetworkElementAction]: []]} columns={[
{ property: "nodeId", title: "Node Name", type: ColumnType.text },
{ property: "isRequired", title: "Required", type: ColumnType.boolean },
{ property: "status", title: "Connection Status", type: ColumnType.text },
@@ -163,6 +200,10 @@ export class NetworkElementsListComponent extends React.Component<NetworkElement
mode={this.state.networkElementEditorMode}
onClose={this.onCloseEditNetworkElementDialog}
/>
+ <RefreshNetworkElementsDialog
+ mode={this.state.refreshNetworkElementsEditorMode}
+ onClose={this.onCloseRefreshNetworkElementsDialog}
+ />
<InfoNetworkElementDialog
initialNetworkElement={networkElementToEdit}
mode={this.state.infoNetworkElementEditorMode}
@@ -243,7 +284,11 @@ export class NetworkElementsListComponent extends React.Component<NetworkElement
networkElementToEdit: emptyRequireNetworkElement,
});
}
+ private onCloseRefreshNetworkElementsDialog = () => {
+ this.setState({
+ refreshNetworkElementsEditorMode: RefreshNetworkElementsDialogMode.None
+ });
+ }
}
export const NetworkElementsList = withStyles(styles)(connect(mapProps, mapDispatch)(NetworkElementsListComponent));
-export default NetworkElementsList; \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/connectApp/src/components/refreshConnectionStatusLogDialog.tsx b/sdnr/wt/odlux/apps/connectApp/src/components/refreshConnectionStatusLogDialog.tsx
new file mode 100644
index 000000000..41229eae6
--- /dev/null
+++ b/sdnr/wt/odlux/apps/connectApp/src/components/refreshConnectionStatusLogDialog.tsx
@@ -0,0 +1,117 @@
+/**
+ * ============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 * as React from 'react';
+
+import Button from '@material-ui/core/Button';
+import Dialog from '@material-ui/core/Dialog';
+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 { connectionStatusLogReloadAction } from '../handlers/connectionStatusLogHandler';
+import { IDispatcher, connect, Connect } from '../../../../framework/src/flux/connect';
+
+import { ConnectionStatusLogType } from '../models/connectionStatusLog';
+
+export enum RefreshConnectionStatusLogDialogMode {
+ None = "none",
+ RefreshConnectionStatusLogTable = "RefreshConnectionStatusLogTable",
+}
+
+const mapDispatch = (dispatcher: IDispatcher) => ({
+ refreshConnectionStatusLog: () => dispatcher.dispatch(connectionStatusLogReloadAction)
+});
+
+type DialogSettings = {
+ dialogTitle: string,
+ dialogDescription: string,
+ applyButtonText: string,
+ cancelButtonText: string,
+ enableMountIdEditor: boolean,
+ enableUsernameEditor: boolean,
+ enableExtendedEditor: boolean,
+}
+
+const settings: { [key: string]: DialogSettings } = {
+ [RefreshConnectionStatusLogDialogMode.None]: {
+ dialogTitle: "",
+ dialogDescription: "",
+ applyButtonText: "",
+ cancelButtonText: "",
+ enableMountIdEditor: false,
+ enableUsernameEditor: false,
+ enableExtendedEditor: false,
+ },
+ [RefreshConnectionStatusLogDialogMode.RefreshConnectionStatusLogTable]: {
+ dialogTitle: "Do you want to refresh the Connection Status Log table?",
+ dialogDescription: "",
+ applyButtonText: "Yes",
+ cancelButtonText: "Cancel",
+ enableMountIdEditor: true,
+ enableUsernameEditor: true,
+ enableExtendedEditor: true,
+ }
+}
+
+type RefreshConnectionStatusLogDialogComponentProps = Connect<undefined, typeof mapDispatch> & {
+ mode: RefreshConnectionStatusLogDialogMode;
+ onClose: () => void;
+};
+
+type RefreshConnectionStatusLogDialogComponentState = ConnectionStatusLogType & { isNameValid: boolean, isHostSet: boolean };
+
+class RefreshConnectionStatusLogDialogComponent extends React.Component<RefreshConnectionStatusLogDialogComponentProps, RefreshConnectionStatusLogDialogComponentState> {
+ constructor(props: RefreshConnectionStatusLogDialogComponentProps) {
+ super(props);
+ }
+
+ render(): JSX.Element {
+ const setting = settings[this.props.mode];
+ return (
+ <Dialog open={this.props.mode !== RefreshConnectionStatusLogDialogMode.None}>
+ <DialogTitle id="form-dialog-title" aria-label={`${setting.dialogTitle.replace(/ /g, "-").toLowerCase()}-dialog`}>{setting.dialogTitle}</DialogTitle>
+ <DialogContent>
+ <DialogContentText>
+ {setting.dialogDescription}
+ </DialogContentText>
+ </DialogContent>
+ <DialogActions>
+ <Button aria-label="dialog-confirm-button" onClick={(event) => {
+ this.onRefresh();
+ }} > {setting.applyButtonText} </Button>
+ <Button aria-label="dialog-cancel-button" onClick={(event) => {
+ this.onCancel();
+ }} color="secondary"> {setting.cancelButtonText} </Button>
+ </DialogActions>
+ </Dialog>
+ )
+ }
+
+ private onRefresh = () => {
+ this.props.refreshConnectionStatusLog();
+ this.props.onClose();
+ };
+
+ private onCancel = () => {
+ this.props.onClose();
+ }
+}
+
+export const RefreshConnectionStatusLogDialog = connect(undefined, mapDispatch)(RefreshConnectionStatusLogDialogComponent);
+export default RefreshConnectionStatusLogDialog; \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/connectApp/src/components/refreshNetworkElementsDialog.tsx b/sdnr/wt/odlux/apps/connectApp/src/components/refreshNetworkElementsDialog.tsx
new file mode 100644
index 000000000..a349977ab
--- /dev/null
+++ b/sdnr/wt/odlux/apps/connectApp/src/components/refreshNetworkElementsDialog.tsx
@@ -0,0 +1,117 @@
+/**
+ * ============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 * as React from 'react';
+
+import Button from '@material-ui/core/Button';
+import Dialog from '@material-ui/core/Dialog';
+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 { networkElementsReloadAction } from '../handlers/networkElementsHandler';
+import { IDispatcher, connect, Connect } from '../../../../framework/src/flux/connect';
+
+import { NetworkElementConnection } from '../models/networkElementConnection';
+
+export enum RefreshNetworkElementsDialogMode {
+ None = "none",
+ RefreshNetworkElementsTable = "RefreshNetworkElementsTable",
+}
+
+const mapDispatch = (dispatcher: IDispatcher) => ({
+ refreshNetworkElement: () => dispatcher.dispatch(networkElementsReloadAction)
+});
+
+type DialogSettings = {
+ dialogTitle: string,
+ dialogDescription: string,
+ applyButtonText: string,
+ cancelButtonText: string,
+ enableMountIdEditor: boolean,
+ enableUsernameEditor: boolean,
+ enableExtendedEditor: boolean,
+}
+
+const settings: { [key: string]: DialogSettings } = {
+ [RefreshNetworkElementsDialogMode.None]: {
+ dialogTitle: "",
+ dialogDescription: "",
+ applyButtonText: "",
+ cancelButtonText: "",
+ enableMountIdEditor: false,
+ enableUsernameEditor: false,
+ enableExtendedEditor: false,
+ },
+ [RefreshNetworkElementsDialogMode.RefreshNetworkElementsTable]: {
+ dialogTitle: "Do you want to refresh the Network Elements table?",
+ dialogDescription: "",
+ applyButtonText: "Yes",
+ cancelButtonText: "Cancel",
+ enableMountIdEditor: true,
+ enableUsernameEditor: true,
+ enableExtendedEditor: true,
+ }
+}
+
+type RefreshNetworkElementsDialogComponentProps = Connect<undefined, typeof mapDispatch> & {
+ mode: RefreshNetworkElementsDialogMode;
+ onClose: () => void;
+};
+
+type RefreshNetworkElementsDialogComponentState = NetworkElementConnection & { isNameValid: boolean, isHostSet: boolean };
+
+class RefreshNetworkElementsDialogComponent extends React.Component<RefreshNetworkElementsDialogComponentProps, RefreshNetworkElementsDialogComponentState> {
+ constructor(props: RefreshNetworkElementsDialogComponentProps) {
+ super(props);
+ }
+
+ render(): JSX.Element {
+ const setting = settings[this.props.mode];
+ return (
+ <Dialog open={this.props.mode !== RefreshNetworkElementsDialogMode.None}>
+ <DialogTitle id="form-dialog-title" aria-label={`${setting.dialogTitle.replace(/ /g, "-").toLowerCase()}-dialog`}>{setting.dialogTitle}</DialogTitle>
+ <DialogContent>
+ <DialogContentText>
+ {setting.dialogDescription}
+ </DialogContentText>
+ </DialogContent>
+ <DialogActions>
+ <Button aria-label="dialog-confirm-button" onClick={(event) => {
+ this.onRefresh();
+ }} > {setting.applyButtonText} </Button>
+ <Button aria-label="dialog-cancel-button" onClick={(event) => {
+ this.onCancel();
+ }} color="secondary"> {setting.cancelButtonText} </Button>
+ </DialogActions>
+ </Dialog>
+ )
+ }
+
+ private onRefresh = () => {
+ this.props.refreshNetworkElement();
+ this.props.onClose();
+ };
+
+ private onCancel = () => {
+ this.props.onClose();
+ }
+}
+
+export const RefreshNetworkElementsDialog = connect(undefined, mapDispatch)(RefreshNetworkElementsDialogComponent);
+export default RefreshNetworkElementsDialog; \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/connectApp/src/handlers/connectAppRootHandler.ts b/sdnr/wt/odlux/apps/connectApp/src/handlers/connectAppRootHandler.ts
index 302a981eb..c23e43924 100644
--- a/sdnr/wt/odlux/apps/connectApp/src/handlers/connectAppRootHandler.ts
+++ b/sdnr/wt/odlux/apps/connectApp/src/handlers/connectAppRootHandler.ts
@@ -68,7 +68,7 @@ const guiCutThroughHandler: IActionHandler<guiCutThroughState> = (state = { sear
} else if (action instanceof RemoveWebUri) {
const nodeId = action.element;
- const webUris = state.searchedElements.filter(item => item.nodeId !== nodeId);
+ const webUris = state.searchedElements.filter(item => item.id !== nodeId);
const knownElements = state.notSearchedElements.filter(item => item !== nodeId);
const unsupportedElement = state.unsupportedElements.filter(item => item != nodeId);
state = { notSearchedElements: knownElements, searchedElements: webUris, unsupportedElements: unsupportedElement };
diff --git a/sdnr/wt/odlux/apps/connectApp/src/handlers/networkElementsHandler.ts b/sdnr/wt/odlux/apps/connectApp/src/handlers/networkElementsHandler.ts
index 4fe858c69..b74a39427 100644
--- a/sdnr/wt/odlux/apps/connectApp/src/handlers/networkElementsHandler.ts
+++ b/sdnr/wt/odlux/apps/connectApp/src/handlers/networkElementsHandler.ts
@@ -17,10 +17,11 @@
*/
import { createExternal, IExternalTableState } from '../../../../framework/src/components/material-table/utilities';
import { createSearchDataHandler } from '../../../../framework/src/utilities/elasticSearch';
+import { getAccessPolicyByUrl } from '../../../../framework/src/services/restService';
import { NetworkElementConnection } from '../models/networkElementConnection';
-import connectService from '../services/connectService';
-import { requestRest } from '../../../../framework/src/services/restService';
+import { connectService } from '../services/connectService';
+
export interface INetworkElementsState extends IExternalTableState<NetworkElementConnection> { }
// create eleactic search material data fetch handler
@@ -31,8 +32,7 @@ export const {
createActions: createNetworkElementsActions,
createProperties: createNetworkElementsProperties,
reloadAction: networkElementsReloadAction,
- reloadActionAsync: networkElementsReloadActionAsync
-
+
// set value action, to change a value
} = createExternal<NetworkElementConnection>(networkElementsSearchHandler, appState => {
@@ -43,9 +43,9 @@ export const {
appState.connect.networkElements.rows.forEach(element => {
if (element.status === "Connected") {
- const webUri = webUris.find(item => item.nodeId === element.id as string);
+ const webUri = webUris.find(item => item.id === element.id as string);
if (webUri) {
- element.webUri = webUri.webUri;
+ element.weburi = webUri.weburi;
element.isWebUriUnreachable = false;
}
else {
@@ -56,5 +56,10 @@ export const {
}
return appState.connect.networkElements
+}, (ne) => {
+ if (!ne || !ne.id) return true;
+ const neUrl = connectService.getNetworkElementUri(ne.id);
+ const policy = getAccessPolicyByUrl(neUrl);
+ return !(policy.GET || policy.POST);
});
diff --git a/sdnr/wt/odlux/apps/connectApp/src/index.html b/sdnr/wt/odlux/apps/connectApp/src/index.html
index 9c8a2063e..6f44c25f7 100644
--- a/sdnr/wt/odlux/apps/connectApp/src/index.html
+++ b/sdnr/wt/odlux/apps/connectApp/src/index.html
@@ -19,6 +19,7 @@
connectApp.register();
faultApp.register();
inventoryApp.register();
+ app("./app.tsx").configureApplication({ authentication:"basic", enablePolicy: false,});
app("./app.tsx").runApplication();
});
</script>
diff --git a/sdnr/wt/odlux/apps/connectApp/src/models/guiCutTrough.ts b/sdnr/wt/odlux/apps/connectApp/src/models/guiCutTrough.ts
index d44eea685..b9f515dc8 100644
--- a/sdnr/wt/odlux/apps/connectApp/src/models/guiCutTrough.ts
+++ b/sdnr/wt/odlux/apps/connectApp/src/models/guiCutTrough.ts
@@ -16,4 +16,7 @@
* ============LICENSE_END==========================================================================
*/
-export type guiCutThrough = { webUri?: string, nodeId: string } \ No newline at end of file
+export type guiCutThrough = {
+ id: string,
+ weburi?: string
+} \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/connectApp/src/models/networkElementConnection.ts b/sdnr/wt/odlux/apps/connectApp/src/models/networkElementConnection.ts
index b3586d693..71eddc808 100644
--- a/sdnr/wt/odlux/apps/connectApp/src/models/networkElementConnection.ts
+++ b/sdnr/wt/odlux/apps/connectApp/src/models/networkElementConnection.ts
@@ -24,7 +24,7 @@ export type NetworkElementConnection = {
port: number;
username?: string;
password?: string;
- webUri?: string;
+ weburi?: string;
isWebUriUnreachable?: boolean;
status?: "Connected" | "mounted" | "unmounted" | "Connecting" | "Disconnected" | "idle";
coreModelCapability?: string;
diff --git a/sdnr/wt/odlux/apps/connectApp/src/pluginConnect.tsx b/sdnr/wt/odlux/apps/connectApp/src/pluginConnect.tsx
index f711c440c..93bed1aad 100644
--- a/sdnr/wt/odlux/apps/connectApp/src/pluginConnect.tsx
+++ b/sdnr/wt/odlux/apps/connectApp/src/pluginConnect.tsx
@@ -20,19 +20,12 @@ import { faPlug } from '@fortawesome/free-solid-svg-icons';
import applicationManager from '../../../framework/src/services/applicationManager';
import { subscribe, IFormatedMessage } from '../../../framework/src/services/notificationService';
+import { AddSnackbarNotification } from '../../../framework/src/actions/snackbarActions';
import connectAppRootHandler from './handlers/connectAppRootHandler';
import ConnectApplication from './views/connectView';
-import { AddSnackbarNotification } from '../../../framework/src/actions/snackbarActions';
-import { updateCurrentViewAsyncAction } from './actions/commonNetworkElementsActions';
-
-type ObjectNotification = {
- counter: string;
- nodeName: string;
- objectId: string;
- timeStamp: string;
-}
+import { findWebUrisForGuiCutThroughAsyncAction, updateCurrentViewAsyncAction } from './actions/commonNetworkElementsActions';
export function register() {
const applicationApi = applicationManager.registerApplication({
@@ -44,13 +37,19 @@ export function register() {
});
// subscribe to the websocket notifications
- subscribe<ObjectNotification & IFormatedMessage>(["ObjectCreationNotification", "ObjectDeletionNotification", "AttributeValueChangedNotification"], (msg => {
+ subscribe<IFormatedMessage>(["object-creation-notification", "object-deletion-notification", "attribute-value-changed-notification"], (msg => {
const store = applicationApi.applicationStore;
- if (msg && msg.notifType === "ObjectCreationNotification" && store) {
- store.dispatch(new AddSnackbarNotification({ message: `Adding network element [${msg.objectId}]`, options: { variant: 'info' } }));
- } else if (msg && (msg.notifType === "ObjectDeletionNotification" || msg.notifType === "AttributeValueChangedNotification") && store) {
- store.dispatch(new AddSnackbarNotification({ message: `Updating network element [${msg.objectId}]`, options: { variant: 'info' } }));
+ if (msg && msg.type.type === "object-creation-notification" && store) {
+ store.dispatch(new AddSnackbarNotification({ message: `Adding network element [${msg['node-id']}]`, options: { variant: 'info' } }));
+ } else if (msg && (msg.type.type === "object-deletion-notification" || msg.type.type === "attribute-value-changed-notification") && store) {
+ store.dispatch(new AddSnackbarNotification({ message: `Updating network element [${msg['node-id']}]`, options: { variant: 'info' } }));
+ }
+ if (store) {
+ store.dispatch(updateCurrentViewAsyncAction() as any).then(() => {
+ if (msg['node-id']) {
+ store.dispatch(findWebUrisForGuiCutThroughAsyncAction([msg['node-id']]));
+ }
+ });
}
- store && store.dispatch(updateCurrentViewAsyncAction());
}));
} \ No newline at end of file
diff --git a/sdnr/wt/odlux/apps/connectApp/src/services/connectService.ts b/sdnr/wt/odlux/apps/connectApp/src/services/connectService.ts
index fbbfa68d9..5d7667a7f 100644
--- a/sdnr/wt/odlux/apps/connectApp/src/services/connectService.ts
+++ b/sdnr/wt/odlux/apps/connectApp/src/services/connectService.ts
@@ -28,12 +28,15 @@ import { guiCutThrough } from '../models/guiCutTrough';
* Represents a web api accessor service for all Network Elements actions.
*/
class ConnectService {
+ public getNetworkElementUri = (nodeId: string) => '/rests/data/network-topology:network-topology/topology=topology-netconf/node=' + nodeId;
+ public getNetworkElementConnectDataProviderUri = (operation: "create" | "update" | "delete" ) => `/rests/operations/data-provider:${operation}-network-element-connection`;
+ public getAllWebUriExtensionsForNetworkElementListUri = (nodeId: string) => this.getNetworkElementUri(nodeId) + '/yang-ext:mount/core-model:network-element';
/**
* Inserts a network elements.
*/
public async createNetworkElement(element: NetworkElementConnection): Promise<NetworkElementConnection | null> {
- const path = `/rests/operations/data-provider:create-network-element-connection`;
+ const path = this.getNetworkElementConnectDataProviderUri("create") ;
const result = await requestRest<NetworkElementConnection>(path, {
method: "POST", body: JSON.stringify(convertPropertyNames({ "data-provider:input": element }, replaceUpperCase))
});
@@ -44,7 +47,7 @@ class ConnectService {
* Updates a network element.
*/
public async updateNetworkElement(element: UpdateNetworkElement): Promise<NetworkElementConnection | null> {
- const path = `/rests/operations/data-provider:update-network-element-connection`;
+ const path = this.getNetworkElementConnectDataProviderUri("update");
const result = await requestRest<NetworkElementConnection>(path, {
method: "POST", body: JSON.stringify(convertPropertyNames({ "data-provider:input": element }, replaceUpperCase))
});
@@ -58,7 +61,7 @@ class ConnectService {
const query = {
"id": element.id
};
- const path = `/rests/operations/data-provider:delete-network-element-connection`;
+ const path = this.getNetworkElementConnectDataProviderUri("delete");
const result = await requestRest<NetworkElementConnection>(path, {
method: "POST", body: JSON.stringify(convertPropertyNames({ "data-provider:input": query }, replaceUpperCase))
});
@@ -67,7 +70,7 @@ class ConnectService {
/** Mounts network element. */
public async mountNetworkElement(networkElement: NetworkElementConnection): Promise<boolean> {
- const path = '/rests/data/network-topology:network-topology/topology=topology-netconf/node=' + networkElement.nodeId;
+ const path = this.getNetworkElementUri(networkElement.nodeId);
const mountXml = [
'<node xmlns="urn:TBD:params:xml:ns:yang:network-topology">',
`<node-id>${networkElement.nodeId}</node-id>`,
@@ -106,7 +109,7 @@ class ConnectService {
/** Unmounts a network element by its id. */
public async unmountNetworkElement(nodeId: string): Promise<boolean> {
- const path = '/rests/data/network-topology:network-topology/topology=topology-netconf/node=' + nodeId;
+ const path = this.getNetworkElementUri(nodeId);
try {
const result = await requestRest<string>(path, {
@@ -126,7 +129,7 @@ class ConnectService {
/** Yang capabilities of the selected network elements. */
public async infoNetworkElement(nodeId: string): Promise<TopologyNode | null> {
- const path = '/rests/data/network-topology:network-topology/topology=topology-netconf/node=' + nodeId;
+ const path = this.getNetworkElementUri(nodeId);
const topologyRequestPomise = requestRest<Topology>(path, { method: "GET" });
return topologyRequestPomise && topologyRequestPomise.then(result => {
@@ -157,38 +160,80 @@ class ConnectService {
})) || null;
}
- public getAllWebUriExtensionsForNetworkElementListAsync(ne: string[]) {
-
- let promises: any[] = [];
- let webUris: guiCutThrough[] = []
-
- ne.forEach(nodeId => {
- const path = '/rests/data/network-topology:network-topology/topology=topology-netconf/node=' + nodeId + '/yang-ext:mount/core-model:network-element';
+ public async getAllWebUriExtensionsForNetworkElementListAsync(neList: string[]): Promise<(guiCutThrough)[]> {
+ const path = `/rests/operations/data-provider:read-gui-cut-through-entry`;
+ let webUriList: guiCutThrough[] = []
+ const query = {
+ "data-provider:input": {
+ "filter": [{
+ "property": "id",
+ "filtervalues": neList
+ }],
+ "pagination": {
+ "size": 20,
+ "page": 1
+ }
+ }
+ }
- // add search request to array
- promises.push(requestRest<any>(path, { method: "GET" })
- .then(result => {
- if (result != null && result['core-model:network-element'] && result['core-model:network-element'].extension) {
- const webUri = result['core-model:network-element'].extension.find((item: any) => item['value-name'] === "webUri")
- if (webUri) {
- webUris.push({ webUri: webUri.value, nodeId: nodeId });
- } else {
- webUris.push({ webUri: undefined, nodeId: nodeId });
+ const result = await requestRest<Result<guiCutThrough>>(path, { method: "POST", body: JSON.stringify(query) });
+ const resultData = result && result["data-provider:output"] && result["data-provider:output"].data;
+ neList.forEach(nodeId => {
+ let entryNotFound = true;
+ if (resultData) {
+ const BreakException = {};
+ try {
+ resultData.forEach(entry => {
+ if (entry.id == nodeId) {
+ entryNotFound = false;
+ if (entry.weburi) {
+ webUriList.push({ id: nodeId, weburi: entry.weburi });
+ } else {
+ webUriList.push({ id: nodeId, weburi: undefined });
+ }
+ throw BreakException;
}
- } else {
- webUris.push({ webUri: undefined, nodeId: nodeId });
- }
- })
- .catch(error => {
- webUris.push({ webUri: undefined, nodeId: nodeId });
- }))
-
- })
-
- // wait until all promises are done and return weburis
- return Promise.all(promises).then(result => { return webUris });
+ });
+ } catch (e) {}
+ }
+ if (entryNotFound)
+ webUriList.push({ id: nodeId, weburi: undefined });
+ });
+ return webUriList;
}
+ // public async getAllWebUriExtensionsForNetworkElementListAsync(ne: string[]): Promise<(guiCutThrough)[] | null> {
+
+ // let promises: any[] = [];
+ // let webUris: guiCutThrough[] = []
+
+ // ne.forEach(nodeId => {
+ // const path = this.getAllWebUriExtensionsForNetworkElementListUri(nodeId);
+
+ // // add search request to array
+ // promises.push(requestRest<any>(path, { method: "GET" })
+ // .then(result => {
+ // if (result != null && result['core-model:network-element'] && result['core-model:network-element'].extension) {
+ // const webUri = result['core-model:network-element'].extension.find((item: any) => item['value-name'] === "webUri")
+ // if (webUri) {
+ // webUris.push({ weburi: webUri.value, id: nodeId });
+ // } else {
+ // webUris.push({ weburi: undefined, id: nodeId });
+ // }
+ // } else {
+ // webUris.push({ weburi: undefined, id: nodeId });
+ // }
+ // })
+ // .catch(error => {
+ // webUris.push({ weburi: undefined, id: nodeId });
+ // }))
+ // })
+ // // wait until all promises are done and return weburis
+ // return Promise.all(promises).then(result => { return webUris });
+ // }
+
}
+
+
+
export const connectService = new ConnectService();
-export default connectService;
diff --git a/sdnr/wt/odlux/apps/connectApp/src/views/connectView.tsx b/sdnr/wt/odlux/apps/connectApp/src/views/connectView.tsx
index 1fa5e1909..34b1b94b6 100644
--- a/sdnr/wt/odlux/apps/connectApp/src/views/connectView.tsx
+++ b/sdnr/wt/odlux/apps/connectApp/src/views/connectView.tsx
@@ -40,10 +40,9 @@ const mapProps = (state: IApplicationStoreState) => ({
const mapDispatcher = (dispatcher: IDispatcher) => ({
networkElementsActions: createNetworkElementsActions(dispatcher.dispatch),
connectionStatusLogActions: createConnectionStatusLogActions(dispatcher.dispatch),
- onLoadNetworkElements: () => {
- dispatcher.dispatch(networkElementsReloadAction);
- },
- loadWebUris: async (networkElements: NetworkElementConnection[]) => { await dispatcher.dispatch(findWebUrisForGuiCutThroughAsyncAction(networkElements)) },
+ onLoadNetworkElements: () => dispatcher.dispatch(networkElementsReloadAction),
+ loadWebUris: (networkElements: NetworkElementConnection[]) =>
+ dispatcher.dispatch(findWebUrisForGuiCutThroughAsyncAction(networkElements.map((ne) => ne.id!))),
isBusy: (busy: boolean) => dispatcher.dispatch(new SetWeburiSearchBusy(busy)),
onLoadConnectionStatusLog: () => {
dispatcher.dispatch(connectionStatusLogReloadAction);
@@ -65,12 +64,14 @@ class ConnectApplicationComponent extends React.Component<ConnectApplicationComp
//this.props.connectionStatusLogActions.onToggleFilter();
}
- public componentDidUpdate = async () => {
- // search for guicutthroughs after networkelements were found
+ public componentDidUpdate = () => {
+
const networkElements = this.props.netWorkElements;
if (networkElements.rows.length > 0) {
- await this.props.loadWebUris(networkElements.rows);
+ // Update all netWorkElements for propper WebUriClient settings in case of table data changes.
+ // e.G: Pagination of the table data (there is no event)
+ this.props.loadWebUris(networkElements.rows);
}
}