Skip to content

Commit

Permalink
Add indeterminate state to Checkbox, cleanup bulk actions selection l…
Browse files Browse the repository at this point in the history
…ogic
  • Loading branch information
tlrobinson committed Jun 14, 2018
1 parent 9145799 commit fe58b61
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 35 deletions.
2 changes: 1 addition & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"trailing-comma": "all"
"trailingComma": "all"
}
26 changes: 15 additions & 11 deletions frontend/src/metabase/components/CheckBox.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand All @@ -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 (
<div
Expand All @@ -52,13 +55,14 @@ export default class CheckBox extends Component {
style={checkboxStyle}
className="flex align-center justify-center rounded"
>
{checked && (
<Icon
style={{ color: checked ? "white" : themeColor }}
name="check"
size={size - padding * 2}
/>
)}
{(checked || indeterminate) &&
!noIcon && (
<Icon
style={{ color: checked ? "white" : uncheckedColor }}
name={indeterminate ? "dash" : "check"}
size={size - padding * 2}
/>
)}
</div>
</div>
);
Expand Down
49 changes: 27 additions & 22 deletions frontend/src/metabase/components/CollectionLanding.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -159,15 +168,10 @@ class DefaultLanding extends React.Component {
<Box>
<CollectionLoader collectionId={collectionId}>
{({ object: collection }) => {
if (items.length === 0) {
if (pinned.length === 0 && unpinned.length === 0) {
return <CollectionEmptyState />;
}

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,
Expand Down Expand Up @@ -587,7 +591,6 @@ const PINNABLE_ENTITY_TYPES = new Set(["questions", "dashboards"]);
class PinPositionDropTarget extends React.Component {
render() {
const {
index,
left,
right,
connectDropTarget,
Expand Down Expand Up @@ -750,9 +753,11 @@ const SelectionControls = ({
onSelectNone,
}) =>
deselected.length === 0 ? (
<StackedCheckBox checked={true} onChange={onSelectNone} />
<StackedCheckBox checked onChange={onSelectNone} />
) : selected.length === 0 ? (
<StackedCheckBox onChange={onSelectAll} />
) : (
<StackedCheckBox checked={false} onChange={onSelectAll} />
<StackedCheckBox checked indeterminate onChange={onSelectAll} />
);

// TODO - this should be a selector
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/metabase/components/StackedCheckBox.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const StackedCheckBox = props => (
zIndex: -1,
}}
>
<CheckBox {...props} />
<CheckBox {...props} noIcon />
</span>
<CheckBox {...props} />
</div>
Expand Down
1 change: 1 addition & 0 deletions frontend/src/metabase/icon_paths.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit fe58b61

Please sign in to comment.