aboutsummaryrefslogtreecommitdiffstats
path: root/sdnr/wt/odlux/framework/src/views
diff options
context:
space:
mode:
authorAijana Schumann <aijana.schumann@highstreet-technologies.com>2021-12-06 15:09:15 +0100
committerAijana Schumann <aijana.schumann@highstreet-technologies.com>2021-12-06 15:12:24 +0100
commit152cb381ea2c915c762416092337ce1d8589d1c6 (patch)
tree63b71c8343f9292281f5d7f5eac14342fec06402 /sdnr/wt/odlux/framework/src/views
parent8ea94e1210671b941f84abfe16e248cfa086fe49 (diff)
Update ODLUX
Update login view, add logout after user session ends, add user settings, several bugfixes Issue-ID: CCSDK-3540 Signed-off-by: Aijana Schumann <aijana.schumann@highstreet-technologies.com> Change-Id: I21137756b204287e25766a9646bf2faf7bad9d35
Diffstat (limited to 'sdnr/wt/odlux/framework/src/views')
-rw-r--r--sdnr/wt/odlux/framework/src/views/frame.tsx10
-rw-r--r--sdnr/wt/odlux/framework/src/views/home.tsx185
-rw-r--r--sdnr/wt/odlux/framework/src/views/login.tsx79
-rw-r--r--sdnr/wt/odlux/framework/src/views/settings.tsx126
4 files changed, 329 insertions, 71 deletions
diff --git a/sdnr/wt/odlux/framework/src/views/frame.tsx b/sdnr/wt/odlux/framework/src/views/frame.tsx
index b4cc43e0b..1c78dd297 100644
--- a/sdnr/wt/odlux/framework/src/views/frame.tsx
+++ b/sdnr/wt/odlux/framework/src/views/frame.tsx
@@ -19,7 +19,7 @@ import * as React from 'react';
import { HashRouter as Router, Route, Redirect, Switch } from 'react-router-dom';
import { withStyles, WithStyles, createStyles, Theme } from '@material-ui/core/styles';
-import { faHome, faAddressBook, faSignInAlt } from '@fortawesome/free-solid-svg-icons';
+import { faHome, faAddressBook, faSignInAlt, faCog } from '@fortawesome/free-solid-svg-icons';
import { SnackbarProvider } from 'notistack';
import { ConfirmProvider } from 'material-ui-confirm';
@@ -34,6 +34,7 @@ import Home from '../views/home';
import Login from '../views/login';
import About from '../views/about';
import Test from '../views/test';
+import UserSettings from '../views/settings';
import applicationService from '../services/applicationManager';
@@ -58,6 +59,8 @@ const styles = (theme: Theme) => createStyles({
toolbar: theme.mixins.toolbar as any
});
+
+
type FrameProps = WithStyles<typeof styles>;
class FrameComponent extends React.Component<FrameProps>{
@@ -89,6 +92,11 @@ class FrameComponent extends React.Component<FrameProps>{
<About />
</AppFrame>
)} />
+ <Route path="/settings" component={() => (
+ <AppFrame title={"Settings"} icon={faCog} >
+ <UserSettings />
+ </AppFrame>
+ )} />
{process.env.NODE_ENV === "development" ? <Route path="/test" component={() => (
<AppFrame title={"Test"} icon={faAddressBook} >
<Test />
diff --git a/sdnr/wt/odlux/framework/src/views/home.tsx b/sdnr/wt/odlux/framework/src/views/home.tsx
index 0e1d487e3..176de02ab 100644
--- a/sdnr/wt/odlux/framework/src/views/home.tsx
+++ b/sdnr/wt/odlux/framework/src/views/home.tsx
@@ -34,6 +34,16 @@ const styles = (theme: Theme) => createStyles({
const scrollbar = { overflow: "auto", paddingRight: "20px" }
+let connectionStatusinitialLoad = true;
+let connectionStatusinitialStateChanged = false;
+let connectionStatusDataLoad: number[] = [0, 0, 0, 0];
+let connectionTotalCount = 0;
+
+let alarmStatusinitialLoad = true;
+let alarmStatusinitialStateChanged = false;
+let alarmStatusDataLoad: number[] = [0, 0, 0, 0];
+let alarmTotalCount = 0;
+
const mapProps = (state: IApplicationStoreState) => ({
connectionStatusCount: state.connect.connectionStatusCount,
alarmStatus: state.fault.faultStatus
@@ -55,16 +65,34 @@ class Home extends React.Component<HomeComponentProps> {
render(): JSX.Element {
const { classes } = this.props;
+ if (!this.props.connectionStatusCount.isLoadingConnectionStatusChart) {
+ connectionStatusDataLoad = [
+ this.props.connectionStatusCount.Connected,
+ this.props.connectionStatusCount.Connecting,
+ this.props.connectionStatusCount.Disconnected,
+ this.props.connectionStatusCount.UnableToConnect
+ ];
+ connectionTotalCount = this.props.connectionStatusCount.Connected + this.props.connectionStatusCount.Connecting
+ + this.props.connectionStatusCount.Disconnected + this.props.connectionStatusCount.UnableToConnect;
+
+ }
+
+ if (!this.props.alarmStatus.isLoadingAlarmStatusChart) {
+ alarmStatusDataLoad = [
+ this.props.alarmStatus.critical,
+ this.props.alarmStatus.major,
+ this.props.alarmStatus.minor,
+ this.props.alarmStatus.warning
+ ];
+ alarmTotalCount = this.props.alarmStatus.critical + this.props.alarmStatus.major
+ + this.props.alarmStatus.minor + this.props.alarmStatus.warning;
+ }
+
/** Available Network Connection Status chart data */
const connectionStatusData = {
labels: ['Connected', 'Connecting', 'Disconnected', 'UnableToConnect'],
datasets: [{
- data: [
- this.props.connectionStatusCount.Connected,
- this.props.connectionStatusCount.Connecting,
- this.props.connectionStatusCount.Disconnected,
- this.props.connectionStatusCount.UnableToConnect
- ],
+ data: connectionStatusDataLoad,
backgroundColor: [
'rgb(0, 153, 51)',
'rgb(255, 102, 0)',
@@ -86,6 +114,28 @@ class Home extends React.Component<HomeComponentProps> {
}]
};
+ /** Loading Connection Status chart */
+ const connectionStatusisLoading = {
+ labels: ['Loading chart...'],
+ datasets: [{
+ data: [1],
+ backgroundColor: [
+ 'rgb(255, 255, 255)'
+ ]
+ }]
+ };
+
+ /** Loading Alarm Status chart */
+ const alarmStatusisLoading = {
+ labels: ['Loading chart...'],
+ datasets: [{
+ data: [1],
+ backgroundColor: [
+ 'rgb(255, 255, 255)'
+ ]
+ }]
+ };
+
/** Connection status options */
let labels: String[] = ['Connected', 'Connecting', 'Disconnected', 'UnableToConnect'];
const connectionStatusOptions = {
@@ -153,12 +203,7 @@ class Home extends React.Component<HomeComponentProps> {
'Warning'
],
datasets: [{
- data: [
- this.props.alarmStatus.critical,
- this.props.alarmStatus.major,
- this.props.alarmStatus.minor,
- this.props.alarmStatus.warning
- ],
+ data: alarmStatusDataLoad,
backgroundColor: [
'rgb(240, 25, 10)',
'rgb(240, 133, 10)',
@@ -241,17 +286,25 @@ class Home extends React.Component<HomeComponentProps> {
<div style={scrollbar} >
<h1>Welcome to ODLUX</h1>
<div className={classes.pageWidthSettings}>
- {this.checkConnectionStatus() ?
- <Doughnut
- data={connectionStatusData}
- type={Doughnut}
- width={500}
- height={500}
- options={connectionStatusOptions}
- plugins={connectionStatusPlugins}
- />
+ {this.checkElementsAreLoaded() ?
+ this.checkConnectionStatus() && connectionTotalCount != 0 ?
+ <Doughnut
+ data={connectionStatusData}
+ type={Doughnut}
+ width={500}
+ height={500}
+ options={connectionStatusOptions}
+ plugins={connectionStatusPlugins}
+ />
+ : <Doughnut
+ data={connectionStatusUnavailableData}
+ type={Doughnut}
+ width={500}
+ height={500}
+ options={connectionStatusUnavailableOptions}
+ plugins={connectionStatusPlugins} />
: <Doughnut
- data={connectionStatusUnavailableData}
+ data={connectionStatusisLoading}
type={Doughnut}
width={500}
height={500}
@@ -261,17 +314,26 @@ class Home extends React.Component<HomeComponentProps> {
}
</div>
<div className={classes.pageWidthSettings}>
- {this.checkAlarmStatus() ?
- <Doughnut
- data={alarmStatusData}
- type={Doughnut}
- width={500}
- height={500}
- options={alarmStatusOptions}
- plugins={alarmStatusPlugins}
- />
+ {this.checkAlarmsAreLoaded() ?
+ this.checkAlarmStatus() && alarmTotalCount != 0 ?
+ <Doughnut
+ data={alarmStatusData}
+ type={Doughnut}
+ width={500}
+ height={500}
+ options={alarmStatusOptions}
+ plugins={alarmStatusPlugins}
+ />
+ : <Doughnut
+ data={alarmStatusUnavailableData}
+ type={Doughnut}
+ width={500}
+ height={500}
+ options={alarmStatusUnavailableOptions}
+ plugins={alarmStatusPlugins}
+ />
: <Doughnut
- data={alarmStatusUnavailableData}
+ data={alarmStatusisLoading}
type={Doughnut}
width={500}
height={500}
@@ -288,23 +350,74 @@ class Home extends React.Component<HomeComponentProps> {
/** Check if connection status data available */
public checkConnectionStatus = () => {
let statusCount = this.props.connectionStatusCount;
- if (statusCount.Connected == 0 && statusCount.Connecting == 0 && statusCount.Disconnected == 0 && statusCount.UnableToConnect == 0) {
- return false;
+ if (statusCount.isLoadingConnectionStatusChart) {
+ return true;
}
- else
+ if (statusCount.Connected == 0 && statusCount.Connecting == 0 && statusCount.Disconnected == 0
+ && statusCount.UnableToConnect == 0) {
+ return false;
+ } else {
return true;
+ }
+ }
+
+ /** Check if connection status chart data is loaded */
+ public checkElementsAreLoaded = () => {
+ let isLoadingCheck = this.props.connectionStatusCount;
+ if (connectionStatusinitialLoad && !isLoadingCheck.isLoadingConnectionStatusChart) {
+ if (this.checkConnectionStatus()) {
+ connectionStatusinitialLoad = false;
+ return true;
+ }
+ return false;
+ } else if (connectionStatusinitialLoad && isLoadingCheck.isLoadingConnectionStatusChart) {
+ connectionStatusinitialLoad = false;
+ connectionStatusinitialStateChanged = true;
+ return !isLoadingCheck.isLoadingConnectionStatusChart;
+ } else if (connectionStatusinitialStateChanged) {
+ if (!isLoadingCheck.isLoadingConnectionStatusChart) {
+ connectionStatusinitialStateChanged = false;
+ }
+ return !isLoadingCheck.isLoadingConnectionStatusChart;
+ }
+ return true;
}
/** Check if alarms data available */
public checkAlarmStatus = () => {
let alarmCount = this.props.alarmStatus;
+ if (alarmCount.isLoadingAlarmStatusChart) {
+ return true;
+ }
if (alarmCount.critical == 0 && alarmCount.major == 0 && alarmCount.minor == 0 && alarmCount.warning == 0) {
return false;
}
- else
+ else {
return true;
+ }
}
+ /** Check if alarm status chart data is loaded */
+ public checkAlarmsAreLoaded = () => {
+ let isLoadingCheck = this.props.alarmStatus;
+ if (alarmStatusinitialLoad && !isLoadingCheck.isLoadingAlarmStatusChart) {
+ if (this.checkAlarmStatus()) {
+ alarmStatusinitialLoad = false;
+ return true;
+ }
+ return false;
+ } else if (alarmStatusinitialLoad && isLoadingCheck.isLoadingAlarmStatusChart) {
+ alarmStatusinitialLoad = false;
+ alarmStatusinitialStateChanged = true;
+ return !isLoadingCheck.isLoadingAlarmStatusChart;
+ } else if (alarmStatusinitialStateChanged) {
+ if (!isLoadingCheck.isLoadingAlarmStatusChart) {
+ alarmStatusinitialStateChanged = false;
+ }
+ return !isLoadingCheck.isLoadingAlarmStatusChart;
+ }
+ return true;
+ }
}
export default withStyles(styles)(withRouter(connect(mapProps, mapDispatch)(Home))); \ No newline at end of file
diff --git a/sdnr/wt/odlux/framework/src/views/login.tsx b/sdnr/wt/odlux/framework/src/views/login.tsx
index be1fb801f..53219facd 100644
--- a/sdnr/wt/odlux/framework/src/views/login.tsx
+++ b/sdnr/wt/odlux/framework/src/views/login.tsx
@@ -36,7 +36,7 @@ import connect, { Connect, IDispatcher } from '../flux/connect';
import authenticationService from '../services/authenticationService';
import { updateExternalLoginProviderAsyncActionCreator } from '../actions/loginProvider';
-import { UpdatePolicies, UpdateUser } from '../actions/authentication';
+import { loginUserAction, UpdatePolicies } from '../actions/authentication';
import { IApplicationStoreState } from '../store/applicationStore';
import { AuthPolicy, AuthToken, User } from '../models/authentication';
@@ -73,6 +73,20 @@ const styles = (theme: Theme) => createStyles({
submit: {
marginTop: theme.spacing(3),
},
+ lineContainer:{
+ width: '100%',
+ height: 10,
+ borderBottom: '1px solid grey',
+ textAlign: 'center',
+ marginTop:15,
+ marginBottom:5
+ },
+ thirdPartyDivider:{
+ fontSize: 15,
+ backgroundColor: 'white',
+ padding: '0 10px',
+ color: 'grey'
+ }
});
const mapProps = (state: IApplicationStoreState) => ({
@@ -85,7 +99,7 @@ const mapDispatch = (dispatcher: IDispatcher) => ({
updateExternalProviders: () => dispatcher.dispatch(updateExternalLoginProviderAsyncActionCreator()),
updateAuthentication: (token: AuthToken | null) => {
const user = token && new User(token) || undefined;
- dispatcher.dispatch(new UpdateUser(user));
+ dispatcher.dispatch(loginUserAction(user));
},
updatePolicies: (policies?: AuthPolicy[]) => {
return dispatcher.dispatch(new UpdatePolicies(policies));
@@ -138,6 +152,7 @@ class LoginComponent extends React.Component<LoginProps, ILoginState> {
render(): JSX.Element {
const { classes } = this.props;
+ const areProvidersAvailable = this.props.externalLoginProviders && this.props.externalLoginProviders.length > 0;
return (
<>
<CssBaseline />
@@ -148,6 +163,32 @@ class LoginComponent extends React.Component<LoginProps, ILoginState> {
</Avatar>
<Typography variant="caption">Sign in</Typography>
<form className={classes.form}>
+
+
+ {areProvidersAvailable &&
+ <>
+ {
+ this.props.externalLoginProviders!.map((provider, index) => (
+ <Button
+ aria-controls="externalLogin"
+ aria-label={"external-login-identity-provider-" + (index + 1)}
+ aria-haspopup="true"
+ fullWidth
+ variant="contained"
+ color="primary"
+ className={classes.submit} onClick={() => { window.location = provider.loginUrl as any; }}>
+ {provider.title}
+ </Button>))
+ }
+
+ <div className={classes.lineContainer}>
+ <span className={classes.thirdPartyDivider}>
+ OR
+ </span>
+ </div>
+ </>
+ }
+
<FormControl margin="normal" required fullWidth>
<InputLabel htmlFor="username">Username</InputLabel>
<Input id="username" name="username" autoComplete="username" autoFocus
@@ -178,10 +219,6 @@ class LoginComponent extends React.Component<LoginProps, ILoginState> {
onChange={event => { this.setState({ scope: event.target.value }) }}
/>
</FormControl>
- <FormControlLabel
- control={<Checkbox value="remember" color="secondary" />}
- label="Remember me"
- />
<Button
aria-label="login-button"
type="submit"
@@ -193,34 +230,8 @@ class LoginComponent extends React.Component<LoginProps, ILoginState> {
onClick={this.onSignIn}
>
Sign in
- </Button>
- { this.props.externalLoginProviders && this.props.externalLoginProviders.length > 0
- ?
- [
- <Button
- aria-controls="externalLogin"
- aria-haspopup="true"
- fullWidth
- variant="contained"
- color="primary"
- className={classes.submit} onClick={(ev) => { this.setExternalProviderAnchor(ev.currentTarget); }}>
- Use external Login
- </Button>,
- <Menu
- anchorEl={this.state.externalProviderAnchor}
- keepMounted
- open={Boolean(this.state.externalProviderAnchor)}
- onClose={() => { this.setExternalProviderAnchor(null); }}
- >
- {
- this.props.externalLoginProviders.map((provider) => (
- <MenuItem key={provider.id} onClick={() => { window.location = provider.loginUrl as any; } }>{ provider.title} </MenuItem>
- ))
- }
- </Menu>
- ]
- : null
- }
+ </Button>
+
</form>
{this.state.message && <Alert severity="error">{this.state.message}</Alert>}
</Paper>
diff --git a/sdnr/wt/odlux/framework/src/views/settings.tsx b/sdnr/wt/odlux/framework/src/views/settings.tsx
new file mode 100644
index 000000000..f1a8ab35a
--- /dev/null
+++ b/sdnr/wt/odlux/framework/src/views/settings.tsx
@@ -0,0 +1,126 @@
+/**
+ * ============LICENSE_START========================================================================
+ * ONAP : ccsdk feature sdnr wt odlux
+ * =================================================================================================
+ * Copyright (C) 2021 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 { IApplicationStoreState } from "../store/applicationStore";
+import connect, { Connect, IDispatcher } from "../flux/connect";
+
+import applicationService from '../services/applicationManager';
+import { makeStyles } from '@material-ui/styles';
+import { Divider, List, ListItem, ListItemText, Paper } from '@material-ui/core';
+
+import { GeneralUserSettings } from '../components/settings/general'
+import { GoBackAction } from '../actions/navigationActions';
+import { toAriaLabel } from '../utilities/yangHelper';
+
+type props = Connect<typeof mapProps, typeof mapDispatch>;
+
+type SettingsEntry = { name: string, element: JSX.Element }
+
+
+const mapProps = (state: IApplicationStoreState) => ({
+
+});
+
+const mapDispatch = (dispatcher: IDispatcher) => ({
+ goBack: () => dispatcher.dispatch(new GoBackAction())
+});
+
+const styles = makeStyles({
+ sectionMargin: {
+ marginTop: "30px",
+ marginBottom: "15px"
+ },
+ elementMargin: {
+
+ marginLeft: "10px"
+ },
+ menu: {
+ flex: "1 0 0%",
+ }
+});
+
+const UserSettings: React.FunctionComponent<props> = (props) => {
+
+ const classes = styles();
+ const registrations = applicationService.applications;
+
+ const [selectedIndex, setSelectedIndex] = React.useState(0);
+
+ const navigateBack = () => {
+ props.goBack();
+ }
+
+ let settingsArray: SettingsEntry[] = [];
+
+ //add all framework specific settings
+ settingsArray.push({name:"General", element: <GeneralUserSettings onClose={navigateBack} />})
+
+
+ //get app settings
+ let settingsElements : (SettingsEntry) [] = Object.keys(registrations).map(p => {
+ const application = registrations[p];
+
+ if (application.settingsElement) {
+ const value: SettingsEntry = { name: application.menuEntry?.toString()!, element: <application.settingsElement onClose={navigateBack} /> };
+ return value;
+
+ } else {
+ return null;
+ }
+ }).filter((x): x is SettingsEntry => x !== null);
+
+
+ settingsArray.push(...settingsElements);
+
+ const onSelectElement = (e: any, newValue: number) => {
+ e.preventDefault();
+ setSelectedIndex(newValue);
+ }
+
+ return <div style={{ display: "flex", flexDirection: "row", height: "100%" }}>
+ <div style={{ display: "flex", flexDirection: "column", height: "100%", width: "15%" }}>
+ <Paper variant="outlined" style={{ height: "70%" }}>
+ <List className={classes.menu} component="nav">
+ {
+ settingsArray.map((el, index) => {
+ return (
+ <>
+ <ListItem selected={selectedIndex === index} button onClick={e => { onSelectElement(e, index) }} aria-label={toAriaLabel(el?.name+"-settings")}>
+ <ListItemText primary={el?.name} style={{ padding: 0 }} />
+ </ListItem>
+ <Divider />
+ </>)
+ })
+ }
+ </List>
+ </Paper>
+
+ </div>
+ <div style={{ height: "100%", width: "80%", marginLeft: 15 }}>
+ <div style={{ height: "100%" }}>
+ {
+ settingsArray[selectedIndex]?.element
+ }
+ </div>
+ </div>
+ </div>
+}
+
+
+export default connect(mapProps, mapDispatch)(UserSettings);