feat(xod-client): show/hide deprecated patches in the ProjectBrowser by toggling filter option

This commit is contained in:
Kirill Shumilov
2018-03-19 20:07:49 +03:00
parent 3a7c919f69
commit 459498cfc2
10 changed files with 93 additions and 65 deletions

View File

@@ -1,52 +0,0 @@
.PanelToolbar {
display: block;
height: 24px;
overflow: hidden;
box-sizing: border-box;
background-color: $chrome-title-bg;
button {
display: inline-block;
box-sizing: border-box;
width: 24px;
height: 24px;
padding: 0;
text-align: center;
vertical-align: middle;
line-height: 1;
background: none;
border: none;
outline: none;
cursor: pointer;
color: $sidebar-color-text;
&:hover, &:focus {
color: $sidebar-color-text-hover;
}
&.addlib{
@extend .icon-addlib;
}
&.newpatch{
@extend .icon-newpatch;
}
&.contextmenu {
@extend .icon-contextmenu;
}
}
&-title {
font-size: $font-size-m;
color: $light-grey-bright;
float: left;
line-height: 18px;
padding: 3px;
}
&-buttons {
float: right;
}
}

View File

@@ -50,6 +50,9 @@
&.newpatch{
@extend .icon-newpatch;
}
&.filter {
@extend .icon-filter;
}
&.contextmenu {
@extend .icon-contextmenu;
opacity: 0.7;

View File

@@ -36,7 +36,6 @@
'components/Modals',
'components/Node',
'components/NoPatch',
'components/PanelToolbar',
'components/PatchDocs',
'components/PatchGroup',
'components/PatchGroupItem',

View File

@@ -4,3 +4,5 @@ export const PATCH_DELETE_REQUESTED = 'PATCH_DELETE_REQUESTED';
export const SET_SELECTION = 'SET_SELECTION';
export const REMOVE_SELECTION = 'REMOVE_SELECTION';
export const TOGGLE_DEPRECATED_FILTER = 'TOGGLE_DEPRECATED_FILTER';

View File

@@ -6,6 +6,7 @@ import {
PATCH_DELETE_REQUESTED,
SET_SELECTION,
REMOVE_SELECTION,
TOGGLE_DEPRECATED_FILTER,
} from './actionTypes';
import { getSelectedPatchPath } from './selectors';
@@ -49,3 +50,7 @@ export const setSelection = selectedPatchPath => ({
export const removeSelection = () => ({
type: REMOVE_SELECTION,
});
export const toggleDeprecatedFilter = () => ({
type: TOGGLE_DEPRECATED_FILTER,
});

View File

@@ -1,3 +1,4 @@
// Id of context menu to show it
// eslint-disable-next-line import/prefer-default-export
export const PATCH_GROUP_CONTEXT_MENU_ID = 'PATCH_GROUP_CONTEXT_MENU_ID';
export const FILTER_CONTEXT_MENU_ID = 'FILTER_CONTEXT_MENU_ID';

View File

@@ -5,7 +5,7 @@ import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { Icon } from 'react-fa';
import { HotKeys } from 'react-hotkeys';
import { ContextMenuTrigger } from 'react-contextmenu';
import { ContextMenuTrigger, ContextMenu, MenuItem } from 'react-contextmenu';
import $ from 'sanctuary-def';
import {
@@ -14,6 +14,7 @@ import {
isPathLocal,
getBaseName,
PatchPath,
isDeprecatedPatch,
} from 'xod-project';
import { isAmong, notEquals, $Maybe, foldMaybe } from 'xod-func-tools';
@@ -36,16 +37,23 @@ import PatchGroupItem from '../components/PatchGroupItem';
import ProjectBrowserPopups from '../components/ProjectBrowserPopups';
import PatchGroupItemContextMenu from '../components/PatchGroupItemContextMenu';
import { PATCH_GROUP_CONTEXT_MENU_ID } from '../constants';
import {
PATCH_GROUP_CONTEXT_MENU_ID,
FILTER_CONTEXT_MENU_ID,
} from '../constants';
import { PANEL_IDS, SIDEBAR_IDS } from '../../editor/constants';
import { triggerUpdateHelpboxPositionViaProjectBrowser } from '../../editor/utils';
const pickPatchPartsForComparsion = R.map(R.pick(['dead', 'path']));
const pickPatchPartsForComparsion = R.map(
R.pick(['deprecated', 'dead', 'path'])
);
const checkmark = active => (active ? <span className="state"></span> : null);
const pickPropsForComparsion = R.compose(
R.evolve({
localPatches: pickPatchPartsForComparsion,
libs: pickPatchPartsForComparsion,
libs: R.map(pickPatchPartsForComparsion),
}),
R.omit(['actions'])
);
@@ -178,9 +186,11 @@ class ProjectBrowser extends React.Component {
const collectPropsFn = this.getCollectPropsFn(path);
const key = `${path}${deprecated ? '_deprecated' : ''}`;
return (
<PatchGroupItem
key={path}
key={key}
patchPath={path}
dead={dead}
label={getBaseName(path)}
@@ -235,6 +245,14 @@ class ProjectBrowser extends React.Component {
);
const installingLibNames = R.pluck('name', installingLibsComponents);
// Rejecting of deprecated patches is implemented in the
// component for better performance.
// :: { LibName: [Patch] } -> { LibName: [Patch] }
const rejectDeprecatedPatches = R.unless(
() => this.props.showDeprecated,
R.map(R.reject(isDeprecatedPatch))
);
const libComponents = R.compose(
R.reject(R.compose(isAmong(installingLibNames), R.prop('name'))),
R.map(([libName, libPatches]) => ({
@@ -250,7 +268,8 @@ class ProjectBrowser extends React.Component {
</PatchGroup>
),
})),
R.toPairs
R.toPairs,
rejectDeprecatedPatches
)(libs);
return R.compose(
@@ -283,6 +302,17 @@ class ProjectBrowser extends React.Component {
title="Add library"
onClick={this.onClickAddLibrary}
/>,
<ContextMenuTrigger
id={FILTER_CONTEXT_MENU_ID}
key="contextMenuTrigger"
renderTag="button"
attributes={{
className: 'filter',
}}
holdToDisplay={0}
>
<span />
</ContextMenuTrigger>,
];
}
@@ -323,6 +353,12 @@ class ProjectBrowser extends React.Component {
onPatchRename={this.props.actions.requestRename}
onPatchHelp={this.onPatchHelpClicked}
/>
<ContextMenu id={FILTER_CONTEXT_MENU_ID}>
<MenuItem onClick={this.props.actions.toggleDeprecatedFilter}>
{checkmark(this.props.showDeprecated)}
Deprecated nodes
</MenuItem>
</ContextMenu>
</HotKeys>
);
}
@@ -342,6 +378,7 @@ ProjectBrowser.propTypes = {
defaultNodePosition: PropTypes.object.isRequired,
sidebarId: PropTypes.oneOf(R.values(SIDEBAR_IDS)).isRequired,
autohide: PropTypes.bool.isRequired,
showDeprecated: PropTypes.bool.isRequired,
actions: PropTypes.shape({
addNode: PropTypes.func.isRequired,
switchPatch: PropTypes.func.isRequired,
@@ -357,6 +394,7 @@ ProjectBrowser.propTypes = {
closeAllPopups: PropTypes.func.isRequired,
showLibSuggester: PropTypes.func.isRequired,
showHelpbox: PropTypes.func.isRequired,
toggleDeprecatedFilter: PropTypes.func.isRequired,
}),
};
@@ -370,6 +408,7 @@ const mapStateToProps = R.applySpec({
libs: ProjectBrowserSelectors.getLibs,
installingLibs: ProjectBrowserSelectors.getInstallingLibraries,
defaultNodePosition: EditorSelectors.getDefaultNodePlacePosition,
showDeprecated: ProjectBrowserSelectors.shouldShowDeprecatedPatches,
});
const mapDispatchToProps = dispatch => ({
@@ -395,6 +434,8 @@ const mapDispatchToProps = dispatch => ({
addNotification: MessagesActions.addNotification,
showLibSuggester: EditorActions.showLibSuggester,
showHelpbox: EditorActions.showHelpbox,
toggleDeprecatedFilter: ProjectBrowserActions.toggleDeprecatedFilter,
},
dispatch
),

View File

@@ -7,6 +7,7 @@ import {
PATCH_DELETE_REQUESTED,
SET_SELECTION,
REMOVE_SELECTION,
TOGGLE_DEPRECATED_FILTER,
} from './actionTypes';
import { PATCH_DELETE, PATCH_RENAME } from '../project/actionTypes';
@@ -17,6 +18,7 @@ import {
INSTALL_LIBRARIES_FAILED,
} from '../editor/actionTypes';
// Reducers
const selectionReducer = (state, action) => {
switch (action.type) {
case SET_SELECTION:
@@ -52,9 +54,19 @@ const installingLibrariesReducer = (state, action) => {
}
};
const filtersReducer = (state, action) => {
switch (action.type) {
case TOGGLE_DEPRECATED_FILTER:
return R.over(R.lensProp('deprecated'), R.not, state);
default:
return state;
}
};
export default (state = initialState, action) =>
R.merge(state, {
selectedPatchPath: selectionReducer(state.selectedPatchPath, action),
filters: filtersReducer(state.filters, action),
installingLibraries: installingLibrariesReducer(
state.installingLibraries,
action

View File

@@ -10,6 +10,11 @@ import { isPatchDeadTerminal } from '../project/utils';
export const getProjectBrowser = R.prop('projectBrowser');
export const shouldShowDeprecatedPatches = createSelector(
getProjectBrowser,
R.path(['filters', 'deprecated'])
);
export const getSelectedPatchPath = createSelector(
getProjectBrowser,
R.prop('selectedPatchPath')
@@ -29,14 +34,23 @@ const markDeadPatches = R.curry((project, patch) =>
)(patch, project)
);
export const getLocalPatches = createSelector(
// :: Patch -> Patch
const markDeprecatedPatches = patch =>
R.assoc('deprecated', XP.isDeprecatedPatch(patch), patch);
const getLocalPatchesList = createSelector(
ProjectSelectors.getProject,
project =>
XP.listLocalPatches
);
export const getLocalPatches = createMemoizedSelector(
[getLocalPatchesList, ProjectSelectors.getProject],
[R.equals],
(patches, project) =>
R.compose(
R.sortBy(XP.getPatchPath),
R.map(markDeadPatches(project)),
XP.listLocalPatches
)(project)
R.map(R.compose(markDeprecatedPatches, markDeadPatches(project)))
)(patches)
);
// TODO: this is not actually label anymore
@@ -63,7 +77,7 @@ export const getLibs = createMemoizedSelector(
R.map(R.sort(R.ascend(XP.getPatchPath))),
R.groupBy(R.pipe(XP.getPatchPath, XP.getLibraryName)),
R.reject(isPatchDeadTerminal),
R.map(markDeadPatches(project))
R.map(R.compose(markDeprecatedPatches, markDeadPatches(project)))
)(patches)
);

View File

@@ -1,4 +1,7 @@
export default {
selectedPatchPath: null,
filters: {
deprecated: false,
},
installingLibraries: [],
};