From fe58b613e0ebb1fc9d9de4d70ead9b0f4f7bbbb5 Mon Sep 17 00:00:00 2001 From: Tom Robinson Date: Thu, 14 Jun 2018 13:25:08 -0700 Subject: [PATCH] Add indeterminate state to Checkbox, cleanup bulk actions selection logic --- .prettierrc | 2 +- frontend/src/metabase/components/CheckBox.jsx | 26 +++++----- .../metabase/components/CollectionLanding.jsx | 49 ++++++++++--------- .../metabase/components/StackedCheckBox.jsx | 2 +- frontend/src/metabase/icon_paths.js | 1 + 5 files changed, 45 insertions(+), 35 deletions(-) diff --git a/.prettierrc b/.prettierrc index f1ce769cc165c..bf357fbbc081d 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,3 +1,3 @@ { - "trailing-comma": "all" + "trailingComma": "all" } diff --git a/frontend/src/metabase/components/CheckBox.jsx b/frontend/src/metabase/components/CheckBox.jsx index 4a76ed419b485..b1ab71d20b52f 100644 --- a/frontend/src/metabase/components/CheckBox.jsx +++ b/frontend/src/metabase/components/CheckBox.jsx @@ -7,10 +7,12 @@ import { normal as defaultColors } from "metabase/lib/colors"; export default class CheckBox extends Component { static propTypes = { checked: PropTypes.bool, + indeterminate: PropTypes.bool, onChange: PropTypes.func, color: PropTypes.oneOf(Object.keys(defaultColors)), size: PropTypes.number, // TODO - this should probably be a concrete set of options padding: PropTypes.number, // TODO - the component should pad itself properly based on the size + noIcon: PropTypes.bool, }; static defaultProps = { @@ -31,15 +33,16 @@ export default class CheckBox extends Component { } render() { - const { checked, color, padding, size } = this.props; + const { checked, indeterminate, color, padding, size, noIcon } = this.props; - const themeColor = defaultColors[color]; + const checkedColor = defaultColors[color]; + const uncheckedColor = "#ddd"; const checkboxStyle = { width: size, height: size, - backgroundColor: checked ? themeColor : "white", - border: `2px solid ${checked ? themeColor : "#ddd"}`, + backgroundColor: checked ? checkedColor : "white", + border: `2px solid ${checked ? checkedColor : uncheckedColor}`, }; return (
- {checked && ( - - )} + {(checked || indeterminate) && + !noIcon && ( + + )}
); diff --git a/frontend/src/metabase/components/CollectionLanding.jsx b/frontend/src/metabase/components/CollectionLanding.jsx index 45c26ba13a45f..0d7c8b8d9e4f8 100644 --- a/frontend/src/metabase/components/CollectionLanding.jsx +++ b/frontend/src/metabase/components/CollectionLanding.jsx @@ -104,7 +104,23 @@ const ROW_HEIGHT = 72; entityQuery: (state, props) => ({ collection: props.collectionId }), wrapped: true, }) -@listSelect({ keyForItem: item => `${item.entity_type}:${item.id}` }) +@connect((state, props) => { + // split out collections, pinned, and unpinned since bulk actions only apply to unpinned + const [collections, items] = _.partition( + props.list || [], + item => item.entity_type === "collections", + ); + const [pinned, unpinned] = _.partition( + items, + item => item.collection_position != null, + ); + return { collections, pinned, unpinned }; +}) +// only apply bulk actions to unpinned items +@listSelect({ + listProp: "unpinned", + keyForItem: item => `${item.entity_type}:${item.id}`, +}) class DefaultLanding extends React.Component { state = { moveItems: null, @@ -113,9 +129,12 @@ class DefaultLanding extends React.Component { render() { const { collectionId, - list, - onToggleSelected, + collections, + pinned, + unpinned, + selected, selection, + onToggleSelected, onSelectNone, } = this.props; const { moveItems } = this.state; @@ -128,16 +147,6 @@ class DefaultLanding extends React.Component { onSelectNone(); }; - // exclude collections from selection since they can't currently be selected - const selected = this.props.selected.filter( - item => item.model !== "collection", - ); - - const [collections, items] = _.partition( - list, - item => item.entity_type === "collections", - ); - // Show the const showCollectionList = collectionId === "root" || collections.length > 0; @@ -159,15 +168,10 @@ class DefaultLanding extends React.Component { {({ object: collection }) => { - if (items.length === 0) { + if (pinned.length === 0 && unpinned.length === 0) { return ; } - const [pinned, unpinned] = _.partition( - items, - i => i.collection_position != null, - ); - // sort the pinned items by collection_position pinned.sort( (a, b) => a.collection_position - b.collection_position, @@ -587,7 +591,6 @@ const PINNABLE_ENTITY_TYPES = new Set(["questions", "dashboards"]); class PinPositionDropTarget extends React.Component { render() { const { - index, left, right, connectDropTarget, @@ -750,9 +753,11 @@ const SelectionControls = ({ onSelectNone, }) => deselected.length === 0 ? ( - + + ) : selected.length === 0 ? ( + ) : ( - + ); // TODO - this should be a selector diff --git a/frontend/src/metabase/components/StackedCheckBox.jsx b/frontend/src/metabase/components/StackedCheckBox.jsx index f265e6af62907..c7549d230a139 100644 --- a/frontend/src/metabase/components/StackedCheckBox.jsx +++ b/frontend/src/metabase/components/StackedCheckBox.jsx @@ -13,7 +13,7 @@ const StackedCheckBox = props => ( zIndex: -1, }} > - + diff --git a/frontend/src/metabase/icon_paths.js b/frontend/src/metabase/icon_paths.js index 7ca1ed6511783..d3b5c6d8b0df3 100644 --- a/frontend/src/metabase/icon_paths.js +++ b/frontend/src/metabase/icon_paths.js @@ -110,6 +110,7 @@ export const ICON_PATHS = { "M27,19 C25.3431458,19 24,17.6568542 24,16 C24,14.3431458 25.3431458,13 27,13 C28.6568542,13 30,14.3431458 30,16 C30,17.6568542 28.6568542,19 27,19 Z M16,8 C14.3431458,8 13,6.65685425 13,5 C13,3.34314575 14.3431458,2 16,2 C17.6568542,2 19,3.34314575 19,5 C19,6.65685425 17.6568542,8 16,8 Z M16,30 C14.3431458,30 13,28.6568542 13,27 C13,25.3431458 14.3431458,24 16,24 C17.6568542,24 19,25.3431458 19,27 C19,28.6568542 17.6568542,30 16,30 Z M5,19 C3.34314575,19 2,17.6568542 2,16 C2,14.3431458 3.34314575,13 5,13 C6.65685425,13 8,14.3431458 8,16 C8,17.6568542 6.65685425,19 5,19 Z M16,19 C14.3431458,19 13,17.6568542 13,16 C13,14.3431458 14.3431458,13 16,13 C17.6568542,13 19,14.3431458 19,16 C19,17.6568542 17.6568542,19 16,19 Z M10,12 C8.8954305,12 8,11.1045695 8,10 C8,8.8954305 8.8954305,8 10,8 C11.1045695,8 12,8.8954305 12,10 C12,11.1045695 11.1045695,12 10,12 Z M22,12 C20.8954305,12 20,11.1045695 20,10 C20,8.8954305 20.8954305,8 22,8 C23.1045695,8 24,8.8954305 24,10 C24,11.1045695 23.1045695,12 22,12 Z M22,24 C20.8954305,24 20,23.1045695 20,22 C20,20.8954305 20.8954305,20 22,20 C23.1045695,20 24,20.8954305 24,22 C24,23.1045695 23.1045695,24 22,24 Z M10,24 C8.8954305,24 8,23.1045695 8,22 C8,20.8954305 8.8954305,20 10,20 C11.1045695,20 12,20.8954305 12,22 C12,23.1045695 11.1045695,24 10,24 Z", database: "M1.18285296e-08,10.5127919 C-1.47856568e-08,7.95412848 1.18285298e-08,4.57337284 1.18285298e-08,4.57337284 C1.18285298e-08,4.57337284 1.58371041,5.75351864e-10 15.6571342,0 C29.730558,-5.7535027e-10 31.8900148,4.13849684 31.8900148,4.57337284 L31.8900148,10.4843058 C31.8900148,10.4843058 30.4448001,15.1365942 16.4659751,15.1365944 C2.48715012,15.1365947 2.14244494e-08,11.4353349 1.18285296e-08,10.5127919 Z M0.305419478,21.1290071 C0.305419478,21.1290071 0.0405133833,21.2033291 0.0405133833,21.8492606 L0.0405133833,27.3032816 C0.0405133833,27.3032816 1.46515486,31.941655 15.9641228,31.941655 C30.4630908,31.941655 32,27.3446712 32,27.3446712 C32,27.3446712 32,21.7986104 32,21.7986105 C32,21.2073557 31.6620557,21.0987647 31.6620557,21.0987647 C31.6620557,21.0987647 29.7146434,25.22314 16.0318829,25.22314 C2.34912233,25.22314 0.305419478,21.1290071 0.305419478,21.1290071 Z M0.305419478,12.656577 C0.305419478,12.656577 0.0405133833,12.730899 0.0405133833,13.3768305 L0.0405133833,18.8308514 C0.0405133833,18.8308514 1.46515486,23.4692249 15.9641228,23.4692249 C30.4630908,23.4692249 32,18.8722411 32,18.8722411 C32,18.8722411 32,13.3261803 32,13.3261803 C32,12.7349256 31.6620557,12.6263346 31.6620557,12.6263346 C31.6620557,12.6263346 29.7146434,16.7507099 16.0318829,16.7507099 C2.34912233,16.7507099 0.305419478,12.656577 0.305419478,12.656577 Z", + dash: "M0 13h32v6.61H0z", dashboard: "M32 28a4 4 0 0 1-4 4H4a4.002 4.002 0 0 1-3.874-3H0V4a4 4 0 0 1 4-4h25a3 3 0 0 1 3 3v25zm-4 0V8H4v20h24zM7.273 18.91h10.182v4.363H7.273v-4.364zm0-6.82h17.454v4.365H7.273V12.09zm13.09 6.82h4.364v4.363h-4.363v-4.364z", curve: