Skip to content

Commit 973e316

Browse files
authored
Global exact match filters (#185)
* Add support for "contains exactly" column filter type in ResultsView component * steps to allow for Multiselect of values on filter * Canvas label dialog ux improvements (#187) * Add Callout to distinguish the action taking place * 1.16.0 * Add support for metaKey to navigate to canvas node * Update Kanban Cards to display selections (#182) * Update Kanban Cards to display selections * PR feedback: show selections by default * 1.17.0 * pr review, columnFilters to array, add multiselect * Add support for "contains exactly" column filter type in ResultsView component * steps to allow for Multiselect of values on filter * pr review, columnFilters to array, add multiselect * rm comment * Update Docs: add optional limit to<%QUERYBUILDER%> * Ability to add source to canvas node (#190) * init * add arrow to toolbar to add source to node * handle color with formatHexColor * update css * add nodeLabel to callout text * handle trimmed title comparison * update arrow label * . * . * update allFormatsWithReferencedNodes name and shape * PR Feedback * 1.18.0 * Add Sort to QB Menu (#192) * init * move resultHeaderSetActiveSort to ResultsView * set activeSort and blocks * init * move resultHeaderSetActiveSort to ResultsView * set activeSort and blocks * Update Docs: add optional limit to<%QUERYBUILDER%> * Ability to add source to canvas node (#190) * init * add arrow to toolbar to add source to node * handle color with formatHexColor * update css * add nodeLabel to callout text * handle trimmed title comparison * update arrow label * . * . * update allFormatsWithReferencedNodes name and shape * PR Feedback * 1.18.0 * init * move resultHeaderSetActiveSort to ResultsView * set activeSort and blocks * PR Feedback * Add support for "contains exactly" column filter type in ResultsView component * steps to allow for Multiselect of values on filter * pr review, columnFilters to array, add multiselect * steps to allow for Multiselect of values on filter * pr review, columnFilters to array, add multiselect * rm comment
1 parent 3b57472 commit 973e316

File tree

3 files changed

+104
-25
lines changed

3 files changed

+104
-25
lines changed

src/components/ResultsView.tsx

Lines changed: 93 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
Intent,
1212
Label,
1313
} from "@blueprintjs/core";
14+
import { MultiSelect } from "@blueprintjs/select";
1415
import getBasicTreeByParentUid from "roamjs-components/queries/getBasicTreeByParentUid";
1516
import { Filters } from "roamjs-components/components/Filter";
1617
import getSubTree from "roamjs-components/util/getSubTree";
@@ -36,6 +37,7 @@ import getFirstChildUidByBlockUid from "roamjs-components/queries/getFirstChildU
3637
import { Condition } from "../utils/types";
3738
import ResultsTable from "./ResultsTable";
3839
import { render as renderSimpleAlert } from "roamjs-components/components/SimpleAlert";
40+
import setInputSettings from "roamjs-components/util/setInputSettings";
3941

4042
const VIEWS: Record<string, { value: boolean }> = {
4143
link: { value: false },
@@ -170,7 +172,7 @@ const QueryUsed = ({ parentUid }: { parentUid: string }) => {
170172
);
171173
};
172174

173-
const SUPPORTED_COLUMN_FILTER_TYPES = [{ id: "contains" }];
175+
const SUPPORTED_COLUMN_FILTER_TYPES = [{ id: "contains" }, { id: "equals" }];
174176

175177
const SUPPORTED_LAYOUTS = [
176178
{
@@ -631,7 +633,10 @@ const ResultsView: ResultsViewComponent = ({
631633
</div>
632634
</div>
633635
) : isEditColumnFilter ? (
634-
<div className="relative w-80 p-2">
636+
<div
637+
className="relative p-2 max-w-2xl"
638+
style={{ minWidth: "320px" }}
639+
>
635640
<h4 className="font-bold flex justify-between items-center p-2">
636641
Set Filters
637642
<Button
@@ -646,7 +651,7 @@ const ResultsView: ResultsViewComponent = ({
646651
<div key={uid}>
647652
<div className="flex items-center justify-between gap-2 mb-2">
648653
<MenuItemSelect
649-
className="roamjs-column-filter-key flex-grow"
654+
className="roamjs-column-filter-key"
650655
items={columns.map((c) => c.key)}
651656
transformItem={(k) =>
652657
k.length > 10 ? `${k.slice(0, 7)}...` : k
@@ -662,7 +667,7 @@ const ResultsView: ResultsViewComponent = ({
662667
}}
663668
/>
664669
<MenuItemSelect
665-
className="roamjs-column-filter-type"
670+
className="roamjs-column-filter-type flex-grow"
666671
items={SUPPORTED_COLUMN_FILTER_TYPES.map(
667672
(c) => c.id
668673
)}
@@ -692,24 +697,89 @@ const ResultsView: ResultsViewComponent = ({
692697
/>
693698
</div>
694699
<div>
695-
<InputGroup
696-
className="roamjs-column-filter-value"
697-
value={value}
698-
placeholder="Type a value..."
699-
onChange={(e) => {
700-
const newValue = e.target.value;
701-
setColumnFilters(
702-
columnFilters.map((f) =>
703-
f.uid === uid ? { ...f, value: newValue } : f
700+
{type === "equals" ? (
701+
<MultiSelect
702+
popoverProps={{
703+
minimal: true,
704+
position: "bottom-left",
705+
boundary: "viewport",
706+
}}
707+
selectedItems={value.map((v) => v.toString())}
708+
tagRenderer={(tag) => tag}
709+
tagInputProps={{
710+
tagProps: { className: "max-w-lg" },
711+
}}
712+
itemRenderer={(item, props) => (
713+
<MenuItem
714+
key={item}
715+
text={item}
716+
active={props.modifiers.active}
717+
onClick={props.handleClick}
718+
/>
719+
)}
720+
items={Array.from(
721+
new Set(
722+
results
723+
.map((r) => r[key].toString())
724+
.filter((v) => !value.includes(v))
704725
)
705-
);
706-
setInputSetting({
707-
blockUid: uid,
708-
key: "value",
709-
value: newValue,
710-
});
711-
}}
712-
/>
726+
)}
727+
onRemove={(newValue) => {
728+
setColumnFilters(
729+
columnFilters.map((f) =>
730+
f.uid === uid
731+
? {
732+
...f,
733+
value: value.filter(
734+
(v) => v !== newValue
735+
),
736+
}
737+
: f
738+
)
739+
);
740+
setInputSettings({
741+
blockUid: uid,
742+
key: "value",
743+
values: value.filter((v) => v !== newValue),
744+
});
745+
}}
746+
onItemSelect={(newValue) => {
747+
setColumnFilters(
748+
columnFilters.map((f) =>
749+
f.uid === uid
750+
? { ...f, value: [...value, newValue] }
751+
: f
752+
)
753+
);
754+
setInputSettings({
755+
blockUid: uid,
756+
key: "value",
757+
values: [...value, newValue],
758+
});
759+
}}
760+
/>
761+
) : (
762+
<InputGroup
763+
className="roamjs-column-filter-value"
764+
value={value[0]}
765+
placeholder="Type a value..."
766+
onChange={(e) => {
767+
const newValue = e.target.value;
768+
setColumnFilters(
769+
columnFilters.map((f) =>
770+
f.uid === uid
771+
? { ...f, value: [newValue] }
772+
: f
773+
)
774+
);
775+
setInputSettings({
776+
blockUid: uid,
777+
key: "value",
778+
values: [newValue],
779+
});
780+
}}
781+
/>
782+
)}
713783
</div>
714784
</div>
715785
))}
@@ -720,7 +790,7 @@ const ResultsView: ResultsViewComponent = ({
720790
const newFilter = {
721791
key: columns[0].key,
722792
type: SUPPORTED_COLUMN_FILTER_TYPES[0].id,
723-
value: "",
793+
value: [""],
724794
uid: window.roamAlphaAPI.util.generateUID(),
725795
};
726796
setColumnFilters([...columnFilters, newFilter]);
@@ -741,7 +811,7 @@ const ResultsView: ResultsViewComponent = ({
741811
},
742812
{
743813
text: "value",
744-
children: [{ text: newFilter.value }],
814+
children: [{ text: newFilter.value[0] }],
745815
},
746816
],
747817
},

src/utils/parseResultSettings.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import toFlexRegex from "roamjs-components/util/toFlexRegex";
77
import { StoredFilters } from "../components/DefaultFilters";
88
import { Column } from "./types";
99
import getSettingValueFromTree from "roamjs-components/util/getSettingValueFromTree";
10+
import getSettingValuesFromTree from "roamjs-components/util/getSettingValuesFromTree";
1011

1112
export type Sorts = { key: string; descending: boolean }[];
1213
export type FilterData = Record<string, Filters>;
@@ -150,7 +151,7 @@ const parseResultSettings = (
150151
return {
151152
key: c.text,
152153
uid: c.uid,
153-
value: getSettingValueFromTree({ tree: c.children, key: "value" }),
154+
value: getSettingValuesFromTree({ tree: c.children, key: "value" }),
154155
type: getSettingValueFromTree({ tree: c.children, key: "type" }),
155156
};
156157
}),

src/utils/postProcessResults.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,15 @@ const postProcessResults = (
7474
const resultValue = r[columnFilter.key];
7575
const resultValueString =
7676
typeof resultValue === "string" ? resultValue : `${resultValue}`;
77-
return resultValueString.includes(columnFilter.value);
77+
return resultValueString.includes(columnFilter.value[0]);
78+
case "equals":
79+
if (
80+
columnFilter.value.length === 1 &&
81+
columnFilter.value[0] === ""
82+
) {
83+
return true;
84+
}
85+
return columnFilter.value.some((v) => r[columnFilter.key] === v);
7886
default:
7987
return true;
8088
}

0 commit comments

Comments
 (0)