Skip to content

Commit 94ae439

Browse files
committed
add overflow menu and status tooltips to dependency lists
- replace custom tooltip logic with shared dedupeStatusText helper - add overflow dropdown with navigation links in item-dependency-list - make item names clickable in both dependency and dependents lists - add tabular-nums class for consistent number alignment - improve dependency status visualization with dedicated tooltips
1 parent 28b4161 commit 94ae439

File tree

5 files changed

+160
-101
lines changed

5 files changed

+160
-101
lines changed

frontend/src/features/archived-items/item-dependency-list/item-dependency-list.ts

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import { localized, msg } from "@lit/localize";
22
import { Task } from "@lit/task";
3-
import type { SlTree } from "@shoelace-style/shoelace";
43
import { html, nothing, unsafeCSS } from "lit";
5-
import { customElement, property, query } from "lit/decorators.js";
4+
import { customElement, property } from "lit/decorators.js";
65
import { repeat } from "lit/directives/repeat.js";
76
import queryString from "query-string";
87

@@ -12,6 +11,7 @@ import stylesheet from "./item-dependency-list.stylesheet.css";
1211

1312
import { BtrixElement } from "@/classes/BtrixElement";
1413
import { dedupeIcon } from "@/features/collections/templates/dedupe-icon";
14+
import { dedupeStatusText } from "@/features/collections/templates/dedupe-status-text";
1515
import type { ArchivedItemSectionName } from "@/pages/org/archived-item-detail/archived-item-detail";
1616
import { OrgTab, WorkflowTab } from "@/routes";
1717
import type { APIPaginatedList } from "@/types/api";
@@ -39,9 +39,6 @@ export class ItemDependencyTree extends BtrixElement {
3939
@property({ type: Array })
4040
items?: ArchivedItem[];
4141

42-
@query("sl-tree")
43-
private readonly tree?: SlTree | null;
44-
4542
private readonly timerIds: number[] = [];
4643

4744
private readonly dependenciesMap = new Map<
@@ -107,6 +104,7 @@ export class ItemDependencyTree extends BtrixElement {
107104
style="--btrix-table-grid-template-columns: ${[
108105
"[clickable-start] min-content",
109106
"repeat(4, auto) [clickable-end]",
107+
"min-content",
110108
].join(" ")}"
111109
>
112110
<btrix-table-head
@@ -171,26 +169,38 @@ export class ItemDependencyTree extends BtrixElement {
171169
href=${
172170
crawled
173171
? `${this.navigate.orgBasePath}/${OrgTab.Workflows}/${item.cid}/${WorkflowTab.Crawls}/${item.id}#${"dependencies" as ArchivedItemSectionName}`
174-
: `${this.navigate.orgBasePath}/${OrgTab.Items}/${item.type}/${item.id}`
172+
: `${this.navigate.orgBasePath}/${OrgTab.Items}/${item.type}/${item.id}#${"dependencies" as ArchivedItemSectionName}`
175173
}
176174
@click=${this.navigate.link}
177175
>
178176
${renderName(item)}
179177
</a>
180178
</btrix-table-cell>
181-
<btrix-table-cell class="flex items-center gap-1.5 truncate">
179+
<btrix-table-cell class="flex items-center gap-1.5 truncate tabular-nums">
180+
<sl-tooltip
181+
content=${dedupeStatusText(
182+
item.requiredByCrawls.length,
183+
dependencies.length,
184+
)}
185+
placement="left"
186+
hoist
187+
>
182188
${
183189
dependencies.length
184190
? html`
185-
${dedupeIcon({ hasDependencies: true, hasDependents: true })}
191+
${dedupeIcon({
192+
hasDependencies: true,
193+
hasDependents: !!item.requiredByCrawls.length,
194+
})}
186195
${this.localize.number(dependencies.length)}
187196
${pluralOf("dependencies", dependencies.length)}
188197
`
189198
: nothing
190199
}
200+
</sl-tooltip>
191201
</btrix-table-cell>
192202
193-
<btrix-table-cell class="flex items-center gap-1.5 truncate">
203+
<btrix-table-cell class="flex items-center gap-1.5 truncate tabular-nums">
194204
${
195205
crawled
196206
? html`<sl-tooltip
@@ -219,6 +229,30 @@ export class ItemDependencyTree extends BtrixElement {
219229
<sl-icon name="file-earmark-binary"></sl-icon>
220230
${this.localize.bytes(item.fileSize || 0, { unitDisplay: "short" })}
221231
</btrix-table-cell>
232+
<btrix-table-cell>
233+
<btrix-overflow-dropdown>
234+
<sl-menu>
235+
<btrix-menu-item-link
236+
href="${
237+
crawled
238+
? `${this.navigate.orgBasePath}/${OrgTab.Workflows}/${item.cid}/${WorkflowTab.Crawls}/${item.id}`
239+
: `${this.navigate.orgBasePath}/${OrgTab.Items}/${item.type}/${item.id}`
240+
}"
241+
>
242+
<sl-icon slot="prefix" name=${crawled ? "gear-wide-connected" : "arrow-return-right"}></sl-icon>
243+
${crawled ? msg("Go to Crawl Run") : msg("Go to Item")}
244+
</btrix-menu-item-link>
245+
<btrix-menu-item-link
246+
href="${
247+
this.navigate.orgBasePath
248+
}/${OrgTab.Workflows}/${item.cid}"
249+
>
250+
<sl-icon slot="prefix" name="arrow-return-right"></sl-icon>
251+
${msg("Go to Workflow")}
252+
</btrix-menu-item-link>
253+
</sl-menu>
254+
</btrix-overflow-dropdown>
255+
</btrix-table-cell>
222256
</div>`;
223257
};
224258
}

frontend/src/features/archived-items/item-dependents.ts

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,17 @@ import { localized, msg } from "@lit/localize";
22
import { html } from "lit";
33
import { customElement, property } from "lit/decorators.js";
44

5+
import { dedupeStatusText } from "../collections/templates/dedupe-status-text";
6+
57
import { collectionStatusIcon } from "./templates/collection-status-icon";
68

79
import { BtrixElement } from "@/classes/BtrixElement";
10+
import { dedupeIcon } from "@/features/collections/templates/dedupe-icon";
811
import type { ArchivedItemSectionName } from "@/pages/org/archived-item-detail/archived-item-detail";
912
import { OrgTab, WorkflowTab } from "@/routes";
1013
import type { ArchivedItem } from "@/types/crawler";
1114
import { isCrawl, renderName } from "@/utils/crawler";
15+
import { pluralOf } from "@/utils/pluralize";
1216

1317
@customElement("btrix-item-dependents")
1418
@localized()
@@ -69,13 +73,35 @@ export class ItemDependents extends BtrixElement {
6973
collectionId: this.collectionId,
7074
})}</btrix-table-cell
7175
>
72-
<btrix-table-cell class="pl-0">${renderName(item)}</btrix-table-cell>
73-
<btrix-table-cell class="tabular-nums">
74-
${this.localize.number(item.requiredByCrawls.length, {
75-
notation: "compact",
76-
})}
76+
<btrix-table-cell class="pl-0" rowClickTarget="a">
77+
<a
78+
href=${crawled
79+
? `${this.navigate.orgBasePath}/${OrgTab.Workflows}/${item.cid}/${WorkflowTab.Crawls}/${item.id}#${"overview" as ArchivedItemSectionName}`
80+
: `${this.navigate.orgBasePath}/${OrgTab.Items}/${item.type}/${item.id}`}
81+
>
82+
${renderName(item)}
83+
</a>
7784
</btrix-table-cell>
78-
<btrix-table-cell class="tabular-nums">
85+
<btrix-table-cell class="flex items-center gap-1.5 truncate tabular-nums">
86+
<sl-tooltip
87+
content=${dedupeStatusText(
88+
item.requiredByCrawls.length,
89+
item.requiresCrawls.length,
90+
)}
91+
placement="left"
92+
hoist
93+
>
94+
${dedupeIcon({
95+
hasDependencies: !!item.requiresCrawls.length,
96+
hasDependents: true,
97+
})}
98+
${this.localize.number(item.requiredByCrawls.length, {
99+
notation: "compact",
100+
})}
101+
${pluralOf("dependents", item.requiredByCrawls.length)}
102+
</sl-tooltip>
103+
</btrix-table-cell>
104+
<btrix-table-cell class="flex items-center gap-1.5 truncate tabular-nums">
79105
${this.localize.date(item.finished || item.started, {
80106
dateStyle: "short",
81107
timeStyle: "short",
@@ -84,13 +110,6 @@ export class ItemDependents extends BtrixElement {
84110
<btrix-table-cell class="tabular-nums">
85111
${this.localize.bytes(item.fileSize || 0, { unitDisplay: "short" })}
86112
</btrix-table-cell>
87-
<btrix-table-cell>
88-
${this.renderLink(
89-
crawled
90-
? `${this.navigate.orgBasePath}/${OrgTab.Workflows}/${item.cid}/${WorkflowTab.Crawls}/${item.id}#${"overview" as ArchivedItemSectionName}`
91-
: `${this.navigate.orgBasePath}/${OrgTab.Items}/${item.type}/${item.id}`,
92-
)}
93-
</btrix-table-cell>
94113
</btrix-table-row>`;
95114
};
96115

frontend/src/features/collections/dedupe-badge.ts

Lines changed: 7 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
import { localized, msg, str } from "@lit/localize";
1+
import { localized } from "@lit/localize";
22
import { css, html } from "lit";
33
import { customElement, property } from "lit/decorators.js";
44

55
import { dedupeIcon, dedupeLabelFor } from "./templates/dedupe-icon";
6+
import { dedupeStatusText } from "./templates/dedupe-status-text";
67

78
import { TailwindElement } from "@/classes/TailwindElement";
8-
import localize from "@/utils/localize";
9-
import { pluralize } from "@/utils/pluralize";
109
import { tw } from "@/utils/tailwind";
1110

1211
@customElement("btrix-dedupe-badge")
@@ -25,86 +24,17 @@ export class DedupeBadge extends TailwindElement {
2524
dependencies?: string[] = [];
2625

2726
render() {
28-
const dependentsCount = this.dependents?.length;
29-
const dependenciesCount = this.dependencies?.length;
27+
const dependentsCount = this.dependents?.length ?? 0;
28+
const dependenciesCount = this.dependencies?.length ?? 0;
3029

3130
if (!dependentsCount && !dependenciesCount) return;
3231

33-
let tooltip = "";
32+
const tooltip = dedupeStatusText(dependentsCount, dependenciesCount);
3433
let text: string = dedupeLabelFor.both;
3534

36-
if (dependentsCount && dependenciesCount) {
37-
const number_of_dependent_items = localize.number(dependentsCount);
38-
const number_of_dependency_items = localize.number(dependenciesCount);
39-
40-
const listFormatter = new Intl.ListFormat("en", {
41-
style: "long",
42-
type: "conjunction",
43-
});
44-
45-
tooltip = listFormatter.format([
46-
pluralize(dependenciesCount, {
47-
zero: msg("This item depends on no items"),
48-
one: msg("This item depends on 1 item"),
49-
two: msg("This item depends on 2 items"),
50-
few: msg(
51-
str`This item depends on ${number_of_dependency_items} items`,
52-
),
53-
many: msg(
54-
str`This item depends on ${number_of_dependency_items} items`,
55-
),
56-
other: msg(
57-
str`This item depends on ${number_of_dependency_items} items`,
58-
),
59-
}),
60-
pluralize(dependentsCount, {
61-
zero: msg(
62-
"it is a dependency of 0 items in the deduplication source.",
63-
),
64-
one: msg("it is a dependency of 1 item in the deduplication source."),
65-
two: msg(
66-
"it is a dependency of 2 items in the deduplication source.",
67-
),
68-
few: msg(
69-
str`it is a dependency of ${number_of_dependent_items} items in the deduplication source.`,
70-
),
71-
many: msg(
72-
str`it is a dependency of ${number_of_dependent_items} items in the deduplication source.`,
73-
),
74-
other: msg(
75-
str`it is a dependency of ${number_of_dependent_items} items in the deduplication source.`,
76-
),
77-
}),
78-
]);
79-
} else if (dependenciesCount) {
80-
const number_of_dependency_items = localize.number(dependenciesCount);
81-
82-
tooltip = pluralize(dependenciesCount, {
83-
zero: msg("This item is dependent on no items"),
84-
one: msg("This item is dependent on 1 item"),
85-
two: msg("This item is dependent on 2 items"),
86-
few: msg(
87-
str`This item is dependent on ${number_of_dependency_items} items`,
88-
),
89-
many: msg(
90-
str`This item is dependent on ${number_of_dependency_items} items`,
91-
),
92-
other: msg(
93-
str`This item is dependent on ${number_of_dependency_items} items`,
94-
),
95-
});
35+
if (!dependentsCount) {
9636
text = dedupeLabelFor.dependent;
97-
} else if (dependentsCount) {
98-
const number_of_dependent_items = localize.number(dependentsCount);
99-
100-
tooltip = pluralize(dependentsCount, {
101-
zero: msg("No items depend on this item"),
102-
one: msg("1 item depends on this item"),
103-
two: msg("2 items depend on this item"),
104-
few: msg(str`${number_of_dependent_items} depend on this item`),
105-
many: msg(str`${number_of_dependent_items} depend on this item`),
106-
other: msg(str`${number_of_dependent_items} depend on this item`),
107-
});
37+
} else if (!dependenciesCount) {
10838
text = dedupeLabelFor.dependency;
10939
}
11040

frontend/src/features/collections/dedupe-workflows/dedupe-workflows.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,12 +117,12 @@ export class DedupeWorkflows extends BtrixElement {
117117
this.workflowCrawlsMap
118118
.get(workflow.id)
119119
?.then((crawls) => this.renderCrawls(workflow, crawls)),
120-
html`<div class="m-3 flex flex-col gap-1.5">
120+
html`<div class="m-3 mt-6 flex flex-col gap-6">
121121
${Array.from({ length: totalCrawls }).map(
122122
() => html`
123123
<sl-skeleton
124124
effect="sheen"
125-
class="h-6 [--color:var(--sl-color-neutral-100)]"
125+
class="h-4 [--color:var(--sl-color-neutral-100)]"
126126
></sl-skeleton>
127127
`,
128128
)}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { msg, str } from "@lit/localize";
2+
3+
import localize from "@/utils/localize";
4+
import { pluralize } from "@/utils/pluralize";
5+
6+
export const dedupeStatusText = (
7+
dependentsCount: number,
8+
dependenciesCount: number,
9+
): string | undefined => {
10+
if (dependentsCount && dependenciesCount) {
11+
const number_of_dependent_items = localize.number(dependentsCount);
12+
const number_of_dependency_items = localize.number(dependenciesCount);
13+
14+
const listFormatter = new Intl.ListFormat("en", {
15+
style: "long",
16+
type: "conjunction",
17+
});
18+
19+
return listFormatter.format([
20+
pluralize(dependenciesCount, {
21+
zero: msg("This item depends on no items"),
22+
one: msg("This item depends on 1 item"),
23+
two: msg("This item depends on 2 items"),
24+
few: msg(str`This item depends on ${number_of_dependency_items} items`),
25+
many: msg(
26+
str`This item depends on ${number_of_dependency_items} items`,
27+
),
28+
other: msg(
29+
str`This item depends on ${number_of_dependency_items} items`,
30+
),
31+
}),
32+
pluralize(dependentsCount, {
33+
zero: msg("it is a dependency of 0 items."),
34+
one: msg("it is a dependency of 1 item."),
35+
two: msg("it is a dependency of 2 items."),
36+
few: msg(
37+
str`it is a dependency of ${number_of_dependent_items} items.`,
38+
),
39+
many: msg(
40+
str`it is a dependency of ${number_of_dependent_items} items.`,
41+
),
42+
other: msg(
43+
str`it is a dependency of ${number_of_dependent_items} items.`,
44+
),
45+
}),
46+
]);
47+
} else if (dependenciesCount) {
48+
const number_of_dependency_items = localize.number(dependenciesCount);
49+
50+
return pluralize(dependenciesCount, {
51+
zero: msg("This item is dependent on no items"),
52+
one: msg("This item is dependent on 1 item"),
53+
two: msg("This item is dependent on 2 items"),
54+
few: msg(
55+
str`This item is dependent on ${number_of_dependency_items} items`,
56+
),
57+
many: msg(
58+
str`This item is dependent on ${number_of_dependency_items} items`,
59+
),
60+
other: msg(
61+
str`This item is dependent on ${number_of_dependency_items} items`,
62+
),
63+
});
64+
} else if (dependentsCount) {
65+
const number_of_dependent_items = localize.number(dependentsCount);
66+
67+
return pluralize(dependentsCount, {
68+
zero: msg("No items depend on this item"),
69+
one: msg("1 item depends on this item"),
70+
two: msg("2 items depend on this item"),
71+
few: msg(str`${number_of_dependent_items} items depend on this item`),
72+
many: msg(str`${number_of_dependent_items} items depend on this item`),
73+
other: msg(str`${number_of_dependent_items} items depend on this item`),
74+
});
75+
}
76+
};

0 commit comments

Comments
 (0)