Skip to content

Commit 3e14a34

Browse files
committed
add "any"/"all" toggle to tags filter chip
1 parent e825da1 commit 3e14a34

File tree

2 files changed

+91
-22
lines changed

2 files changed

+91
-22
lines changed

frontend/src/features/crawl-workflows/workflow-tag-filter.ts

Lines changed: 62 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,17 @@ import { isFocusable } from "tabbable";
2222
import { BtrixElement } from "@/classes/BtrixElement";
2323
import type { BtrixChangeEvent } from "@/events/btrix-change";
2424
import { type WorkflowTag, type WorkflowTags } from "@/types/workflow";
25+
import { stopProp } from "@/utils/events";
2526
import { tw } from "@/utils/tailwind";
2627

2728
const MAX_TAGS_IN_LABEL = 5;
2829

29-
export type BtrixChangeWorkflowTagFilterEvent = BtrixChangeEvent<
30-
string[] | undefined
31-
>;
30+
type ChangeWorkflowTagEventDetails =
31+
| { tags: string[]; type: "and" | "or" }
32+
| undefined;
33+
34+
export type BtrixChangeWorkflowTagFilterEvent =
35+
BtrixChangeEvent<ChangeWorkflowTagEventDetails>;
3236

3337
/**
3438
* @fires btrix-change
@@ -52,8 +56,18 @@ export class WorkflowTagFilter extends BtrixElement {
5256
keys: ["tag"],
5357
});
5458

59+
@state()
60+
private get selectedTags() {
61+
return Array.from(this.selected.entries())
62+
.filter(([_tag, selected]) => selected)
63+
.map(([tag]) => tag);
64+
}
65+
5566
private selected = new Map<string, boolean>();
5667

68+
@state()
69+
private type: "and" | "or" = "or";
70+
5771
protected willUpdate(changedProperties: PropertyValues<this>): void {
5872
if (changedProperties.has("tags")) {
5973
if (this.tags) {
@@ -92,17 +106,17 @@ export class WorkflowTagFilter extends BtrixElement {
92106
@sl-after-hide=${() => {
93107
this.searchString = "";
94108
95-
const selectedTags = [];
96-
97-
for (const [tag, value] of this.selected) {
98-
if (value) {
99-
selectedTags.push(tag);
100-
}
101-
}
109+
console.log("after hide");
102110
103111
this.dispatchEvent(
104-
new CustomEvent<BtrixChangeEvent["detail"]>("btrix-change", {
105-
detail: { value: selectedTags.length ? selectedTags : undefined },
112+
new CustomEvent<
113+
BtrixChangeEvent<ChangeWorkflowTagEventDetails>["detail"]
114+
>("btrix-change", {
115+
detail: {
116+
value: this.selectedTags.length
117+
? { tags: this.selectedTags, type: this.type }
118+
: undefined,
119+
},
106120
}),
107121
);
108122
}}
@@ -141,23 +155,49 @@ export class WorkflowTagFilter extends BtrixElement {
141155
checkbox.checked = false;
142156
});
143157
158+
this.type = "or";
159+
144160
this.dispatchEvent(
145-
new CustomEvent<BtrixChangeEvent["detail"]>(
146-
"btrix-change",
147-
{
148-
detail: {
149-
value: undefined,
150-
},
161+
new CustomEvent<
162+
BtrixChangeEvent<ChangeWorkflowTagEventDetails>["detail"]
163+
>("btrix-change", {
164+
detail: {
165+
value: undefined,
151166
},
152-
),
167+
}),
153168
);
154169
}}
155170
>${msg("Clear")}</sl-button
156171
>`
157172
: nothing}
158173
</sl-menu-label>
159174
160-
<div class="px-3">${this.renderSearch()}</div>
175+
<div class="flex gap-2 px-3">
176+
${this.renderSearch()}
177+
<sl-radio-group
178+
size="small"
179+
value=${this.type}
180+
@sl-change=${(event: SlChangeEvent) => {
181+
this.type = (event.target as HTMLInputElement).value as
182+
| "or"
183+
| "and";
184+
}}
185+
@sl-after-hide=${stopProp}
186+
>
187+
<sl-tooltip hoist content=${msg("Any of the selected tags")}>
188+
<sl-radio-button value="or" checked>
189+
<sl-icon name="union" slot="prefix"></sl-icon>
190+
${msg("Any")}
191+
</sl-radio-button>
192+
</sl-tooltip>
193+
<sl-tooltip hoist content=${msg("All of the selected tags")}>
194+
<sl-radio-button value="and">
195+
<sl-icon name="intersect" slot="prefix"></sl-icon>
196+
${msg("All")}
197+
</sl-radio-button>
198+
</sl-tooltip>
199+
</sl-radio-group>
200+
</div>
161201
</header>
162202
163203
${this.orgTagsTask.render({
@@ -194,6 +234,7 @@ export class WorkflowTagFilter extends BtrixElement {
194234
),
195235
]
196236
: tags,
237+
{ type: this.type === "and" ? "conjunction" : "disjunction" },
197238
);
198239

199240
return formatter2.map((part, index, array) =>
@@ -266,6 +307,7 @@ export class WorkflowTagFilter extends BtrixElement {
266307
const { checked, value } = e.target as SlCheckbox;
267308
268309
this.selected.set(value, checked);
310+
this.requestUpdate("selectedTags");
269311
}}
270312
>
271313
${repeat(

frontend/src/pages/org/workflows-list.ts

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,9 @@ export class WorkflowsList extends BtrixElement {
132132
@state()
133133
private filterByTags?: string[];
134134

135+
@state()
136+
private filterByTagsType: "and" | "or" = "or";
137+
135138
@state()
136139
private filterByProfiles?: string[];
137140

@@ -190,6 +193,10 @@ export class WorkflowsList extends BtrixElement {
190193
this.filterByCurrentUser = value === "true";
191194
}
192195

196+
if (key === "tagsType") {
197+
this.filterByTagsType = value === "and" ? "and" : "or";
198+
}
199+
193200
// Sorting field
194201
if (key === "sortBy") {
195202
if (value in sortableFields) {
@@ -210,7 +217,18 @@ export class WorkflowsList extends BtrixElement {
210217
}
211218

212219
// Ignored params
213-
if (["page", "mine", "tags", "sortBy", "sortDir"].includes(key)) continue;
220+
if (
221+
[
222+
"page",
223+
"mine",
224+
"tags",
225+
"tagsType",
226+
"profiles",
227+
"sortBy",
228+
"sortDir",
229+
].includes(key)
230+
)
231+
continue;
214232

215233
// Convert string bools to filter values
216234
if (value === "true") {
@@ -249,6 +267,7 @@ export class WorkflowsList extends BtrixElement {
249267
const resetToFirstPageProps = [
250268
"filterByCurrentUser",
251269
"filterByTags",
270+
"filterByTagsType",
252271
"filterByProfiles",
253272
"filterByScheduled",
254273
"filterBy",
@@ -289,6 +308,7 @@ export class WorkflowsList extends BtrixElement {
289308
changedProperties.has("filterBy") ||
290309
changedProperties.has("filterByCurrentUser") ||
291310
changedProperties.has("filterByTags") ||
311+
changedProperties.has("filterByTagsType") ||
292312
changedProperties.has("filterByProfiles") ||
293313
changedProperties.has("orderBy")
294314
) {
@@ -308,6 +328,11 @@ export class WorkflowsList extends BtrixElement {
308328

309329
["tags", this.filterByTags],
310330

331+
[
332+
"tagsType",
333+
this.filterByTagsType !== "or" ? this.filterByTagsType : undefined,
334+
],
335+
311336
["profiles", this.filterByProfiles],
312337

313338
// Sorting fields
@@ -638,7 +663,8 @@ export class WorkflowsList extends BtrixElement {
638663
<btrix-workflow-tag-filter
639664
.tags=${this.filterByTags}
640665
@btrix-change=${(e: BtrixChangeWorkflowTagFilterEvent) => {
641-
this.filterByTags = e.detail.value;
666+
this.filterByTags = e.detail.value?.tags;
667+
this.filterByTagsType = e.detail.value?.type || "or";
642668
}}
643669
></btrix-workflow-tag-filter>
644670
@@ -995,6 +1021,7 @@ export class WorkflowsList extends BtrixElement {
9951021
INITIAL_PAGE_SIZE,
9961022
userid: this.filterByCurrentUser ? this.userInfo?.id : undefined,
9971023
tag: this.filterByTags || undefined,
1024+
tagMatch: this.filterByTagsType,
9981025
profileIds: this.filterByProfiles || undefined,
9991026
sortBy: this.orderBy.field,
10001027
sortDirection: this.orderBy.direction === "desc" ? -1 : 1,

0 commit comments

Comments
 (0)