From ce78a6683ab8648ed90e944cd23ed7c01205fce6 Mon Sep 17 00:00:00 2001 From: Aijana Schumann Date: Fri, 13 Mar 2020 10:39:11 +0100 Subject: Fix odlux bugs Fix help and about app not scrollable Fix filter hiding and showing without user interaction and default sort in all tables Issue-ID: SDNC-1117 Signed-off-by: Aijana Schumann Change-Id: I5c6ff86c73a3b222a8d9022125454788496f6399 --- sdnr/wt/odlux/framework/pom.xml | 2 +- .../src/components/material-table/index.tsx | 6 +- .../src/components/material-table/utilities.ts | 27 ++++- .../src/components/material-ui/treeView.tsx | 120 ++++++++++++++++----- .../framework/src/components/navigationMenu.tsx | 32 +++++- sdnr/wt/odlux/framework/src/index.dev.html | 6 ++ sdnr/wt/odlux/framework/src/views/about.tsx | 14 ++- sdnr/wt/odlux/framework/src/views/frame.tsx | 1 - 8 files changed, 167 insertions(+), 41 deletions(-) (limited to 'sdnr/wt/odlux/framework') diff --git a/sdnr/wt/odlux/framework/pom.xml b/sdnr/wt/odlux/framework/pom.xml index 967ca2a7e..b7ea291eb 100644 --- a/sdnr/wt/odlux/framework/pom.xml +++ b/sdnr/wt/odlux/framework/pom.xml @@ -46,7 +46,7 @@ ${maven.build.timestamp} ONAP Frankfurt (Neon, mdsal ${odl.mdsal.version}) - 46.9d666e7(20/02/28) + 50.53aa73a(20/03/12) ONAP SDN-R | ONF Wireless for ${distversion} - Build: ${buildtime} ${buildno} ${project.version} 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 a80a5a58d..3dfbe0b91 100644 --- a/sdnr/wt/odlux/framework/src/components/material-table/index.tsx +++ b/sdnr/wt/odlux/framework/src/components/material-table/index.tsx @@ -111,6 +111,8 @@ type MaterialTableComponentBaseProps = WithStyles & { tableId?: string; title?: string; stickyHeader?: boolean; + defaultSortOrder?: 'asc' | 'desc'; + defaultSortColumn?: keyof TData; enableSelection?: boolean; disableSorting?: boolean; disableFilter?: boolean; @@ -164,8 +166,8 @@ class MaterialTableComponent extends React.Component(callback: DataCallback, selectState } } + class RequestExplicitSortAction extends TableAction { + constructor(public propertyName: string, public sortOrder: "asc" | "desc") { + super(); + } + } + class SetSelectedAction extends TableAction { constructor(public selected: TData[] | null) { super(); @@ -136,7 +142,15 @@ export function createExternal(callback: DataCallback, selectState orderBy: state.orderBy === action.orderBy && state.order === 'desc' ? null : action.orderBy, order: state.orderBy === action.orderBy && state.order === 'asc' ? 'desc' : 'asc', } - } else if (action instanceof SetShowFilterAction) { + } else if (action instanceof RequestExplicitSortAction) { + state = { + ...state, + loading: true, + orderBy: action.propertyName, + order: action.sortOrder + } + } + else if (action instanceof SetShowFilterAction) { state = { ...state, loading: true, @@ -239,11 +253,18 @@ export function createExternal(callback: DataCallback, selectState (!skipRefresh) && dispatch(reloadAction); }); }, - onToggleFilter: () => { + onHandleExplicitRequestSort: (property: string, sortOrder: "asc" | "desc") => { + dispatch((dispatch: Dispatch) => { + dispatch(new RequestExplicitSortAction(property, sortOrder)); + (!skipRefresh) && dispatch(reloadAction); + }); + }, + onToggleFilter: (refresh?: boolean) => { dispatch((dispatch: Dispatch, getAppState: () => IApplicationStoreState) => { const { showFilter } = selectState(getAppState()); dispatch(new SetShowFilterAction(!showFilter)); - (!skipRefresh) && dispatch(reloadAction); + if (!skipRefresh && (refresh === undefined || refresh)) + dispatch(reloadAction); }); }, onFilterChanged: (property: string, filterTerm: string) => { diff --git a/sdnr/wt/odlux/framework/src/components/material-ui/treeView.tsx b/sdnr/wt/odlux/framework/src/components/material-ui/treeView.tsx index 98ee291d1..1bb49367c 100644 --- a/sdnr/wt/odlux/framework/src/components/material-ui/treeView.tsx +++ b/sdnr/wt/odlux/framework/src/components/material-ui/treeView.tsx @@ -37,6 +37,11 @@ const styles = (theme: Theme) => createStyles({ } }); +export enum SearchMode { + OnKeyDown = 1, + OnEnter =2 +} + export type TreeItem = { disabled?: boolean; icon?: React.ComponentType; @@ -47,13 +52,19 @@ export type TreeItem = { value?: TData; } +export type ExternalTreeItem = TreeItem & { + isMatch?: boolean; +} + + type TreeViewComponentState = { /** All indices of all expanded Items */ - expandedItems: TreeItem[]; + expandedItems: ExternalTreeItem[]; /** The index of the active iten or undefined if no item is active. */ - activeItem: undefined | TreeItem; + activeItem?: ExternalTreeItem; /** The search term or undefined if search is corrently not active. */ - searchTerm: undefined | string; + searchTerm?: string; + searchTermValue?: string; } type TreeViewComponentBaseProps = WithTheme & WithStyles & { @@ -65,6 +76,7 @@ type TreeViewComponentBaseProps = WithTheme & WithStyles = TreeViewComponentBaseProps & { @@ -72,7 +84,17 @@ type TreeViewComponentWithInternalStateProps = TreeViewComponentBas onFolderClick?: (item: TreeItem) => void; } -type TreeViewComponentWithExternalStateProps = TreeViewComponentBaseProps & TreeViewComponentState & { +type TreeViewComponentWithExternalSearchProps = TreeViewComponentBaseProps & { + items: ExternalTreeItem[]; + searchTerm: string; + onSearch: (searchTerm: string) => void; + onItemClick?: (item: TreeItem) => void; + onFolderClick?: (item: TreeItem) => void; +} + +type TreeViewComponentWithExternalStateProps = TreeViewComponentBaseProps & TreeViewComponentState & { + items: ExternalTreeItem[]; + searchTerm: string; onSearch: (searchTerm: string) => void; onItemClick: (item: TreeItem) => void; onFolderClick: (item: TreeItem) => void; @@ -80,14 +102,25 @@ type TreeViewComponentWithExternalStateProps = TreeViewComponentBas type TreeViewComponentProps = | TreeViewComponentWithInternalStateProps + | TreeViewComponentWithExternalSearchProps | TreeViewComponentWithExternalStateProps; +function isTreeViewComponentWithExternalSearchProps(props: TreeViewComponentProps): props is TreeViewComponentWithExternalSearchProps { + const propsWithExternalState = (props as TreeViewComponentWithExternalStateProps) + return ( + propsWithExternalState.onSearch instanceof Function && + propsWithExternalState.onFolderClick === undefined && + propsWithExternalState.expandedItems === undefined && + propsWithExternalState.searchTerm !== undefined + ); +} + function isTreeViewComponentWithExternalStateProps(props: TreeViewComponentProps): props is TreeViewComponentWithExternalStateProps { const propsWithExternalState = (props as TreeViewComponentWithExternalStateProps) return ( - propsWithExternalState.onSearch instanceof Function || - propsWithExternalState.expandedItems !== undefined || - propsWithExternalState.activeItem !== undefined || + propsWithExternalState.onSearch instanceof Function && + propsWithExternalState.onFolderClick instanceof Function && + propsWithExternalState.expandedItems !== undefined && propsWithExternalState.searchTerm !== undefined ); } @@ -103,19 +136,20 @@ class TreeViewComponent extends React.Component {children} - {enableSearchBar && || null} + {enableSearchBar && || null} {this.renderItems(items, searchTerm && searchTerm.toLowerCase())} @@ -124,20 +158,21 @@ class TreeViewComponent extends React.Component[], searchTerm: string | undefined, depth: number = 1) => { + private renderItems = (items: TreeItem[], searchTerm: string | undefined, depth: number = 1, forceRender: boolean = true) => { + return items.reduce((acc, item) => { const children = item.children; // this.props.childrenProperty && ((item as any)[this.props.childrenProperty] as TData[]); - const childrenJsx = children && this.renderItems(children, searchTerm, depth + 1); + const childrenJsx = children && this.renderItems(children, searchTerm, depth + 1, this.state.expandedItems.indexOf(item) > -1); - const expanded = searchTerm + const expanded = !isTreeViewComponentWithExternalStateProps(this.props) && searchTerm ? childrenJsx && childrenJsx.length > 0 : !children ? false : this.state.expandedItems.indexOf(item) > -1; const isFolder = children !== undefined; - const itemJsx = this.renderItem(item, searchTerm, depth, isFolder, expanded || false); + const itemJsx = this.renderItem(item, searchTerm, depth, isFolder, expanded || false, forceRender); itemJsx && acc.push(itemJsx); if (isFolder && expanded && childrenJsx) { @@ -147,7 +182,7 @@ class TreeViewComponent extends React.Component, searchTerm: string | undefined, depth: number, isFolder: boolean, expanded: boolean): JSX.Element | null => { + private renderItem = (item: ExternalTreeItem, searchTerm: string | undefined, depth: number, isFolder: boolean, expanded: boolean, forceRender: boolean): JSX.Element | null => { const styles = { item: { paddingLeft: (((this.props.depthOffset || 0) + depth) * this.props.theme.spacing(3)), @@ -175,7 +210,7 @@ class TreeViewComponent extends React.Component -1 || expanded) || !searchTerm) + return ((searchTerm && (matchIndex > -1 || expanded || (!isTreeViewComponentWithExternalStateProps(this.props) && item.isMatch || depth === 1)) || !searchTerm || forceRender) ? ( @@ -186,7 +221,7 @@ class TreeViewComponent extends React.Component -1 - ? ( + ? {text.substring(0, matchIndex)} extends React.Component {text.substring(matchIndex + searchTermLength)} - ) - : () + )} /> + : + {text} + )} /> } { // display the right icon, depending on the state @@ -235,16 +277,39 @@ class TreeViewComponent extends React.Component) => { + const enterMode = this.props.searchMode === SearchMode.OnEnter; + + if (enterMode && event.keyCode === 13) { + event.preventDefault(); + event.stopPropagation(); + + enterMode && this.setState({ + searchTerm: this.state.searchTermValue + }); + + if (isTreeViewComponentWithExternalSearchProps(this.props) || isTreeViewComponentWithExternalStateProps(this.props)) { + this.props.onSearch(this.state.searchTermValue || ""); + } + } + } + private onChangeSearchText = (event: React.ChangeEvent) => { event.preventDefault(); event.stopPropagation(); - if (isTreeViewComponentWithExternalStateProps(this.props)) { - this.props.onSearch(event.target.value) - } else { - this.setState({ - searchTerm: event.target.value - }); + const keyDownMode = (!this.props.searchMode || this.props.searchMode === SearchMode.OnKeyDown); + + this.setState(keyDownMode + ? { + searchTerm: event.target.value, + searchTermValue: event.target.value, + } as any : { + searchTermValue: event.target.value, + }) as any; + + if ((isTreeViewComponentWithExternalSearchProps(this.props) || isTreeViewComponentWithExternalStateProps(this.props)) && keyDownMode) { + this.props.onSearch(event.target.value); } }; @@ -256,6 +321,11 @@ class TreeViewComponent extends React.Component createStyles({ drawerPaper: { position: 'relative', width: drawerWidth, }, toolbar: theme.mixins.toolbar as any, + drawerOpen: { width: drawerWidth, transition: theme.transitions.create('width', { @@ -58,7 +62,24 @@ const styles = (theme: Theme) => createStyles({ [theme.breakpoints.up('sm')]: { width: theme.spacing(9) + 1, }, - } + }, + drawer: { + + }, + menu: { + flex: "1 0 0%", + }, + optLinks: { + borderTop: "2px solid #cfcfcf", + display: "flex", + flexDirection: "row", + flexWrap: "wrap", + justifyContent: "space-around" + }, + link: { + margin: theme.spacing(1)+1, + fontSize: theme.typography.fontSize-2, + }, }); const tabletWidthBreakpoint = 768; @@ -103,7 +124,7 @@ export const NavigationMenu = withStyles(styles)(connect()(({ classes, state, di
{ /* https://fiffty.github.io/react-treeview-mui/ */} - + } /> { @@ -141,6 +162,9 @@ export const NavigationMenu = withStyles(styles)(connect()(({ classes, state, di : null } + {isOpen && extraLinks &&
+ {extraLinks.map(linkInfo => ({linkInfo[0]}))} +
|| null} || null } ) diff --git a/sdnr/wt/odlux/framework/src/index.dev.html b/sdnr/wt/odlux/framework/src/index.dev.html index 71cb7408d..240da266d 100644 --- a/sdnr/wt/odlux/framework/src/index.dev.html +++ b/sdnr/wt/odlux/framework/src/index.dev.html @@ -13,6 +13,12 @@
+