From a2b6dd34d73bf432846dc59c6f57dd59a03aff9b Mon Sep 17 00:00:00 2001 From: Michael Dürre Date: Thu, 8 Sep 2022 09:45:06 +0200 Subject: update odlux sources MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit update basic odlux functionality for kohn Issue-ID: CCSDK-3765 Signed-off-by: Michael Dürre Change-Id: I3723c9c2f35b9012ba537920b294a54bb556cbc6 Signed-off-by: Michael Dürre --- sdnr/wt/odlux/framework/pom.xml | 8 - .../odlux/framework/src/actions/authentication.ts | 38 +++-- .../odlux/framework/src/actions/settingsAction.ts | 86 ++++++++-- sdnr/wt/odlux/framework/src/assets/images/home.svg | 20 +++ .../framework/src/assets/images/home.svg.d.ts | 20 +++ .../src/components/material-table/columnModel.ts | 1 + .../src/components/material-table/index.tsx | 51 +++++- .../components/material-table/showColumnDialog.tsx | 188 +++++++++++++++++++++ .../src/components/material-table/tableFilter.tsx | 7 +- .../src/components/material-table/tableHead.tsx | 14 +- .../src/components/material-table/tableToolbar.tsx | 36 +++- .../src/components/material-table/utilities.ts | 40 ++++- .../framework/src/components/navigationMenu.tsx | 11 +- .../wt/odlux/framework/src/components/titleBar.tsx | 8 +- .../src/handlers/applicationStateHandler.ts | 29 +++- .../src/handlers/authenticationHandler.ts | 4 - sdnr/wt/odlux/framework/src/index.dev.html | 2 +- sdnr/wt/odlux/framework/src/index.html | 2 +- .../wt/odlux/framework/src/models/elasticSearch.ts | 11 ++ .../odlux/framework/src/models/iconDefinition.ts | 2 +- sdnr/wt/odlux/framework/src/models/settings.ts | 24 +++ .../src/services/authenticationService.ts | 8 +- .../framework/src/services/broadcastService.ts | 2 +- .../framework/src/services/forceLogoutService.ts | 57 ------- .../wt/odlux/framework/src/services/restService.ts | 15 +- .../framework/src/services/userSessionService.ts | 2 +- .../odlux/framework/src/utilities/elasticSearch.ts | 94 +++++++---- sdnr/wt/odlux/framework/src/views/about.tsx | 6 +- sdnr/wt/odlux/framework/src/views/frame.tsx | 3 +- sdnr/wt/odlux/framework/src/views/login.tsx | 28 ++- sdnr/wt/odlux/framework/src/views/test.tsx | 2 +- .../framework/src2/main/resources/version.json | 2 - sdnr/wt/odlux/framework/webpack.vendor.js | 5 +- 33 files changed, 648 insertions(+), 178 deletions(-) create mode 100644 sdnr/wt/odlux/framework/src/assets/images/home.svg create mode 100644 sdnr/wt/odlux/framework/src/assets/images/home.svg.d.ts create mode 100644 sdnr/wt/odlux/framework/src/components/material-table/showColumnDialog.tsx delete mode 100644 sdnr/wt/odlux/framework/src/services/forceLogoutService.ts (limited to 'sdnr/wt/odlux/framework') diff --git a/sdnr/wt/odlux/framework/pom.xml b/sdnr/wt/odlux/framework/pom.xml index 48b0d95d1..6f0285a56 100644 --- a/sdnr/wt/odlux/framework/pom.xml +++ b/sdnr/wt/odlux/framework/pom.xml @@ -236,10 +236,6 @@ ##odlux.apps.inventoryApp.buildno## ${odlux.apps.inventoryApp.buildno} - - ##odlux.apps.linkCalculationApp.buildno## - ${odlux.apps.linkCalculationApp.buildno} - ##odlux.apps.maintenanceApp.buildno## ${odlux.apps.maintenanceApp.buildno} @@ -248,10 +244,6 @@ ##odlux.apps.mediatorApp.buildno## ${odlux.apps.mediatorApp.buildno} - - ##odlux.apps.networkMapApp.buildno## - ${odlux.apps.networkMapApp.buildno} - ##odlux.apps.permanceHistoryApp.buildno## ${odlux.apps.permanceHistoryApp.buildno} diff --git a/sdnr/wt/odlux/framework/src/actions/authentication.ts b/sdnr/wt/odlux/framework/src/actions/authentication.ts index 20a248dc1..f1d11de37 100644 --- a/sdnr/wt/odlux/framework/src/actions/authentication.ts +++ b/sdnr/wt/odlux/framework/src/actions/authentication.ts @@ -18,9 +18,11 @@ import { Dispatch } from '../flux/store'; import { Action } from '../flux/action'; import { AuthPolicy, User } from '../models/authentication'; -import { GeneralSettings } from '../models/settings'; -import { SetGeneralSettingsAction, setGeneralSettingsAction } from './settingsAction'; +import { GeneralSettings, Settings } from '../models/settings'; +import { saveInitialSettings, SetGeneralSettingsAction, setGeneralSettingsAction } from './settingsAction'; import { endWebsocketSession } from '../services/notificationService'; +import { endUserSession, startUserSession } from '../services/userSessionService'; +import { IApplicationStoreState } from '../store/applicationStore'; export class UpdateUser extends Action { @@ -40,16 +42,30 @@ export class UpdatePolicies extends Action { export const loginUserAction = (user?: User) => (dispatcher: Dispatch) =>{ dispatcher(new UpdateUser(user)); - loadUserSettings(user, dispatcher); - - + if(user){ + startUserSession(user); + loadUserSettings(user, dispatcher); + localStorage.setItem("userToken", user.toString()); + } } -export const logoutUser = () => (dispatcher: Dispatch) =>{ +export const logoutUser = () => (dispatcher: Dispatch, getState: () => IApplicationStoreState) =>{ + + const {framework:{applicationState:{ authentication }, authenticationState: {user}}} = getState(); dispatcher(new UpdateUser(undefined)); dispatcher(new SetGeneralSettingsAction(null)); endWebsocketSession(); + endUserSession(); + localStorage.removeItem("userToken"); + + + //only call if a user is currently logged in + if (authentication === "oauth" && user) { + + const url = window.location.origin; + window.location.href=`${url}/oauth/logout`; + } } const loadUserSettings = (user: User | undefined, dispatcher: Dispatch) =>{ @@ -74,14 +90,8 @@ const loadUserSettings = (user: User | undefined, dispatcher: Dispatch) =>{ }else{ return null; } - }).then((result:GeneralSettings)=>{ - if(result?.general){ - //will start websocket session if applicable - dispatcher(setGeneralSettingsAction(result.general.areNotificationsEnabled!)); - - }else{ - dispatcher(setGeneralSettingsAction(false)); - } + }).then((result:Settings)=>{ + dispatcher(saveInitialSettings(result)); }) } } \ No newline at end of file diff --git a/sdnr/wt/odlux/framework/src/actions/settingsAction.ts b/sdnr/wt/odlux/framework/src/actions/settingsAction.ts index ffcdfc26a..1c18ddc8e 100644 --- a/sdnr/wt/odlux/framework/src/actions/settingsAction.ts +++ b/sdnr/wt/odlux/framework/src/actions/settingsAction.ts @@ -18,47 +18,113 @@ import { Dispatch } from "../flux/store"; import { Action } from "../flux/action"; -import { GeneralSettings } from "../models/settings"; +import { GeneralSettings, Settings, TableSettings, TableSettingsColumn } from "../models/settings"; import { getSettings, putSettings } from "../services/settingsService"; import { startWebsocketSession, suspendWebsocketSession } from "../services/notificationService"; +import { IApplicationStoreState } from "../store/applicationStore"; -export class SetGeneralSettingsAction extends Action{ +export class SetGeneralSettingsAction extends Action { /** * */ - constructor(public areNoticationsActive: boolean|null) { + constructor(public areNoticationsActive: boolean | null) { super(); - } } -export const setGeneralSettingsAction = (value: boolean) => (dispatcher: Dispatch) =>{ +export class SetTableSettings extends Action { + + constructor(public tableName: string, public updatedColumns: TableSettingsColumn[]) { + super(); + } +} + +export class LoadSettingsAction extends Action { + + constructor(public settings: Settings & { isInitialLoadDone: true }) { + super(); + } + +} + +export class SettingsDoneLoadingAction extends Action { + +} + +export const setGeneralSettingsAction = (value: boolean) => (dispatcher: Dispatch) => { dispatcher(new SetGeneralSettingsAction(value)); - if(value){ + if (value) { startWebsocketSession(); - }else{ + } else { suspendWebsocketSession(); } } -export const updateGeneralSettingsAction = (activateNotifications: boolean) => async (dispatcher: Dispatch) =>{ +export const updateGeneralSettingsAction = (activateNotifications: boolean) => async (dispatcher: Dispatch) => { - const value: GeneralSettings = {general:{areNotificationsEnabled: activateNotifications}}; + const value: GeneralSettings = { general: { areNotificationsEnabled: activateNotifications } }; const result = await putSettings("/general", JSON.stringify(value.general)); dispatcher(setGeneralSettingsAction(activateNotifications)); } +export const updateTableSettings = (tableName: string, columns: TableSettingsColumn[]) => async (dispatcher: Dispatch, getState: () => IApplicationStoreState) => { + + + //TODO: ask micha how to handle object with variable properties! + //fix for now: just safe everything! + + let {framework:{applicationState:{settings:{tables}}}} = getState(); + + tables[tableName] = { columns: columns }; + const json=JSON.stringify(tables); + + // would only save latest entry + //const json = JSON.stringify({ [tableName]: { columns: columns } }); + + const result = await putSettings("/tables", json); + + dispatcher(new SetTableSettings(tableName, columns)); +} + export const getGeneralSettingsAction = () => async (dispatcher: Dispatch) => { const result = await getSettings(); - if(result && result.general){ + if (result && result.general) { dispatcher(new SetGeneralSettingsAction(result.general.areNotificationsEnabled!)) } +} + +export const saveInitialSettings = (settings: any) => async (dispatcher: Dispatch) => { + + const defaultSettings = {general:{ areNotificationsEnabled: false }, tables:{}}; + + const initialSettings = {...defaultSettings, ...settings}; + + if (initialSettings) { + if (initialSettings.general) { + const settingsActive = initialSettings.general.areNotificationsEnabled; + + if (settingsActive) { + startWebsocketSession(); + } else { + suspendWebsocketSession(); + } + } + + dispatcher(new LoadSettingsAction(initialSettings)); + } + else { + dispatcher(new SettingsDoneLoadingAction()); + + } + + + } \ No newline at end of file diff --git a/sdnr/wt/odlux/framework/src/assets/images/home.svg b/sdnr/wt/odlux/framework/src/assets/images/home.svg new file mode 100644 index 000000000..080d0502e --- /dev/null +++ b/sdnr/wt/odlux/framework/src/assets/images/home.svg @@ -0,0 +1,20 @@ + + + + + + + + + + diff --git a/sdnr/wt/odlux/framework/src/assets/images/home.svg.d.ts b/sdnr/wt/odlux/framework/src/assets/images/home.svg.d.ts new file mode 100644 index 000000000..7098d79a2 --- /dev/null +++ b/sdnr/wt/odlux/framework/src/assets/images/home.svg.d.ts @@ -0,0 +1,20 @@ +/** + * ============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========================================================================== + */ + + declare const home: string; + export default home; \ No newline at end of file diff --git a/sdnr/wt/odlux/framework/src/components/material-table/columnModel.ts b/sdnr/wt/odlux/framework/src/components/material-table/columnModel.ts index ce5b2cd1e..3ed313497 100644 --- a/sdnr/wt/odlux/framework/src/components/material-table/columnModel.ts +++ b/sdnr/wt/odlux/framework/src/components/material-table/columnModel.ts @@ -37,6 +37,7 @@ export type ColumnModel = { disablePadding?: boolean; width?: string | number ; className?: string; + hide?: boolean; style?: React.CSSProperties; align?: 'inherit' | 'left' | 'center' | 'right' | 'justify'; disableSorting?: boolean; diff --git a/sdnr/wt/odlux/framework/src/components/material-table/index.tsx b/sdnr/wt/odlux/framework/src/components/material-table/index.tsx index aac2a1252..8541cfe56 100644 --- a/sdnr/wt/odlux/framework/src/components/material-table/index.tsx +++ b/sdnr/wt/odlux/framework/src/components/material-table/index.tsx @@ -36,7 +36,7 @@ import { EnhancedTableHead } from './tableHead'; import { EnhancedTableFilter } from './tableFilter'; import { ColumnModel, ColumnType } from './columnModel'; -import { Menu } from '@mui/material'; +import { Menu, Typography } from '@mui/material'; import { DistributiveOmit } from '@mui/types'; import makeStyles from '@mui/styles/makeStyles'; @@ -151,19 +151,23 @@ export type MaterialTableComponentState = { rowsPerPage: number; loading: boolean; showFilter: boolean; + hiddenColumns: string[]; filter: { [property: string]: string }; }; export type TableApi = { forceRefresh?: () => Promise }; -type MaterialTableComponentBaseProps = WithStyles & { +type MaterialTableComponentBaseProps = WithStyles & { className?: string; columns: ColumnModel[]; idProperty: keyof TData | ((data: TData) => React.Key); - tableId?: string; + + //Note: used to save settings as well. Must be unique across apps. Null tableIds will not get saved to the settings + tableId: string | null; isPopup?: boolean; title?: string; stickyHeader?: boolean; + allowHtmlHeader?: boolean; defaultSortOrder?: 'asc' | 'desc'; defaultSortColumn?: keyof TData; enableSelection?: boolean; @@ -182,6 +186,8 @@ type MaterialTableComponentPropsWithExternalState = MaterialTableCom onHandleChangePage: (page: number) => void; onHandleChangeRowsPerPage: (rowsPerPage: number | null) => void; onHandleRequestSort: (property: string) => void; + onHideColumns : (columnNames: string[]) => void + onShowColumns: (columnNames: string[]) => void }; type MaterialTableComponentProps = @@ -203,13 +209,18 @@ function isMaterialTableComponentPropsWithRowsAndRequestData(props: MaterialTabl propsWithExternalState.onHandleChangePage instanceof Function || propsWithExternalState.onHandleChangeRowsPerPage instanceof Function || propsWithExternalState.onToggleFilter instanceof Function || + propsWithExternalState.onHideColumns instanceof Function || propsWithExternalState.onHandleRequestSort instanceof Function } +// get settings in here! + + class MaterialTableComponent extends React.Component { constructor(props: MaterialTableComponentProps) { super(props); + const page = isMaterialTableComponentPropsWithRowsAndRequestData(this.props) ? this.props.page : 0; const rowsPerPage = isMaterialTableComponentPropsWithRowsAndRequestData(this.props) ? this.props.rowsPerPage || 10 : 10; @@ -224,6 +235,7 @@ class MaterialTableComponent extends React.Component extends React.Component ((data as { [key: string]: any })[this.props.idProperty as any as string] as string | number) : this.props.idProperty; const toggleFilter = isMaterialTableComponentPropsWithRowsAndRequestData(this.props) ? this.props.onToggleFilter : () => { !this.props.disableFilter && this.setState({ showFilter: !showFilter }, this.update) } + + const hideColumns = isMaterialTableComponentPropsWithRowsAndRequestData(this.props) ? this.props.onHideColumns : (data: string[]) => { const newArray = [...new Set([...this.state.hiddenColumns, ...data])]; this.setState({hiddenColumns:newArray}); } + const showColumns = isMaterialTableComponentPropsWithRowsAndRequestData(this.props) ? this.props.onShowColumns : (data: string[]) => { const newArray = this.state.hiddenColumns.filter(el=> !data.includes(el)); this.setState({hiddenColumns:newArray}); } + + const allColumnsHidden = this.props.columns.length === this.state.hiddenColumns.length; return ( + onToggleFilter={toggleFilter} + columns={columns} + onHideColumns={hideColumns} + onShowColumns={showColumns} /> extends React.Component - {showFilter && || null} - {rows // may need ordering here + {showFilter && || null} + + {allColumnsHidden ? All columns of this table are hidden. : + + rows // may need ordering here .map((entry: TData & { [RowDisabled]?: boolean, [kex: string]: any }, index) => { const entryId = getId(entry); const contextMenu = (this.props.createContextMenu && this.state.contextMenuInfo.index === index && this.props.createContextMenu(entry)) || null; @@ -295,15 +320,17 @@ class MaterialTableComponent extends React.Component {this.props.enableSelection ? - + : null } { + this.props.columns.map( col => { const style = col.width ? { width: col.width } : {}; - return ( + const tableCell = ( + {col.type === ColumnType.custom && col.customControl ? @@ -313,6 +340,10 @@ class MaterialTableComponent extends React.Component ); + + //show column if... + const showColumn = !this.state.hiddenColumns.includes(col.property); + return showColumn && tableCell } ) } @@ -352,6 +383,7 @@ class MaterialTableComponent extends React.Component extends React.Component ({ + settings: state.framework.applicationState.settings, + settingsDoneLoading: state.framework.applicationState.settings.isInitialLoadDone +}); + +const mapDispatchToProps = (dispatcher: IDispatcher) => ({ + saveToSettings: (tableName: string, columns: TableSettingsColumn[]) => dispatcher.dispatch(updateTableSettings(tableName, columns)) +}) + +type DialogProps = { + columns: ColumnModel<{}>[], + settingsName: string | null, + anchorEl: HTMLElement | null; + hideColumns: (columnNames: string[]) => void + showColumns: (columnNames: string[]) => void + onClose(): void + +} & Connect; + + //TODO: figure out why everything gets triggered twice... + +const ShowColumnsDialog: React.FunctionComponent = (props) => { + + const savedSettings = props.settingsName && props.settings.tables[props.settingsName]; + + const [checkedColumns, setCheckedColumns] = React.useState<{ property: string, display: boolean, title: string | undefined }[]>([]); + + const open = Boolean(props.anchorEl); + const allColumnNames = props.columns.map(e => e.property); + + React.useEffect(() => { + + createHideShowSelection(); + + }, []); + + React.useEffect(() => { + + createHideShowSelection(); + + }, [props.settings.isInitialLoadDone]); + + + const createHideShowSelection = () => { + let columns = props.columns.map(e => { return { property: e.property, display: !Boolean(e.hide), title: e.title } }); + + + if (savedSettings) { + + if (columns.length !== savedSettings.columns.length) { + console.error("saved column length does not match current column length. Maybe a settings entry got wrongly overridden?") + } + + //overwrite column data with settings + savedSettings?.columns.forEach(el => { + let foundIndex = columns.findIndex(e => e.property == el.property); + if (columns[foundIndex] !== undefined) + columns[foundIndex].display = el.displayed; + }); + + } else { + console.warn("No settingsName set, changes will not be saved.") + } + + setCheckedColumns(columns); + + const hideColumns = columns.filter(el => !el.display).map(e => e.property); + props.hideColumns(hideColumns); + } + + + const handleChange = (propertyName: string, checked: boolean) => { + if (!checked) { + props.hideColumns([propertyName]); + } else { + props.showColumns([propertyName]) + + } + + let updatedList = checkedColumns.map(item => { + if (item.property == propertyName) { + return { ...item, display: checked }; + } + return item; + }); + + setCheckedColumns(updatedList); + }; + + const onHideAll = () => { + + switchCheckedColumns(false); + props.hideColumns(allColumnNames); + } + + const onShowAll = () => { + + switchCheckedColumns(true); + props.showColumns(allColumnNames); + } + + const onClose = () => { + + const tableColumns: TableSettingsColumn[] = checkedColumns.map(el => { + return { + property: el.property, + displayed: el.display + } + }); + + if (props.settingsName) { + props.saveToSettings(props.settingsName, tableColumns); + } + props.onClose(); + + } + + const switchCheckedColumns = (changeToValue: boolean) => { + let updatedList = checkedColumns.map(item => { + return { ...item, display: changeToValue }; + }); + + setCheckedColumns(updatedList); + + } + + return ( +
+ Hide / Show Columns +
+
+ { + checkedColumns?.map((el, i) => { + + return <> + + handleChange(el.property, e.target.checked)} />} + label={el.title || el.property} + labelPlacement="end" + /> + + }) + } +
+ + +
+
+
) +} + +export default connect(mapStateToProps, mapDispatchToProps)(ShowColumnsDialog); diff --git a/sdnr/wt/odlux/framework/src/components/material-table/tableFilter.tsx b/sdnr/wt/odlux/framework/src/components/material-table/tableFilter.tsx index a46dd18d8..1b9136844 100644 --- a/sdnr/wt/odlux/framework/src/components/material-table/tableFilter.tsx +++ b/sdnr/wt/odlux/framework/src/components/material-table/tableFilter.tsx @@ -50,6 +50,7 @@ interface IEnhancedTableFilterComponentProps extends WithStyles { onFilterChanged: (property: string, filterTerm: string) => void; filter: { [property: string]: string }; columns: ColumnModel<{}>[]; + hiddenColumns: string[]; enableSelection?: boolean; } @@ -73,7 +74,7 @@ class EnhancedTableFilterComponent extends React.Component { const style = col.width ? { width: col.width } : {}; - return ( + const tableCell = ( } ); + + const showColumn = !this.props.hiddenColumns.includes(col.property); + + return showColumn && tableCell; }, this)} ); diff --git a/sdnr/wt/odlux/framework/src/components/material-table/tableHead.tsx b/sdnr/wt/odlux/framework/src/components/material-table/tableHead.tsx index c500f44ce..d6f7b7def 100644 --- a/sdnr/wt/odlux/framework/src/components/material-table/tableHead.tsx +++ b/sdnr/wt/odlux/framework/src/components/material-table/tableHead.tsx @@ -50,7 +50,9 @@ interface IEnhancedTableHeadComponentProps extends styles_header { orderBy: string | null; rowCount: number; columns: ColumnModel<{}>[]; + hiddenColumns: string[]; enableSelection?: boolean; + allowHtmlHeader?: boolean; } class EnhancedTableHeadComponent extends React.Component { @@ -77,7 +79,7 @@ class EnhancedTableHeadComponent extends React.Component { const style = col.width ? { width: col.width } : {}; - return ( + const tableCell = ( - { col.title || col.property } + { + this.props.allowHtmlHeader ?
+ : (col.title || col.property ) + } }
); + + //show column if... + const showColumn = !this.props.hiddenColumns.includes(col.property); + + return showColumn && tableCell; }, this) } diff --git a/sdnr/wt/odlux/framework/src/components/material-table/tableToolbar.tsx b/sdnr/wt/odlux/framework/src/components/material-table/tableToolbar.tsx index 426436d44..143b802a4 100644 --- a/sdnr/wt/odlux/framework/src/components/material-table/tableToolbar.tsx +++ b/sdnr/wt/odlux/framework/src/components/material-table/tableToolbar.tsx @@ -33,6 +33,8 @@ import MenuItem from '@mui/material/MenuItem'; import Menu from '@mui/material/Menu'; import { SvgIconProps } from '@mui/material/SvgIcon'; import { Button } from '@mui/material'; +import { ColumnModel } from './columnModel'; +import ShowColumnsDialog from './showColumnDialog' const styles = (theme: Theme) => createStyles({ root: { @@ -69,18 +71,24 @@ const styles = (theme: Theme) => createStyles({ interface ITableToolbarComponentProps extends WithStyles { numSelected: number | null; title?: string; - tableId?: string; + tableId: string | null; customActionButtons?: { icon: React.ComponentType, tooltip?: string, ariaLabel: string, onClick: () => void, disabled?: boolean }[]; + columns: ColumnModel<{}>[]; + onHideColumns: (columnNames: string[]) => void + onShowColumns: (columnNames: string[]) => void onToggleFilter: () => void; onExportToCsv: () => void; } -class TableToolbarComponent extends React.Component { +class TableToolbarComponent extends React.Component { + + constructor(props: ITableToolbarComponentProps) { super(props); this.state = { - anchorEl: null + anchorEl: null, + anchorElDialog: null }; } @@ -91,11 +99,22 @@ class TableToolbarComponent extends React.Component { this.setState({ anchorEl: null }); }; + + private showColumnsDialog = (event: React.MouseEvent) =>{ + this.setState({ anchorElDialog: this.state.anchorEl }); + } + + private onCloseDialog = () =>{ + this.setState({ anchorElDialog: null }); + + } + render() { const { numSelected, classes } = this.props; const open = !!this.state.anchorEl; - const buttonPrefix = this.props.tableId !== undefined ? this.props.tableId : 'table'; + const buttonPrefix = this.props.tableId !== null ? this.props.tableId : 'table'; return ( + <> 0 ? classes.highlight : ''} `} >
{numSelected && numSelected > 0 ? ( @@ -153,9 +172,18 @@ class TableToolbarComponent extends React.Component { this.props.onExportToCsv(); this.handleClose()}}>Export as CSV + { this.showColumnsDialog(e); this.handleClose()}}>Hide/show columns
+ + ); } } diff --git a/sdnr/wt/odlux/framework/src/components/material-table/utilities.ts b/sdnr/wt/odlux/framework/src/components/material-table/utilities.ts index 544e14e01..f9015493f 100644 --- a/sdnr/wt/odlux/framework/src/components/material-table/utilities.ts +++ b/sdnr/wt/odlux/framework/src/components/material-table/utilities.ts @@ -28,6 +28,7 @@ export interface IExternalTableState { order: 'asc' | 'desc'; orderBy: string | null; selected: any[] | null; + hiddenColumns: string[] rows: (TData & { [RowDisabled]?: boolean })[]; total: number; page: number; @@ -48,7 +49,9 @@ export type ExternalMethodes = { onFilterChanged: (property: string, filterTerm: string) => void; onHandleChangePage: (page: number) => void; onHandleChangeRowsPerPage: (rowsPerPage: number | null) => void; - }; + onHideColumns: (columnName: string[]) => void; + onShowColumns: (columnName: string[]) => void; + }, createPreActions: (dispatch: Dispatch, skipRefresh?: boolean) => { onPreFilterChanged: (preFilter: { [key: string]: string; @@ -128,6 +131,18 @@ export function createExternal(callback: DataCallback, selectState } } + class HideColumnsAction extends TableAction{ + constructor(public property: string[]){ + super(); + } + } + + class ShowColumnsAction extends TableAction{ + constructor(public property: string[]){ + super(); + } + } + // #endregion //#region Action Handler @@ -135,6 +150,7 @@ export function createExternal(callback: DataCallback, selectState order: 'asc', orderBy: null, selected: null, + hiddenColumns:[], rows: [], total: 0, page: 0, @@ -208,6 +224,18 @@ export function createExternal(callback: DataCallback, selectState rowsPerPage: action.rowsPerPage } } + else if (action instanceof HideColumnsAction){ + + //merge arrays, remove duplicates + const newArray = [...new Set([...state.hiddenColumns, ...action.property])] + state = {...state, hiddenColumns: newArray}; + } + else if(action instanceof ShowColumnsAction){ + + const newArray = state.hiddenColumns.filter(el=> !action.property.includes(el)); + state = {...state, hiddenColumns: newArray}; + } + return state; } @@ -290,6 +318,16 @@ export function createExternal(callback: DataCallback, selectState dispatch(new SetRowsPerPageAction(rowsPerPage || 10)); (!skipRefresh) && dispatch(reloadAction); }); + }, + onHideColumns: (columnName: string[]) =>{ + dispatch((dispatch: Dispatch) => { + dispatch(new HideColumnsAction(columnName)); + }) + }, + onShowColumns: (columnName: string[]) =>{ + dispatch((dispatch: Dispatch) => { + dispatch(new ShowColumnsAction(columnName)); + }) } // selected: }; diff --git a/sdnr/wt/odlux/framework/src/components/navigationMenu.tsx b/sdnr/wt/odlux/framework/src/components/navigationMenu.tsx index 1134e230b..195706d28 100644 --- a/sdnr/wt/odlux/framework/src/components/navigationMenu.tsx +++ b/sdnr/wt/odlux/framework/src/components/navigationMenu.tsx @@ -64,9 +64,9 @@ const styles = (theme: Theme) => createStyles({ duration: theme.transitions.duration.leavingScreen, }), overflowX: 'hidden', - width: theme.spacing(7) + 1, + width: theme.spacing(7), [theme.breakpoints.up('sm')]: { - width: theme.spacing(9) + 1, + width: theme.spacing(9), }, }, drawer: { @@ -101,7 +101,7 @@ export const NavigationMenu = withStyles(styles)(connect()(({ classes, state, di //collapse menu on mount if necessary React.useEffect(()=>{ - if(isOpen && window.innerWidth < tabletWidthBreakpoint){ + if(isOpen && window.innerWidth <= tabletWidthBreakpoint){ setResponsive(true); dispatch(new MenuAction(false)); @@ -116,14 +116,12 @@ export const NavigationMenu = withStyles(styles)(connect()(({ classes, state, di if (window.innerWidth < tabletWidthBreakpoint && !responsive) { setResponsive(true); if (!closedByUser) { - console.log("responsive menu collapsed") dispatch(new MenuAction(false)); } } else if (window.innerWidth > tabletWidthBreakpoint && responsive) { setResponsive(false); if (!closedByUser) { - console.log("responsive menu restored") dispatch(new MenuAction(true)); } @@ -145,13 +143,14 @@ export const NavigationMenu = withStyles(styles)(connect()(({ classes, state, di let menuItems = state.framework.applicationRegistraion && Object.keys(state.framework.applicationRegistraion).map(key => { const reg = state.framework.applicationRegistraion[key]; + const icon = !reg.icon ? null :( typeof reg.icon === 'string' ? : ) return reg && ( || null} /> + icon={icon} /> ) || null; }) || null; diff --git a/sdnr/wt/odlux/framework/src/components/titleBar.tsx b/sdnr/wt/odlux/framework/src/components/titleBar.tsx index 7872e51da..19d3bdf74 100644 --- a/sdnr/wt/odlux/framework/src/components/titleBar.tsx +++ b/sdnr/wt/odlux/framework/src/components/titleBar.tsx @@ -131,6 +131,10 @@ class TitleBarComponent extends React.Component : ) + + return ( @@ -144,9 +148,7 @@ class TitleBarComponent extends React.Component - {state.framework.applicationState.icon - ? () - : null} + {icon} {state.framework.applicationState.title}
diff --git a/sdnr/wt/odlux/framework/src/handlers/applicationStateHandler.ts b/sdnr/wt/odlux/framework/src/handlers/applicationStateHandler.ts index 16c6ed5d3..d0a07248d 100644 --- a/sdnr/wt/odlux/framework/src/handlers/applicationStateHandler.ts +++ b/sdnr/wt/odlux/framework/src/handlers/applicationStateHandler.ts @@ -31,8 +31,8 @@ import { ExternalLoginProvider } from '../models/externalLoginProvider'; import { ApplicationConfig } from '../models/applicationConfig'; import { IConnectAppStoreState } from '../../../apps/connectApp/src/handlers/connectAppRootHandler'; import { IFaultAppStoreState } from '../../../apps/faultApp/src/handlers/faultAppRootHandler'; -import { GeneralSettings } from '../models/settings'; -import { SetGeneralSettingsAction } from '../actions/settingsAction'; +import { GeneralSettings, Settings } from '../models/settings'; +import { LoadSettingsAction, SetGeneralSettingsAction, SetTableSettings, SettingsDoneLoadingAction } from '../actions/settingsAction'; import { startWebsocketSession, suspendWebsocketSession } from '../services/notificationService'; @@ -55,7 +55,7 @@ export interface IApplicationState { authentication: "basic"|"oauth", // basic enablePolicy: boolean, // false transportpceUrl : string, - settings: GeneralSettings + settings: Settings & { isInitialLoadDone: boolean } } const applicationStateInit: IApplicationState = { @@ -69,7 +69,11 @@ const applicationStateInit: IApplicationState = { authentication: "basic", enablePolicy: false, transportpceUrl: "", - settings:{ general: { areNotificationsEnabled: null }} + settings:{ + general: { areNotificationsEnabled: null }, + tables: {}, + isInitialLoadDone: false + } }; export const configureApplication = (config: ApplicationConfig) => { @@ -150,8 +154,23 @@ export const applicationStateHandler: IActionHandler = (state state = { ...state, - settings:{general:{areNotificationsEnabled: action.areNoticationsActive}} + settings:{tables: state.settings.tables, isInitialLoadDone:state.settings.isInitialLoadDone, general:{areNotificationsEnabled: action.areNoticationsActive}} } } + else if(action instanceof SetTableSettings){ + + let tableUpdate = state.settings.tables; + tableUpdate[action.tableName] = {columns: action.updatedColumns}; + + state = {...state, settings:{general: state.settings.general, isInitialLoadDone:state.settings.isInitialLoadDone, tables: tableUpdate}} + + }else if(action instanceof LoadSettingsAction){ + + state = {...state, settings:action.settings} + } + else if(action instanceof SettingsDoneLoadingAction){ + state= {...state, settings: {...state.settings, isInitialLoadDone: true}} + } + return state; }; diff --git a/sdnr/wt/odlux/framework/src/handlers/authenticationHandler.ts b/sdnr/wt/odlux/framework/src/handlers/authenticationHandler.ts index 1bcb43528..f98d77487 100644 --- a/sdnr/wt/odlux/framework/src/handlers/authenticationHandler.ts +++ b/sdnr/wt/odlux/framework/src/handlers/authenticationHandler.ts @@ -39,12 +39,8 @@ export const authenticationStateHandler: IActionHandler = const {user} = action; if (user) { - localStorage.setItem("userToken", user.toString()); - startUserSession(user); onLogin(); } else { - localStorage.removeItem("userToken"); - endUserSession(); onLogout(); } diff --git a/sdnr/wt/odlux/framework/src/index.dev.html b/sdnr/wt/odlux/framework/src/index.dev.html index 4dc353c44..69c5f0607 100644 --- a/sdnr/wt/odlux/framework/src/index.dev.html +++ b/sdnr/wt/odlux/framework/src/index.dev.html @@ -26,7 +26,7 @@ faultApp.register(); // inventoryApp.register(); // helpApp.register(); - app("./app.tsx").configureApplication({ authentication:"oauth", enablePolicy: false, transportpceUrl:"http://test.de"}); + app("./app.tsx").configureApplication({ authentication:"basic", enablePolicy: false, transportpceUrl:"http://test.de"}); app("./app.tsx").runApplication(); }); diff --git a/sdnr/wt/odlux/framework/src/index.html b/sdnr/wt/odlux/framework/src/index.html index 5cd2805c1..7196b5cfe 100644 --- a/sdnr/wt/odlux/framework/src/index.html +++ b/sdnr/wt/odlux/framework/src/index.html @@ -16,7 +16,7 @@