ework-web 0.10.42 → 0.10.43
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/package.json +1 -1
- package/src/build.ts +1 -1
- package/src/index.ts +2 -1
- package/src/render/layout.ts +1 -1
- package/src/static/project-labels.js +53 -0
- package/src/views/projectLabels.ts +3 -30
package/package.json
CHANGED
package/src/build.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { join } from "path";
|
|
|
3
3
|
|
|
4
4
|
const STATIC = join(__dirname, "static");
|
|
5
5
|
let m = 0;
|
|
6
|
-
for (const f of ["app.js", "session.js", "file.js", "tts.js", "highlight.css"]) {
|
|
6
|
+
for (const f of ["app.js", "session.js", "file.js", "tts.js", "highlight.css", "label-picker.js", "project-labels.js", "daemon-groups.js", "db-wizard.js", "daemon-mgr.js"]) {
|
|
7
7
|
try {
|
|
8
8
|
const s = statSync(join(STATIC, f));
|
|
9
9
|
if (s.mtimeMs > m) m = s.mtimeMs;
|
package/src/index.ts
CHANGED
|
@@ -467,6 +467,7 @@ async function handle(req: Request, url: URL, ip: string, ctx: { authed: boolean
|
|
|
467
467
|
if (url.pathname === "/static/daemon-mgr.js") return staticAsset("daemon-mgr.js", "text/javascript; charset=utf-8", req);
|
|
468
468
|
if (url.pathname === "/static/daemon-groups.js") return staticAsset("daemon-groups.js", "text/javascript; charset=utf-8", req);
|
|
469
469
|
if (url.pathname === "/static/label-picker.js") return staticAsset("label-picker.js", "text/javascript; charset=utf-8", req);
|
|
470
|
+
if (url.pathname === "/static/project-labels.js") return staticAsset("project-labels.js", "text/javascript; charset=utf-8", req);
|
|
470
471
|
if (url.pathname === "/static/session.js") return staticAsset("session.js", "text/javascript; charset=utf-8", req);
|
|
471
472
|
if (url.pathname === "/static/file.js") return staticAsset("file.js", "text/javascript; charset=utf-8", req);
|
|
472
473
|
if (url.pathname === "/static/tts.js") return staticAsset("tts.js", "text/javascript; charset=utf-8", req);
|
|
@@ -1837,7 +1838,7 @@ async function handle(req: Request, url: URL, ip: string, ctx: { authed: boolean
|
|
|
1837
1838
|
const project = await getProject(owner, repo);
|
|
1838
1839
|
if (!project) return html(errorPage("项目不存在", ""), 404);
|
|
1839
1840
|
const back = `${url.origin}/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/settings/labels`;
|
|
1840
|
-
if (!(await
|
|
1841
|
+
if (!(await canWriteProject(project.id, ctx.user))) {
|
|
1841
1842
|
return Response.redirect(`${back}?err=${encodeURIComponent("无权限")}`, 303);
|
|
1842
1843
|
}
|
|
1843
1844
|
const form = await req.formData().catch(() => new FormData());
|
package/src/render/layout.ts
CHANGED
|
@@ -141,7 +141,7 @@ export function renderLayout(props: LayoutProps, inner: string, initialItems: st
|
|
|
141
141
|
const repoIssuesHref = `/${encodeURIComponent(repoOwner ?? "")}/${encodeURIComponent(repoName ?? "")}/issues`;
|
|
142
142
|
const op = props.operatorLogin ?? "operator";
|
|
143
143
|
const labelsHtml = (props.labels ?? []).length
|
|
144
|
-
? props.labels!.map((l) => `<
|
|
144
|
+
? props.labels!.map((l) => `<a class="issue-label" href="${repoIssuesHref}?state=all&label=${encodeURIComponent(l.name)}" style="border-color:${escapeAttr(l.color)};color:${escapeAttr(l.color)}">${escapeHtml(l.name)}</a>`).join("")
|
|
145
145
|
: "";
|
|
146
146
|
const labelPickerBtn = props.canEditLabels
|
|
147
147
|
? `<button type="button" class="label-edit-btn" id="labelEditBtn" title="管理标签">🏷️</button>`
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
(function () {
|
|
2
|
+
var dataEl = document.getElementById('label-data');
|
|
3
|
+
if (!dataEl) return;
|
|
4
|
+
var data = JSON.parse(dataEl.textContent || '{}');
|
|
5
|
+
var palette = data.palette || [];
|
|
6
|
+
var LABELS = data.labels || [];
|
|
7
|
+
|
|
8
|
+
function bindSwatches(container, colorInput) {
|
|
9
|
+
if (!container || !colorInput) return;
|
|
10
|
+
container.innerHTML = palette.map(function (c) {
|
|
11
|
+
return '<button type="button" class="swatch" data-color="' + c + '" style="background:' + c + '" aria-label="' + c + '"></button>';
|
|
12
|
+
}).join('');
|
|
13
|
+
function sync() {
|
|
14
|
+
container.querySelectorAll('.swatch').forEach(function (b) {
|
|
15
|
+
b.classList.toggle('sel', b.dataset.color.toLowerCase() === colorInput.value.toLowerCase());
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
sync();
|
|
19
|
+
container.addEventListener('click', function (e) {
|
|
20
|
+
var b = e.target.closest('.swatch');
|
|
21
|
+
if (!b) return;
|
|
22
|
+
colorInput.value = b.dataset.color;
|
|
23
|
+
sync();
|
|
24
|
+
});
|
|
25
|
+
colorInput.addEventListener('input', sync);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
bindSwatches(document.getElementById('palette'), document.getElementById('f-color'));
|
|
29
|
+
|
|
30
|
+
var dlg = document.getElementById('dlg');
|
|
31
|
+
if (!dlg) return;
|
|
32
|
+
var ef = document.getElementById('edit-form');
|
|
33
|
+
var dp = document.getElementById('dlg-palette');
|
|
34
|
+
var dlgColor;
|
|
35
|
+
|
|
36
|
+
document.addEventListener('click', function (e) {
|
|
37
|
+
var btn = e.target.closest('[data-edit-btn]');
|
|
38
|
+
if (!btn) return;
|
|
39
|
+
var id = Number(btn.dataset.editBtn);
|
|
40
|
+
var l = LABELS.find(function (x) { return x.id === id; });
|
|
41
|
+
if (!l) return;
|
|
42
|
+
ef.action = btn.form.action;
|
|
43
|
+
ef.querySelector('[name=name]').value = l.name;
|
|
44
|
+
ef.querySelector('[name=color]').value = l.color;
|
|
45
|
+
dlgColor = ef.querySelector('[name=color]');
|
|
46
|
+
ef.querySelector('[name=description]').value = l.description;
|
|
47
|
+
ef.querySelector('[name=exclusive]').checked = l.exclusive === 1;
|
|
48
|
+
bindSwatches(dp, dlgColor);
|
|
49
|
+
dlg.showModal();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
document.getElementById('dlg-cancel').addEventListener('click', function () { dlg.close(); });
|
|
53
|
+
})();
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { THEME_CSS, escapeHtml, escapeAttr } from "../render/layout";
|
|
2
|
+
import { BUILD_ID } from "../build";
|
|
2
3
|
import { projectSettingsTabsHTML } from "./projectUpstreams";
|
|
3
4
|
import { listLabels, type ProjectRow, type UserRow, type LabelRow } from "../store";
|
|
4
5
|
|
|
@@ -58,7 +59,6 @@ export async function buildProjectLabelsPage(
|
|
|
58
59
|
const flashHtml = flash ? `<div class="flash ${flash.kind}">${escapeHtml(flash.msg)}</div>` : "";
|
|
59
60
|
const createAction = `/${encodeURIComponent(project.owner)}/${encodeURIComponent(project.name)}/settings/labels/add`;
|
|
60
61
|
const paletteHtml = PALETTE.map((c) => `<button type="button" class="swatch" data-color="${c}" style="background:${c}" aria-label="${c}"></button>`).join("");
|
|
61
|
-
const labelsJson = JSON.stringify(labels.map((l) => ({ id: l.id, name: l.name, color: l.color, description: l.description, exclusive: l.exclusive, is_archived: l.is_archived })));
|
|
62
62
|
|
|
63
63
|
return `<!doctype html>
|
|
64
64
|
<html lang="zh"><head><meta charset="utf-8">
|
|
@@ -157,34 +157,7 @@ ${rowsHtml}
|
|
|
157
157
|
</div>
|
|
158
158
|
</form>
|
|
159
159
|
</dialog>
|
|
160
|
-
<script>
|
|
161
|
-
|
|
162
|
-
const palette = ${JSON.stringify(PALETTE)};
|
|
163
|
-
function bindSwatches(container, colorInput){
|
|
164
|
-
container.innerHTML = palette.map(c => '<button type="button" class="swatch" data-color="'+c+'" style="background:'+c+'" aria-label="'+c+'"></button>').join('');
|
|
165
|
-
const sync = ()=>{ container.querySelectorAll('.swatch').forEach(b=>b.classList.toggle('sel', b.dataset.color.toLowerCase()===colorInput.value.toLowerCase())); };
|
|
166
|
-
sync();
|
|
167
|
-
container.addEventListener('click', e=>{ const b=e.target.closest('.swatch'); if(!b)return; colorInput.value=b.dataset.color; sync(); });
|
|
168
|
-
colorInput.addEventListener('input', sync);
|
|
169
|
-
}
|
|
170
|
-
bindSwatches(document.getElementById('palette'), document.getElementById('f-color'));
|
|
171
|
-
const dlg=document.getElementById('dlg'), ef=document.getElementById('edit-form'), dp=document.getElementById('dlg-palette');
|
|
172
|
-
let dlgColor;
|
|
173
|
-
document.addEventListener('click', e=>{
|
|
174
|
-
const btn=e.target.closest('[data-edit-btn]');
|
|
175
|
-
if(!btn)return;
|
|
176
|
-
const id=Number(btn.dataset.editBtn);
|
|
177
|
-
const l=LABELS.find(x=>x.id===id); if(!l)return;
|
|
178
|
-
ef.action=btn.form.action;
|
|
179
|
-
ef.querySelector('[name=name]').value=l.name;
|
|
180
|
-
ef.querySelector('[name=color]').value=l.color;
|
|
181
|
-
dlgColor=ef.querySelector('[name=color]');
|
|
182
|
-
ef.querySelector('[name=description]').value=l.description;
|
|
183
|
-
ef.querySelector('[name=exclusive]').checked=l.exclusive===1;
|
|
184
|
-
bindSwatches(dp, dlgColor);
|
|
185
|
-
dlg.showModal();
|
|
186
|
-
});
|
|
187
|
-
document.getElementById('dlg-cancel').addEventListener('click', ()=>dlg.close());
|
|
188
|
-
</script>
|
|
160
|
+
<script type="application/json" id="label-data">${JSON.stringify({ labels: labels.map((l) => ({ id: l.id, name: l.name, color: l.color, description: l.description, exclusive: l.exclusive, is_archived: l.is_archived })), palette: PALETTE })}</script>
|
|
161
|
+
<script src="/static/project-labels.js?v=${BUILD_ID}" defer></script>
|
|
189
162
|
</body></html>`;
|
|
190
163
|
}
|