diff --git a/README.md b/README.md index 3057f1a..8f3b1d8 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,8 @@ local branches, remote branches and tags, and the checked-out commit is ringed. - **Hides what you don't need.** Hide one branch with its eye button in the sidebar, or with h on a commit. Type a pattern such as `prototypes/*` and choose - **hide** or **show only**. gites remembers the filters of each repository. + **hide** or **show only**. The eye next to **Tags** hides all tags, also tags added + later. gites remembers the filters of each repository. - **Folds long straight stretches.** Commits in a row that have no branch, tag, fork or merge fold into one dotted line. c folds all of them, space opens or closes the one at the selected commit. diff --git a/src/App.vue b/src/App.vue index 0576c1f..a683db9 100644 --- a/src/App.vue +++ b/src/App.vue @@ -150,6 +150,7 @@ async function applyRepo(data: RepoData) { }); filters.hidden = saved?.hidden ?? []; filters.rules = saved?.rules ?? []; + filters.hideTags = saved?.hideTags ?? false; collapseAll.value = saved?.collapseAll ?? false; filtersLoadedFor = data.root; toggled.value = new Set(); @@ -173,7 +174,7 @@ watch( saveTimer = window.setTimeout(() => { invoke("save_filters", { repo: repoRoot, - value: { hidden: filters.hidden, rules: filters.rules, collapseAll: collapseAll.value }, + value: { hidden: filters.hidden, rules: filters.rules, hideTags: filters.hideTags, collapseAll: collapseAll.value }, }).catch((e) => showToast(`could not save filters: ${e}`)); }, 300); }, diff --git a/src/components/RefTree.vue b/src/components/RefTree.vue index a295fa0..c37e86e 100644 --- a/src/components/RefTree.vue +++ b/src/components/RefTree.vue @@ -46,7 +46,15 @@ function toggleFolder(n: TreeNode) { {{ n.label }} - + + diff --git a/src/components/Sidebar.vue b/src/components/Sidebar.vue index 5c431c5..2cbabb2 100644 --- a/src/components/Sidebar.vue +++ b/src/components/Sidebar.vue @@ -3,6 +3,7 @@ import { computed, reactive, ref } from "vue"; import { refKind, shortName } from "../lib/filter"; import { buildTree, type TreeNode } from "../lib/tree"; import type { FilterState, Ref, RefKind } from "../lib/types"; +import EyeButton from "./EyeButton.vue"; import RefTree from "./RefTree.vue"; const props = defineProps<{ @@ -98,7 +99,15 @@ function onPatternKey(e: KeyboardEvent) {
-

{{ g.title }} {{ byKind[g.kind].length }}

+

+ {{ g.title }} {{ byKind[g.kind].length }} + +

{ expect(owners.get("f")).toBe("refs/heads/feature"); }); }); + +describe("hiding all tags", () => { + const state = { hidden: [], rules: [], hideTags: true }; + it("hides every tag", () => { + expect(isRefVisible("refs/tags/v1", state)).toBe(false); + expect(isRefVisible("refs/tags/release/2", state)).toBe(false); + }); + it("leaves branches alone", () => { + expect(isRefVisible("refs/heads/main", state)).toBe(true); + expect(isRefVisible("refs/remotes/origin/main", state)).toBe(true); + }); + it("shows tags again when turned off", () => { + expect(isRefVisible("refs/tags/v1", { ...state, hideTags: false })).toBe(true); + }); +}); diff --git a/src/lib/filter.ts b/src/lib/filter.ts index 1338ee2..28d6339 100644 --- a/src/lib/filter.ts +++ b/src/lib/filter.ts @@ -21,6 +21,7 @@ export function globMatch(pattern: string, text: string): boolean { export function isRefVisible(name: string, state: FilterState): boolean { if (state.hidden.includes(name)) return false; + if (state.hideTags && name.startsWith("refs/tags/")) return false; const short = shortName(name); const only = state.rules.filter((r) => r.mode === "only"); if (only.length > 0 && !only.some((r) => globMatch(r.pattern, short))) return false; diff --git a/src/lib/types.ts b/src/lib/types.ts index d53e2d5..b1e7340 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -33,6 +33,8 @@ export interface FilterState { /** Full ref names hidden with the eye toggle. */ hidden: string[]; rules: FilterRule[]; + /** Hides every tag, also tags created later. */ + hideTags?: boolean; } /** A commit as shown on screen, with its parent edges after collapsing. */