Skip to content

Commit a548892

Browse files
committed
feat: implement AND mode for tags filtering
1 parent d23a742 commit a548892

File tree

2 files changed

+77
-40
lines changed

2 files changed

+77
-40
lines changed

frontend/src/ts/elements/account/result-filters.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -959,3 +959,7 @@ function verifyResultFiltersStructure(filterIn: ResultFilters): ResultFilters {
959959
});
960960
return filter;
961961
}
962+
963+
export function getTagsFilterMode(): "and" | "or" {
964+
return filters.tagsFilterMode;
965+
}

frontend/src/ts/pages/account.ts

Lines changed: 73 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,3 @@
1-
import * as DB from "../db";
2-
import * as ResultFilters from "../elements/account/result-filters";
3-
import * as ThemeColors from "../elements/theme-colors";
4-
import * as ChartController from "../controllers/chart-controller";
5-
import Config, * as UpdateConfig from "../config";
6-
import * as MiniResultChartModal from "../modals/mini-result-chart";
7-
import * as PbTables from "../elements/account/pb-tables";
8-
import * as LoadingPage from "./loading";
9-
import * as Focus from "../test/focus";
10-
import * as TodayTracker from "../test/today-tracker";
11-
import * as Notifications from "../elements/notifications";
12-
import Page from "./page";
13-
import * as DateTime from "../utils/date-and-time";
14-
import * as Misc from "../utils/misc";
15-
import * as Arrays from "../utils/arrays";
16-
import * as Numbers from "@monkeytype/util/numbers";
17-
import { get as getTypingSpeedUnit } from "../utils/typing-speed-units";
18-
import * as Profile from "../elements/profile";
19-
import { format } from "date-fns/format";
20-
import * as ConnectionState from "../states/connection";
21-
import * as Skeleton from "../utils/skeleton";
22-
import type { ScaleChartOptions, LinearScaleOptions } from "chart.js";
23-
import * as ConfigEvent from "../observables/config-event";
24-
import * as ActivePage from "../states/active-page";
25-
import { Auth } from "../firebase";
26-
import * as Loader from "../elements/loader";
27-
import * as ResultBatches from "../elements/result-batches";
28-
import Format from "../utils/format";
29-
import * as TestActivity from "../elements/test-activity";
301
import { ChartData } from "@monkeytype/contracts/schemas/results";
312
import {
323
Difficulty,
@@ -35,9 +6,38 @@ import {
356
Mode2Custom,
367
} from "@monkeytype/contracts/schemas/shared";
378
import { ResultFiltersGroupItem } from "@monkeytype/contracts/schemas/users";
38-
import { findLineByLeastSquares } from "../utils/numbers";
9+
import * as Numbers from "@monkeytype/util/numbers";
10+
import type { LinearScaleOptions, ScaleChartOptions } from "chart.js";
11+
import { format } from "date-fns/format";
12+
import Config, * as UpdateConfig from "../config";
3913
import defaultResultFilters from "../constants/default-result-filters";
4014
import { SnapshotResult } from "../constants/default-snapshot";
15+
import * as ChartController from "../controllers/chart-controller";
16+
import * as DB from "../db";
17+
import * as PbTables from "../elements/account/pb-tables";
18+
import * as ResultFilters from "../elements/account/result-filters";
19+
import * as Loader from "../elements/loader";
20+
import * as Notifications from "../elements/notifications";
21+
import * as Profile from "../elements/profile";
22+
import * as ResultBatches from "../elements/result-batches";
23+
import * as TestActivity from "../elements/test-activity";
24+
import * as ThemeColors from "../elements/theme-colors";
25+
import { Auth } from "../firebase";
26+
import * as MiniResultChartModal from "../modals/mini-result-chart";
27+
import * as ConfigEvent from "../observables/config-event";
28+
import * as ActivePage from "../states/active-page";
29+
import * as ConnectionState from "../states/connection";
30+
import * as Focus from "../test/focus";
31+
import * as TodayTracker from "../test/today-tracker";
32+
import * as Arrays from "../utils/arrays";
33+
import * as DateTime from "../utils/date-and-time";
34+
import Format from "../utils/format";
35+
import * as Misc from "../utils/misc";
36+
import { findLineByLeastSquares } from "../utils/numbers";
37+
import * as Skeleton from "../utils/skeleton";
38+
import { get as getTypingSpeedUnit } from "../utils/typing-speed-units";
39+
import * as LoadingPage from "./loading";
40+
import Page from "./page";
4141

4242
let filterDebug = false;
4343
//toggle filterdebug
@@ -450,18 +450,51 @@ async function fillContent(): Promise<void> {
450450

451451
if (validTags === undefined) return;
452452

453-
result.tags.forEach((tag) => {
454-
//check if i even need to check tags anymore
455-
if (!tagHide) return;
456-
//check if tag is valid
457-
if (validTags?.includes(tag)) {
458-
//tag valid, check if filter is on
459-
if (ResultFilters.getFilter("tags", tag)) tagHide = false;
453+
if (ResultFilters.getTagsFilterMode() === "or") {
454+
result.tags.forEach((tag) => {
455+
//check if i even need to check tags anymore
456+
if (!tagHide) return;
457+
//check if tag is valid
458+
if (validTags?.includes(tag)) {
459+
//tag valid, check if filter is on
460+
if (ResultFilters.getFilter("tags", tag)) tagHide = false;
461+
} else {
462+
//tag not found in valid tags, meaning probably deleted
463+
if (ResultFilters.getFilter("tags", "none")) tagHide = false;
464+
}
465+
});
466+
} else if (ResultFilters.getTagsFilterMode() === "and") {
467+
// AND mode - show results that match ALL selected tags
468+
// First, identify all the enabled tags using validTags
469+
const enabledTagIds: string[] = [];
470+
471+
// Loop through all valid tags to find which ones are enabled in the filter
472+
validTags.forEach((tagId) => {
473+
if (tagId !== "none" && ResultFilters.getFilter("tags", tagId)) {
474+
enabledTagIds.push(tagId);
475+
}
476+
});
477+
478+
if (enabledTagIds.length === 0) {
479+
// No tag filters enabled, show everything
480+
tagHide = false;
460481
} else {
461-
//tag not found in valid tags, meaning probably deleted
462-
if (ResultFilters.getFilter("tags", "none")) tagHide = false;
482+
// Check if result has ALL the enabled tag filters
483+
const resultHasAllTags = enabledTagIds.every((tagId) =>
484+
result.tags?.includes(tagId)
485+
);
486+
487+
if (resultHasAllTags) {
488+
tagHide = false;
489+
} else if (
490+
ResultFilters.getFilter("tags", "none") &&
491+
result.tags.length === 0
492+
) {
493+
// Special case: "none" tag is enabled and result has no tags
494+
tagHide = false;
495+
}
463496
}
464-
});
497+
}
465498
}
466499

467500
if (tagHide) {

0 commit comments

Comments
 (0)