Skip to content

Commit 1afcb06

Browse files
committed
add ui
1 parent e943ddc commit 1afcb06

File tree

2 files changed

+110
-30
lines changed

2 files changed

+110
-30
lines changed

web_src/js/features/comp/TextExpander.ts

Lines changed: 61 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,41 @@
1-
import {matchEmoji, matchMention, matchIssueOrPullRequest} from '../../utils/match.ts';
1+
import {matchEmoji, matchMention, matchIssue} from '../../utils/match.ts';
22
import {emojiString} from '../emoji.ts';
3+
import {svg} from '../../svg.ts';
4+
5+
type Issue = {state: 'open' | 'closed'; pull_request: {draft: boolean; merged: boolean} | null};
6+
function getIssueIcon(issue: Issue) {
7+
if (issue.pull_request !== null) {
8+
if (issue.state === 'open') {
9+
if (issue.pull_request.draft === true) {
10+
return 'octicon-git-pull-request-draft'; // WIP PR
11+
}
12+
return 'octicon-git-pull-request'; // Open PR
13+
} else if (issue.pull_request.merged === true) {
14+
return 'octicon-git-merge'; // Merged PR
15+
}
16+
return 'octicon-git-pull-request'; // Closed PR
17+
} else if (issue.state === 'open') {
18+
return 'octicon-issue-opened'; // Open Issue
19+
}
20+
return 'octicon-issue-closed'; // Closed Issue
21+
}
22+
23+
function getIssueColor(issue: Issue) {
24+
if (issue.pull_request !== null) {
25+
if (issue.pull_request.draft === true) {
26+
return 'grey'; // WIP PR
27+
} else if (issue.pull_request.merged === true) {
28+
return 'purple'; // Merged PR
29+
}
30+
}
31+
if (issue.state === 'open') {
32+
return 'green'; // Open Issue
33+
}
34+
return 'red'; // Closed Issue
35+
}
336

437
export function initTextExpander(expander) {
5-
expander?.addEventListener('text-expander-change', async ({detail: {key, provide, text}}) => {
38+
expander?.addEventListener('text-expander-change', ({detail: {key, provide, text}}) => {
639
if (key === ':') {
740
const matches = matchEmoji(text);
841
if (!matches.length) return provide({matched: false});
@@ -50,29 +83,37 @@ export function initTextExpander(expander) {
5083

5184
provide({matched: true, fragment: ul});
5285
} else if (key === '#') {
53-
const url = window.location.href;
54-
const matches = matchIssueOrPullRequest(url, text);
55-
if (!matches.length) return provide({matched: false});
86+
provide(new Promise(async (resolve) => {
87+
const url = window.location.href;
88+
const matches = await matchIssue(url, text);
89+
if (!matches.length) return resolve({matched: false});
5690

57-
const ul = document.createElement('ul');
58-
ul.classList.add('suggestions');
59-
for (const {value, name, type} of matches) {
60-
const li = document.createElement('li');
61-
li.setAttribute('role', 'option');
62-
li.setAttribute('data-value', `${key}${value}`);
91+
const ul = document.createElement('ul');
92+
ul.classList.add('suggestions');
93+
for (const {value, name, issue} of matches) {
94+
const li = document.createElement('li');
95+
li.classList.add('tw-flex', 'tw-gap-2');
96+
li.setAttribute('role', 'option');
97+
li.setAttribute('data-value', `${key}${value}`);
6398

64-
const icon = document.createElement('span');
65-
icon.classList.add('icon', type === 'issue' ? 'issue' : 'pull-request');
66-
li.append(icon);
99+
const icon = document.createElement('div');
100+
icon.innerHTML = svg(getIssueIcon(issue), 16, ['text', getIssueColor(issue)].join(' ')).trim();
101+
li.append(icon.firstChild);
67102

68-
const nameSpan = document.createElement('span');
69-
nameSpan.textContent = name;
70-
li.append(nameSpan);
103+
const id = document.createElement('span');
104+
id.classList.add('id');
105+
id.textContent = value;
106+
li.append(id);
71107

72-
ul.append(li);
73-
}
108+
const nameSpan = document.createElement('span');
109+
nameSpan.textContent = name;
110+
li.append(nameSpan);
74111

75-
provide({matched: true, fragment: ul});
112+
ul.append(li);
113+
}
114+
115+
resolve({matched: true, fragment: ul});
116+
}));
76117
}
77118
});
78119
expander?.addEventListener('text-expander-value', ({detail}) => {

web_src/js/utils/match.ts

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,17 @@ export function matchMention(queryText: string): Mention[] {
4444
return sortAndReduce(results);
4545
}
4646

47-
type IssueOrPullRequest = {value: string; name: string; type: 'issue' | 'pull-request'};
48-
export async function matchIssueOrPullRequest(url: string, queryText: string): IssueOrPullRequest[] {
47+
type Issue = {state: 'open' | 'closed'; pull_request: {draft: boolean; merged: boolean} | null};
48+
type IssueMention = {value: string; name: string; issue: Issue};
49+
export async function matchIssue(url: string, queryText: string): Promise<IssueMention[]> {
4950
const query = queryText.toLowerCase();
5051

51-
const repository = url.split('/').slice(-2).join('/');
52+
// http://localhost:3000/anbraten/test/issues/1
53+
// http://localhost:3000/anbraten/test/compare/main...anbraten-patch-1
54+
const repository = (new URL(url)).pathname.split('/').slice(1, 3).join('/');
5255
const issuePullRequestId = url.split('/').slice(-1)[0];
5356

54-
console.log('suggestions for', {
57+
console.log('suggestions for 1', {
5558
repository,
5659
query,
5760
});
@@ -67,7 +70,7 @@ export async function matchIssueOrPullRequest(url: string, queryText: string): I
6770
// console.log(await res.json());
6871

6972
// results is a map of weights, lower is better
70-
const results = new Map<IssueOrPullRequest, number>();
73+
const results = new Map<IssueMention, number>();
7174
// for (const obj of window.config.mentionValues ?? []) {
7275
// const index = obj.key.toLowerCase().indexOf(query);
7376
// if (index === -1) continue;
@@ -78,33 +81,69 @@ export async function matchIssueOrPullRequest(url: string, queryText: string): I
7881
results.set({
7982
value: '28958',
8083
name: 'Live removal of issue comments using htmx websocket',
81-
type: 'pull-request',
84+
issue: {
85+
state: 'open',
86+
pull_request: {
87+
merged: false,
88+
draft: false,
89+
},
90+
},
8291
}, 0);
8392

8493
results.set({
8594
value: '32234',
8695
name: 'Calculate `PublicOnly` for org membership only once',
87-
type: 'pull-request',
96+
issue: {
97+
state: 'closed',
98+
pull_request: {
99+
merged: true,
100+
draft: false,
101+
},
102+
},
88103
}, 1);
89104

90105
results.set({
91106
value: '32280',
92107
name: 'Optimize branch protection rule loading',
93-
type: 'pull-request',
108+
issue: {
109+
state: 'open',
110+
pull_request: {
111+
merged: false,
112+
draft: false,
113+
},
114+
},
94115
}, 2);
95116

96117
results.set({
97118
value: '32326',
98119
name: 'Shallow Mirroring',
99-
type: 'issue',
120+
issue: {
121+
state: 'open',
122+
pull_request: null,
123+
},
100124
}, 3);
101125

102126
results.set({
103127
value: '32248',
104128
name: 'Make admins adhere to branch protection rules',
105-
type: 'pull-request',
129+
issue: {
130+
state: 'closed',
131+
pull_request: {
132+
merged: true,
133+
draft: false,
134+
},
135+
},
106136
}, 4);
107137

138+
results.set({
139+
value: '32249',
140+
name: 'Add a way to disable branch protection rules for admins',
141+
issue: {
142+
state: 'closed',
143+
pull_request: null,
144+
},
145+
}, 5);
146+
108147
// filter out current issue/pull request
109148
for (const [key] of results.entries()) {
110149
if (key.value === issuePullRequestId) {

0 commit comments

Comments
 (0)