Eye on the Tags header hides all tags, also tags added later
This commit is contained in:
@@ -23,7 +23,8 @@
|
|||||||
local branches, remote branches and tags, and the checked-out commit is ringed.
|
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
|
- **Hides what you don't need.** Hide one branch with its eye button in the sidebar, or
|
||||||
with <kbd>h</kbd> on a commit. Type a pattern such as `prototypes/*` and choose
|
with <kbd>h</kbd> 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
|
- **Folds long straight stretches.** Commits in a row that have no branch, tag, fork or
|
||||||
merge fold into one dotted line. <kbd>c</kbd> folds all of them, <kbd>space</kbd>
|
merge fold into one dotted line. <kbd>c</kbd> folds all of them, <kbd>space</kbd>
|
||||||
opens or closes the one at the selected commit.
|
opens or closes the one at the selected commit.
|
||||||
|
|||||||
+2
-1
@@ -150,6 +150,7 @@ async function applyRepo(data: RepoData) {
|
|||||||
});
|
});
|
||||||
filters.hidden = saved?.hidden ?? [];
|
filters.hidden = saved?.hidden ?? [];
|
||||||
filters.rules = saved?.rules ?? [];
|
filters.rules = saved?.rules ?? [];
|
||||||
|
filters.hideTags = saved?.hideTags ?? false;
|
||||||
collapseAll.value = saved?.collapseAll ?? false;
|
collapseAll.value = saved?.collapseAll ?? false;
|
||||||
filtersLoadedFor = data.root;
|
filtersLoadedFor = data.root;
|
||||||
toggled.value = new Set();
|
toggled.value = new Set();
|
||||||
@@ -173,7 +174,7 @@ watch(
|
|||||||
saveTimer = window.setTimeout(() => {
|
saveTimer = window.setTimeout(() => {
|
||||||
invoke("save_filters", {
|
invoke("save_filters", {
|
||||||
repo: repoRoot,
|
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}`));
|
}).catch((e) => showToast(`could not save filters: ${e}`));
|
||||||
}, 300);
|
}, 300);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -46,7 +46,15 @@ function toggleFolder(n: TreeNode) {
|
|||||||
<path d="M1.5 4a1 1 0 0 1 1-1h3.5l1.5 1.5h6a1 1 0 0 1 1 1V12a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1z" />
|
<path d="M1.5 4a1 1 0 0 1 1-1h3.5l1.5 1.5h6a1 1 0 0 1 1 1V12a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1z" />
|
||||||
</svg>
|
</svg>
|
||||||
<span class="name" :title="n.ref?.name ?? n.path">{{ n.label }}</span>
|
<span class="name" :title="n.ref?.name ?? n.path">{{ n.label }}</span>
|
||||||
<EyeButton :shut="allHidden(n)" @click.stop="emit('toggle', refsUnder(n).map((r) => r.name))" />
|
<EyeButton
|
||||||
|
v-if="kind === 'tag' && filters.hideTags"
|
||||||
|
class="locked"
|
||||||
|
:shut="true"
|
||||||
|
disabled
|
||||||
|
title="all tags are hidden: use the eye next to Tags"
|
||||||
|
@click.stop
|
||||||
|
/>
|
||||||
|
<EyeButton v-else :shut="allHidden(n)" @click.stop="emit('toggle', refsUnder(n).map((r) => r.name))" />
|
||||||
</div>
|
</div>
|
||||||
<RefTree
|
<RefTree
|
||||||
v-if="n.children.length && !closed.has(key(n))"
|
v-if="n.children.length && !closed.has(key(n))"
|
||||||
@@ -80,4 +88,5 @@ function toggleFolder(n: TreeNode) {
|
|||||||
.arrow.open { transform: rotate(90deg); }
|
.arrow.open { transform: rotate(90deg); }
|
||||||
.name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
.name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||||
.item:hover :deep(.eye) { opacity: 1; }
|
.item:hover :deep(.eye) { opacity: 1; }
|
||||||
|
.item :deep(.eye.locked) { opacity: 0.35; cursor: default; }
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { computed, reactive, ref } from "vue";
|
|||||||
import { refKind, shortName } from "../lib/filter";
|
import { refKind, shortName } from "../lib/filter";
|
||||||
import { buildTree, type TreeNode } from "../lib/tree";
|
import { buildTree, type TreeNode } from "../lib/tree";
|
||||||
import type { FilterState, Ref, RefKind } from "../lib/types";
|
import type { FilterState, Ref, RefKind } from "../lib/types";
|
||||||
|
import EyeButton from "./EyeButton.vue";
|
||||||
import RefTree from "./RefTree.vue";
|
import RefTree from "./RefTree.vue";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
@@ -98,7 +99,15 @@ function onPatternKey(e: KeyboardEvent) {
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section v-for="g in groups" v-show="byKind[g.kind].length" :key="g.kind" class="group">
|
<section v-for="g in groups" v-show="byKind[g.kind].length" :key="g.kind" class="group">
|
||||||
<h3>{{ g.title }} <span class="count">{{ byKind[g.kind].length }}</span></h3>
|
<h3>
|
||||||
|
{{ g.title }} <span class="count">{{ byKind[g.kind].length }}</span>
|
||||||
|
<EyeButton
|
||||||
|
v-if="g.kind === 'tag'"
|
||||||
|
:shut="!!filters.hideTags"
|
||||||
|
:title="filters.hideTags ? 'show all tags' : 'hide all tags, also tags added later'"
|
||||||
|
@click="filters.hideTags = !filters.hideTags"
|
||||||
|
/>
|
||||||
|
</h3>
|
||||||
<RefTree
|
<RefTree
|
||||||
:nodes="trees[g.kind]"
|
:nodes="trees[g.kind]"
|
||||||
:kind="g.kind"
|
:kind="g.kind"
|
||||||
@@ -122,6 +131,9 @@ function onPatternKey(e: KeyboardEvent) {
|
|||||||
padding: 10px 0 20px;
|
padding: 10px 0 20px;
|
||||||
}
|
}
|
||||||
h3 {
|
h3 {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
margin: 12px 14px 6px;
|
margin: 12px 14px 6px;
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
@@ -129,6 +141,8 @@ h3 {
|
|||||||
color: var(--text-dim);
|
color: var(--text-dim);
|
||||||
}
|
}
|
||||||
.count { font-weight: normal; opacity: 0.7; }
|
.count { font-weight: normal; opacity: 0.7; }
|
||||||
|
h3 :deep(.eye) { margin-left: auto; margin-right: -6px; }
|
||||||
|
h3:hover :deep(.eye) { opacity: 1; }
|
||||||
.rules { padding: 0 14px; }
|
.rules { padding: 0 14px; }
|
||||||
.rules h3 { margin-left: 0; margin-top: 2px; }
|
.rules h3 { margin-left: 0; margin-top: 2px; }
|
||||||
.rules input { width: 100%; }
|
.rules input { width: 100%; }
|
||||||
|
|||||||
@@ -78,3 +78,18 @@ describe("lineOwners", () => {
|
|||||||
expect(owners.get("f")).toBe("refs/heads/feature");
|
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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ export function globMatch(pattern: string, text: string): boolean {
|
|||||||
|
|
||||||
export function isRefVisible(name: string, state: FilterState): boolean {
|
export function isRefVisible(name: string, state: FilterState): boolean {
|
||||||
if (state.hidden.includes(name)) return false;
|
if (state.hidden.includes(name)) return false;
|
||||||
|
if (state.hideTags && name.startsWith("refs/tags/")) return false;
|
||||||
const short = shortName(name);
|
const short = shortName(name);
|
||||||
const only = state.rules.filter((r) => r.mode === "only");
|
const only = state.rules.filter((r) => r.mode === "only");
|
||||||
if (only.length > 0 && !only.some((r) => globMatch(r.pattern, short))) return false;
|
if (only.length > 0 && !only.some((r) => globMatch(r.pattern, short))) return false;
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ export interface FilterState {
|
|||||||
/** Full ref names hidden with the eye toggle. */
|
/** Full ref names hidden with the eye toggle. */
|
||||||
hidden: string[];
|
hidden: string[];
|
||||||
rules: FilterRule[];
|
rules: FilterRule[];
|
||||||
|
/** Hides every tag, also tags created later. */
|
||||||
|
hideTags?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A commit as shown on screen, with its parent edges after collapsing. */
|
/** A commit as shown on screen, with its parent edges after collapsing. */
|
||||||
|
|||||||
Reference in New Issue
Block a user