taskchef 7.16.0 → 7.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.codex-plugin/plugin.json +1 -1
- package/package.json +1 -1
- package/src/dashboard/app.js +24 -28
- package/src/dashboard/github-links.js +58 -0
package/package.json
CHANGED
package/src/dashboard/app.js
CHANGED
|
@@ -16,7 +16,11 @@ import {
|
|
|
16
16
|
turnPresentation,
|
|
17
17
|
} from "./state.js";
|
|
18
18
|
import { openTaskFromControl } from "./actions.js";
|
|
19
|
-
import {
|
|
19
|
+
import {
|
|
20
|
+
githubReferenceAccessibleLabel,
|
|
21
|
+
githubReferenceDisplayLabels,
|
|
22
|
+
referenceSegments,
|
|
23
|
+
} from "./github-links.js";
|
|
20
24
|
import { formatRelativeTime, RelativeTimeController, parsedTimestamp } from "./time.js";
|
|
21
25
|
|
|
22
26
|
const state = {
|
|
@@ -63,23 +67,15 @@ const elements = {
|
|
|
63
67
|
};
|
|
64
68
|
let notificationDescriptionSerial = 0;
|
|
65
69
|
|
|
66
|
-
function
|
|
67
|
-
if (!typePrefix) return label;
|
|
68
|
-
if (link.type === "pull") return `PR ${label}`;
|
|
69
|
-
if (link.type === "issue") return `Issue ${label}`;
|
|
70
|
-
return label;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function referenceLink(link, { compact = false, displayLabel, typePrefix = false } = {}) {
|
|
70
|
+
function referenceLink(link, { compact = false, displayLabel } = {}) {
|
|
74
71
|
const anchor = document.createElement("a");
|
|
75
72
|
anchor.className = compact ? "github-link github-link-compact" : "github-link";
|
|
76
73
|
anchor.href = link.url;
|
|
77
74
|
anchor.target = "_blank";
|
|
78
75
|
anchor.rel = "noopener noreferrer";
|
|
79
76
|
const label = link.label ?? link.text;
|
|
80
|
-
|
|
81
|
-
const accessibleLabel =
|
|
82
|
-
anchor.textContent = visibleLabel;
|
|
77
|
+
anchor.textContent = displayLabel ?? label;
|
|
78
|
+
const accessibleLabel = githubReferenceAccessibleLabel(link);
|
|
83
79
|
const githubKind = link.type === "issue"
|
|
84
80
|
? ", GitHub issue"
|
|
85
81
|
: link.type === "pull"
|
|
@@ -94,12 +90,20 @@ function referenceLink(link, { compact = false, displayLabel, typePrefix = false
|
|
|
94
90
|
}
|
|
95
91
|
|
|
96
92
|
function appendLinkedText(container, text, task) {
|
|
97
|
-
const
|
|
93
|
+
const segments = referenceSegments(text, {
|
|
98
94
|
projectRepositories: task.project?.githubRepos,
|
|
99
95
|
taskRepository: task.relatedGitHubRepository,
|
|
100
|
-
})
|
|
96
|
+
});
|
|
97
|
+
const links = segments.filter((segment) => segment.kind === "link");
|
|
98
|
+
const displayLabels = githubReferenceDisplayLabels(links);
|
|
99
|
+
let linkIndex = 0;
|
|
100
|
+
const children = segments.map((segment) => {
|
|
101
101
|
if (segment.kind === "text") return document.createTextNode(segment.text);
|
|
102
|
-
if (segment.kind === "link")
|
|
102
|
+
if (segment.kind === "link") {
|
|
103
|
+
const displayLabel = displayLabels[linkIndex];
|
|
104
|
+
linkIndex += 1;
|
|
105
|
+
return referenceLink(segment, { displayLabel });
|
|
106
|
+
}
|
|
103
107
|
const ambiguous = document.createElement("span");
|
|
104
108
|
ambiguous.className = "github-reference-ambiguous";
|
|
105
109
|
ambiguous.textContent = segment.text;
|
|
@@ -121,18 +125,10 @@ function relatedGitHubLinks(task, { compact = false } = {}) {
|
|
|
121
125
|
const container = document.createElement("nav");
|
|
122
126
|
container.className = `github-links${compact ? " github-links-compact" : ""}`;
|
|
123
127
|
container.setAttribute("aria-label", `Related GitHub links for ${task.title}`);
|
|
124
|
-
const
|
|
125
|
-
const children = links.map((link) =>
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
: null;
|
|
129
|
-
const repeatedRepository = repository && seenRepositories.has(repository);
|
|
130
|
-
if (repository) seenRepositories.add(repository);
|
|
131
|
-
const displayLabel = repeatedRepository && link.number
|
|
132
|
-
? `#${link.number}`
|
|
133
|
-
: link.label;
|
|
134
|
-
return referenceLink(link, { compact, displayLabel, typePrefix: true });
|
|
135
|
-
});
|
|
128
|
+
const displayLabels = githubReferenceDisplayLabels(links, { related: true });
|
|
129
|
+
const children = links.map((link, index) => (
|
|
130
|
+
referenceLink(link, { compact, displayLabel: displayLabels[index] })
|
|
131
|
+
));
|
|
136
132
|
if (task.relatedGitHubLinksTruncated) {
|
|
137
133
|
const more = document.createElement("span");
|
|
138
134
|
more.className = "github-links-more";
|
|
@@ -160,7 +156,7 @@ function renderProject(container, task) {
|
|
|
160
156
|
repository: repositoryName,
|
|
161
157
|
type: "repository",
|
|
162
158
|
url: `https://github.com/${repository}`,
|
|
163
|
-
}),
|
|
159
|
+
}, { displayLabel: repositoryName }),
|
|
164
160
|
);
|
|
165
161
|
}
|
|
166
162
|
container.replaceChildren(...children);
|
|
@@ -3,6 +3,64 @@ const REFERENCE_PATTERN = /https?:\/\/(?:www\.)?github\.com\/([A-Za-z0-9](?:[A-Z
|
|
|
3
3
|
const ABSOLUTE_HTTP_PATTERN = /https?:\/\/[^\s<>"'`]+/gi;
|
|
4
4
|
export const MAX_RELATED_GITHUB_LINKS = 20;
|
|
5
5
|
|
|
6
|
+
function repositoryIdentity(link) {
|
|
7
|
+
if (!link?.owner || !link?.repository) return null;
|
|
8
|
+
return `${link.owner.toLowerCase()}/${link.repository.toLowerCase()}`;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function collidingRepositoryBasenames(links) {
|
|
12
|
+
const repositoriesByBasename = new Map();
|
|
13
|
+
for (const link of links) {
|
|
14
|
+
const identity = repositoryIdentity(link);
|
|
15
|
+
if (!identity) continue;
|
|
16
|
+
const basename = link.repository.toLowerCase();
|
|
17
|
+
const repositories = repositoriesByBasename.get(basename) ?? new Set();
|
|
18
|
+
repositories.add(identity);
|
|
19
|
+
repositoriesByBasename.set(basename, repositories);
|
|
20
|
+
}
|
|
21
|
+
return new Set(
|
|
22
|
+
[...repositoriesByBasename]
|
|
23
|
+
.filter(([, repositories]) => repositories.size > 1)
|
|
24
|
+
.map(([basename]) => basename),
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function visibleRepositoryLabel(link, collisions) {
|
|
29
|
+
return collisions.has(link.repository.toLowerCase())
|
|
30
|
+
? `${link.owner}/${link.repository}`
|
|
31
|
+
: link.repository;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function githubReferenceDisplayLabels(links, { related = false } = {}) {
|
|
35
|
+
const collisions = collidingRepositoryBasenames(links);
|
|
36
|
+
let previousRepository = null;
|
|
37
|
+
return links.map((link) => {
|
|
38
|
+
if (link.provider !== "github" && !link.owner) return link.label ?? link.text;
|
|
39
|
+
const repository = repositoryIdentity(link);
|
|
40
|
+
const repositoryLabel = visibleRepositoryLabel(link, collisions);
|
|
41
|
+
if (link.type === "repository") return repositoryLabel;
|
|
42
|
+
if (related) {
|
|
43
|
+
const label = repository === previousRepository
|
|
44
|
+
? `#${link.number}`
|
|
45
|
+
: `${repositoryLabel} #${link.number}`;
|
|
46
|
+
previousRepository = repository;
|
|
47
|
+
return label;
|
|
48
|
+
}
|
|
49
|
+
if (link.type === "pull") return `${repositoryLabel} PR #${link.number}`;
|
|
50
|
+
if (link.type === "issue") return `${repositoryLabel} Issue #${link.number}`;
|
|
51
|
+
return `${repositoryLabel} #${link.number}`;
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function githubReferenceAccessibleLabel(link) {
|
|
56
|
+
const repository = repositoryIdentity(link);
|
|
57
|
+
if (!repository) return link.label ?? link.text;
|
|
58
|
+
if (link.type === "repository") return repository;
|
|
59
|
+
if (link.type === "pull") return `${repository} PR #${link.number}`;
|
|
60
|
+
if (link.type === "issue") return `${repository} Issue #${link.number}`;
|
|
61
|
+
return `${repository} #${link.number}`;
|
|
62
|
+
}
|
|
63
|
+
|
|
6
64
|
function canonicalRepository(owner, repository) {
|
|
7
65
|
return `${owner.toLowerCase()}/${repository.toLowerCase()}`;
|
|
8
66
|
}
|