Skip to content
This repository was archived by the owner on May 30, 2025. It is now read-only.

Commit fe58b61

Browse files
committed
Add indeterminate state to Checkbox, cleanup bulk actions selection logic
1 parent 9145799 commit fe58b61

File tree

5 files changed

+45
-35
lines changed

5 files changed

+45
-35
lines changed

.prettierrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
"trailing-comma": "all"
2+
"trailingComma": "all"
33
}

frontend/src/metabase/components/CheckBox.jsx

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@ import { normal as defaultColors } from "metabase/lib/colors";
77
export default class CheckBox extends Component {
88
static propTypes = {
99
checked: PropTypes.bool,
10+
indeterminate: PropTypes.bool,
1011
onChange: PropTypes.func,
1112
color: PropTypes.oneOf(Object.keys(defaultColors)),
1213
size: PropTypes.number, // TODO - this should probably be a concrete set of options
1314
padding: PropTypes.number, // TODO - the component should pad itself properly based on the size
15+
noIcon: PropTypes.bool,
1416
};
1517

1618
static defaultProps = {
@@ -31,15 +33,16 @@ export default class CheckBox extends Component {
3133
}
3234

3335
render() {
34-
const { checked, color, padding, size } = this.props;
36+
const { checked, indeterminate, color, padding, size, noIcon } = this.props;
3537

36-
const themeColor = defaultColors[color];
38+
const checkedColor = defaultColors[color];
39+
const uncheckedColor = "#ddd";
3740

3841
const checkboxStyle = {
3942
width: size,
4043
height: size,
41-
backgroundColor: checked ? themeColor : "white",
42-
border: `2px solid ${checked ? themeColor : "#ddd"}`,
44+
backgroundColor: checked ? checkedColor : "white",
45+
border: `2px solid ${checked ? checkedColor : uncheckedColor}`,
4346
};
4447
return (
4548
<div
@@ -52,13 +55,14 @@ export default class CheckBox extends Component {
5255
style={checkboxStyle}
5356
className="flex align-center justify-center rounded"
5457
>
55-
{checked && (
56-
<Icon
57-
style={{ color: checked ? "white" : themeColor }}
58-
name="check"
59-
size={size - padding * 2}
60-
/>
61-
)}
58+
{(checked || indeterminate) &&
59+
!noIcon && (
60+
<Icon
61+
style={{ color: checked ? "white" : uncheckedColor }}
62+
name={indeterminate ? "dash" : "check"}
63+
size={size - padding * 2}
64+
/>
65+
)}
6266
</div>
6367
</div>
6468
);

frontend/src/metabase/components/CollectionLanding.jsx

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,23 @@ const ROW_HEIGHT = 72;
104104
entityQuery: (state, props) => ({ collection: props.collectionId }),
105105
wrapped: true,
106106
})
107-
@listSelect({ keyForItem: item => `${item.entity_type}:${item.id}` })
107+
@connect((state, props) => {
108+
// split out collections, pinned, and unpinned since bulk actions only apply to unpinned
109+
const [collections, items] = _.partition(
110+
props.list || [],
111+
item => item.entity_type === "collections",
112+
);
113+
const [pinned, unpinned] = _.partition(
114+
items,
115+
item => item.collection_position != null,
116+
);
117+
return { collections, pinned, unpinned };
118+
})
119+
// only apply bulk actions to unpinned items
120+
@listSelect({
121+
listProp: "unpinned",
122+
keyForItem: item => `${item.entity_type}:${item.id}`,
123+
})
108124
class DefaultLanding extends React.Component {
109125
state = {
110126
moveItems: null,
@@ -113,9 +129,12 @@ class DefaultLanding extends React.Component {
113129
render() {
114130
const {
115131
collectionId,
116-
list,
117-
onToggleSelected,
132+
collections,
133+
pinned,
134+
unpinned,
135+
selected,
118136
selection,
137+
onToggleSelected,
119138
onSelectNone,
120139
} = this.props;
121140
const { moveItems } = this.state;
@@ -128,16 +147,6 @@ class DefaultLanding extends React.Component {
128147
onSelectNone();
129148
};
130149

131-
// exclude collections from selection since they can't currently be selected
132-
const selected = this.props.selected.filter(
133-
item => item.model !== "collection",
134-
);
135-
136-
const [collections, items] = _.partition(
137-
list,
138-
item => item.entity_type === "collections",
139-
);
140-
141150
// Show the
142151
const showCollectionList =
143152
collectionId === "root" || collections.length > 0;
@@ -159,15 +168,10 @@ class DefaultLanding extends React.Component {
159168
<Box>
160169
<CollectionLoader collectionId={collectionId}>
161170
{({ object: collection }) => {
162-
if (items.length === 0) {
171+
if (pinned.length === 0 && unpinned.length === 0) {
163172
return <CollectionEmptyState />;
164173
}
165174

166-
const [pinned, unpinned] = _.partition(
167-
items,
168-
i => i.collection_position != null,
169-
);
170-
171175
// sort the pinned items by collection_position
172176
pinned.sort(
173177
(a, b) => a.collection_position - b.collection_position,
@@ -587,7 +591,6 @@ const PINNABLE_ENTITY_TYPES = new Set(["questions", "dashboards"]);
587591
class PinPositionDropTarget extends React.Component {
588592
render() {
589593
const {
590-
index,
591594
left,
592595
right,
593596
connectDropTarget,
@@ -750,9 +753,11 @@ const SelectionControls = ({
750753
onSelectNone,
751754
}) =>
752755
deselected.length === 0 ? (
753-
<StackedCheckBox checked={true} onChange={onSelectNone} />
756+
<StackedCheckBox checked onChange={onSelectNone} />
757+
) : selected.length === 0 ? (
758+
<StackedCheckBox onChange={onSelectAll} />
754759
) : (
755-
<StackedCheckBox checked={false} onChange={onSelectAll} />
760+
<StackedCheckBox checked indeterminate onChange={onSelectAll} />
756761
);
757762

758763
// TODO - this should be a selector

frontend/src/metabase/components/StackedCheckBox.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ const StackedCheckBox = props => (
1313
zIndex: -1,
1414
}}
1515
>
16-
<CheckBox {...props} />
16+
<CheckBox {...props} noIcon />
1717
</span>
1818
<CheckBox {...props} />
1919
</div>

frontend/src/metabase/icon_paths.js

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)