Skip to content

Commit

Permalink
feat(ui): Collapsable sidebar with filters (argoproj#10626)
Browse files Browse the repository at this point in the history
Signed-off-by: Remington Breeze <[email protected]>
  • Loading branch information
rbreeze authored Sep 29, 2022
1 parent 3960cfd commit 856ba52
Show file tree
Hide file tree
Showing 18 changed files with 402 additions and 175 deletions.
32 changes: 9 additions & 23 deletions ui/src/app/app.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {DataLoader, Layout, NavigationManager, Notifications, NotificationsManager, PageContext, Popup, PopupManager, PopupProps, Tooltip} from 'argo-ui';
import {DataLoader, NavigationManager, Notifications, NotificationsManager, PageContext, Popup, PopupManager, PopupProps} from 'argo-ui';
import {createBrowserHistory} from 'history';
import * as PropTypes from 'prop-types';
import * as React from 'react';
Expand All @@ -8,6 +8,7 @@ import applications from './applications';
import help from './help';
import login from './login';
import settings from './settings';
import {Layout} from './shared/components/layout/layout';
import {VersionPanel} from './shared/components/version-info/version-info-panel';
import {Provider} from './shared/context';
import {services} from './shared/services';
Expand All @@ -32,12 +33,14 @@ const routes: {[path: string]: {component: React.ComponentType<RouteComponentPro

const navItems = [
{
title: 'Manage your applications, and diagnose health problems.',
title: 'Applications',
tooltip: 'Manage your applications, and diagnose health problems.',
path: '/applications',
iconClassName: 'argo-icon-application'
},
{
title: 'Manage your repositories, projects, settings',
title: 'Settings',
tooltip: 'Manage your repositories, projects, settings',
path: '/settings',
iconClassName: 'argo-icon-settings'
},
Expand All @@ -47,7 +50,8 @@ const navItems = [
iconClassName: 'fa fa-user-circle'
},
{
title: 'Read the documentation, and get help and assistance.',
title: 'Documentation',
tooltip: 'Read the documentation, and get help and assistance.',
path: '/help',
iconClassName: 'argo-icon-docs'
}
Expand Down Expand Up @@ -186,25 +190,7 @@ export class App extends React.Component<{}, {popupProps: PopupProps; showVersio
) : (
<DataLoader load={() => services.viewPreferences.getPreferences()}>
{pref => (
<Layout
navItems={navItems}
theme={pref.theme}
version={() => (
<DataLoader load={() => versionLoader}>
{version => {
const versionString = version ? version.Version : 'Unknown';
return (
<React.Fragment>
<Tooltip content={versionString}>
<a style={{color: 'white'}} onClick={() => this.setState({showVersionPanel: true})}>
{versionString}
</a>
</Tooltip>
</React.Fragment>
);
}}
</DataLoader>
)}>
<Layout onVersionClick={() => this.setState({showVersionPanel: true})} navItems={navItems} theme={pref.theme}>
<Banner>
<route.component {...routeProps} />
</Banner>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
@import 'node_modules/argo-ui/src/styles/config';
@import 'node_modules/foundation-sites/scss/util/util';
@import '../../../shared/config.scss';

$header: 120px;

.application-details {
height: 100vh;
width: 100%;
&__status-panel {
position: fixed;
left: 60px;
left: $sidebar-width;
right: 0;
z-index: 3;
@media screen and (max-width: map-get($breakpoints, xlarge)) {
Expand All @@ -23,7 +25,6 @@ $header: 120px;
}

&__tree {
position: relative;
padding: 1em;
overflow-x: auto;
overflow-y: auto;
Expand Down Expand Up @@ -203,11 +204,6 @@ $header: 120px;
.filters-group__panel {
top: 230px;
}
@include breakpoint(large down) {
.filters-group__panel {
top: 280px;
}
}

.graph-options-panel {
margin-left: 10px;
Expand All @@ -217,7 +213,7 @@ $header: 120px;
background-color: $argo-color-gray-1;
box-shadow: 1px 1px 3px $argo-color-gray-5;
position: fixed;

a {
padding: 5px;
margin: 2px;
Expand All @@ -235,24 +231,24 @@ $header: 120px;
line-height: 1.4;
text-align: center;
user-select: none;
transition: background-color .2s, border .2s, color .2s;
transition: background-color 0.2s, border 0.2s, color 0.2s;
text-transform: uppercase;
&:hover {
background-color: #d1d5d9;
}
&:active {
transition: background-color .2s, border .2s, color .2s;
transition: background-color 0.2s, border 0.2s, color 0.2s;
border: 1px $argo-color-teal-5 solid;
}
}

&.group-nodes-button-on {
color: $argo-color-gray-1;
background-color: $argo-color-gray-6;
&:hover {
background-color: $argo-color-gray-5;
}
}
}
}

.separator {
Expand All @@ -275,5 +271,5 @@ $header: 120px;
padding: 2px;
color: $argo-color-gray-7;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {DropDownMenu, NotificationType, SlidingPanel} from 'argo-ui';
import * as classNames from 'classnames';
import * as PropTypes from 'prop-types';
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import * as models from '../../../shared/models';
import {RouteComponentProps} from 'react-router';
import {BehaviorSubject, combineLatest, from, merge, Observable} from 'rxjs';
Expand All @@ -22,10 +23,11 @@ import {ApplicationSyncPanel} from '../application-sync-panel/application-sync-p
import {ResourceDetails} from '../resource-details/resource-details';
import * as AppUtils from '../utils';
import {ApplicationResourceList} from './application-resource-list';
import {Filters} from './application-resource-filter';
import {Filters, FiltersProps} from './application-resource-filter';
import {urlPattern} from '../utils';
import {ResourceStatus} from '../../../shared/models';
import {ApplicationsDetailsAppDropdown} from './application-details-app-dropdown';
import {useSidebarTarget} from '../../../sidebar/sidebar';

require('./application-details.scss');

Expand All @@ -47,6 +49,11 @@ interface FilterInput {
namespace: string[];
}

const ApplicationDetailsFilters = (props: FiltersProps) => {
const sidebarTarget = useSidebarTarget();
return ReactDOM.createPortal(<Filters {...props} />, sidebarTarget?.current);
};

export const NodeInfo = (node?: string): {key: string; container: number} => {
const nodeContainer = {key: '', container: 0};
if (node) {
Expand Down Expand Up @@ -353,7 +360,19 @@ export class ApplicationDetails extends React.Component<RouteComponentProps<{app
<div className='application-details__tree'>
{refreshing && <p className='application-details__refreshing-label'>Refreshing</p>}
{((pref.view === 'tree' || pref.view === 'network') && (
<Filters pref={pref} tree={tree} resourceNodes={this.state.filteredGraph} onSetFilter={setFilter} onClearFilter={clearFilter}>
<>
<DataLoader load={() => services.viewPreferences.getPreferences()}>
{viewPref => (
<ApplicationDetailsFilters
pref={pref}
tree={tree}
onSetFilter={setFilter}
onClearFilter={clearFilter}
collapsed={viewPref.hideSidebar}
resourceNodes={this.state.filteredGraph}
/>
)}
</DataLoader>
<div className='graph-options-panel'>
<a
className={`group-nodes-button`}
Expand Down Expand Up @@ -416,7 +435,7 @@ export class ApplicationDetails extends React.Component<RouteComponentProps<{app
setNodeExpansion={(node, isExpanded) => this.setNodeExpansion(node, isExpanded)}
getNodeExpansion={node => this.getNodeExpansion(node)}
/>
</Filters>
</>
)) ||
(pref.view === 'pods' && (
<PodView
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,17 @@ function toOption(label: string) {
return {label};
}

export const Filters = (props: {
export interface FiltersProps {
children?: React.ReactNode;
pref: AppDetailsPreferences;
tree: ApplicationTree;
resourceNodes: models.ResourceStatus[];
onSetFilter: (items: string[]) => void;
onClearFilter: () => void;
}) => {
collapsed?: boolean;
}

export const Filters = (props: FiltersProps) => {
const ctx = React.useContext(Context);

const {pref, tree, onSetFilter} = props;
Expand All @@ -31,9 +34,6 @@ export const Filters = (props: {
props.onClearFilter();
};

const shown = pref.hideFilters;
const setShown = (val: boolean) => services.viewPreferences.updatePreferences({appDetails: {...pref, hideFilters: val}});

const resourceFilter = pref.resourceFilter || [];
const removePrefix = (prefix: string) => (v: string) => v.replace(prefix + ':', '');

Expand Down Expand Up @@ -121,7 +121,7 @@ export const Filters = (props: {
};

return (
<FiltersGroup content={props.children} appliedFilter={pref.resourceFilter} onClearFilter={onClearFilter} setShown={setShown} expanded={shown}>
<FiltersGroup content={props.children} appliedFilter={pref.resourceFilter} onClearFilter={onClearFilter} collapsed={props.collapsed}>
{ResourceFilter({label: 'NAME', prefix: 'name', options: names.map(toOption), field: true})}
{ResourceFilter({
label: 'KINDS',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ interface AppFilterProps {
pref: AppsListPreferences;
onChange: (newPrefs: AppsListPreferences) => void;
children?: React.ReactNode;
collapsed?: boolean;
}

const getCounts = (apps: FilteredApp[], filterType: keyof FilterResult, filter: (app: Application) => string, init?: string[]) => {
Expand Down Expand Up @@ -216,17 +217,20 @@ const NamespaceFilter = (props: AppFilterProps) => {

const FavoriteFilter = (props: AppFilterProps) => {
const ctx = React.useContext(Context);
const onChange = (val: boolean) => {
ctx.navigation.goto('.', {showFavorites: val}, {replace: true});
services.viewPreferences.updatePreferences({appList: {...props.pref, showFavorites: val}});
};
return (
<div className={`filter filter__item ${props.pref.showFavorites ? 'filter__item--selected' : ''}`}>
<div
className={`filter filter__item ${props.pref.showFavorites ? 'filter__item--selected' : ''}`}
style={{margin: '0.5em 0'}}
onClick={() => onChange(!props.pref.showFavorites)}>
<Checkbox
value={!!props.pref.showFavorites}
onChange={val => {
ctx.navigation.goto('.', {showFavorites: val}, {replace: true});
services.viewPreferences.updatePreferences({appList: {...props.pref, showFavorites: val}});
}}
onChange={onChange}
style={{
marginRight: '8px',
marginLeft: '8px'
marginRight: '8px'
}}
/>
<div style={{marginRight: '5px'}}>
Expand All @@ -238,12 +242,8 @@ const FavoriteFilter = (props: AppFilterProps) => {
};

export const ApplicationsFilter = (props: AppFilterProps) => {
const setShown = (val: boolean) => {
services.viewPreferences.updatePreferences({appList: {...props.pref, hideFilters: !val}});
};

return (
<FiltersGroup setShown={setShown} expanded={!props.pref.hideFilters} content={props.children}>
<FiltersGroup content={props.children} collapsed={props.collapsed}>
<FavoriteFilter {...props} />
<SyncFilter {...props} />
<HealthFilter {...props} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
&__title {
font-weight: bolder;
font-size: 15px;
@include themify($themes) {
@include themify($themes) {
color: themed('text-1');
}
padding-top: 0.25em;
Expand Down Expand Up @@ -116,7 +116,7 @@

&__search {
border: 1px solid $argo-color-gray-4;
@include themify($themes){
@include themify($themes) {
background-color: themed('light-argo-gray-2');
}
border-radius: 7px;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {Autocomplete, ErrorNotification, MockupList, NotificationType, SlidingPanel, Toolbar, Tooltip} from 'argo-ui';
import * as classNames from 'classnames';
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import {Key, KeybindingContext, KeybindingProvider} from 'argo-ui/v2';
import {RouteComponentProps} from 'react-router';
import {combineLatest, from, merge, Observable} from 'rxjs';
Expand All @@ -19,6 +20,7 @@ import {ApplicationsSummary} from './applications-summary';
import {ApplicationsTable} from './applications-table';
import {ApplicationTiles} from './applications-tiles';
import {ApplicationsRefreshPanel} from '../applications-refresh-panel/applications-refresh-panel';
import {useSidebarTarget} from '../../../sidebar/sidebar';

require('./applications-list.scss');
require('./flex-top-bar.scss');
Expand Down Expand Up @@ -348,6 +350,8 @@ export const ApplicationsList = (props: RouteComponentProps<{}>) => {
return '';
}

const sidebarTarget = useSidebarTarget();

return (
<ClusterCtx.Provider value={clusters}>
<KeybindingProvider>
Expand Down Expand Up @@ -464,7 +468,21 @@ export const ApplicationsList = (props: RouteComponentProps<{}>) => {
</button>
</EmptyState>
) : (
<ApplicationsFilter apps={filterResults} onChange={newPrefs => onFilterPrefChanged(ctx, newPrefs)} pref={pref}>
<>
{ReactDOM.createPortal(
<DataLoader load={() => services.viewPreferences.getPreferences()}>
{allpref => (
<ApplicationsFilter
apps={filterResults}
onChange={newPrefs => onFilterPrefChanged(ctx, newPrefs)}
pref={pref}
collapsed={allpref.hideSidebar}
/>
)}
</DataLoader>,
sidebarTarget?.current
)}

{(pref.view === 'summary' && <ApplicationsSummary applications={filteredApps} />) || (
<Paginate
header={filteredApps.length > 1 && <ApplicationsStatusBar applications={filteredApps} />}
Expand Down Expand Up @@ -515,7 +533,7 @@ export const ApplicationsList = (props: RouteComponentProps<{}>) => {
}
</Paginate>
)}
</ApplicationsFilter>
</>
)}
<ApplicationsSyncPanel
key='syncsPanel'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
@import 'node_modules/foundation-sites/scss/util/util';
@import '../../../shared/config.scss';

.flex-top-bar {
position: fixed;
left: 60px;
right: 0;
z-index: 5;
padding: 0 15px;
left: $sidebar-width;
align-items: center;
flex-wrap: wrap;
&__actions {
Expand All @@ -28,6 +29,7 @@
flex-wrap: wrap;
}
}

&__padder {
height: 50px;
@include breakpoint(medium down) {
Expand Down
Loading

0 comments on commit 856ba52

Please sign in to comment.