ework-web 0.10.63 → 0.10.65

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ework-web",
3
- "version": "0.10.63",
3
+ "version": "0.10.65",
4
4
  "type": "module",
5
5
  "description": "ework-web — standalone multi-project issue tracker. Local SQLite-backed, no external API dependency. Bun + TypeScript + SSR HTML.",
6
6
  "license": "MIT",
package/src/giteaApi.ts CHANGED
@@ -126,12 +126,13 @@ export async function handleGiteaApi(
126
126
  if (!(await canSudo(caller))) return giteaError(403, "sudo requires permission");
127
127
  if (!/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,63}$/.test(sudoLogin)) return giteaError(400, "invalid sudo login");
128
128
  const sudoKindRaw = req.headers.get("Sudo-Kind")?.trim();
129
+ const sudoDisplayName = req.headers.get("Sudo-Display-Name")?.trim() || null;
129
130
  const existing = await getUserByLogin(sudoLogin);
130
131
  if (existing) {
131
132
  user = existing;
132
133
  } else {
133
134
  const kind = sudoKindRaw === "bot" || sudoKindRaw === "system" ? sudoKindRaw : "human";
134
- user = await ensureUser(sudoLogin, kind);
135
+ user = await ensureUser(sudoLogin, kind, sudoDisplayName);
135
136
  }
136
137
  if (!user.is_active) return giteaError(403, "sudo target inactive");
137
138
  }
@@ -153,7 +154,7 @@ export async function handleGiteaApi(
153
154
  const limitRaw = Number(url.searchParams.get("limit") ?? 50);
154
155
  const limit = Number.isFinite(limitRaw) && limitRaw > 0 ? Math.min(limitRaw, 200) : 50;
155
156
  try {
156
- const rows = await listAllIssues({ q, state, limit, viewerLogin: user.login, viewerIsAdmin: user.is_admin === 1 });
157
+ const rows = await listAllIssues({ q, state, limit, viewerLogin: user.login, viewerIsAdmin: caller.is_admin === 1 && user.is_admin === 1 });
157
158
  const body = [];
158
159
  for (const row of rows) {
159
160
  const project = await getProject(row.project_owner, row.project_name);
package/src/index.ts CHANGED
@@ -2260,8 +2260,8 @@ async function handle(req: Request, url: URL, ip: string, ctx: { authed: boolean
2260
2260
  const dispatchCfg = await getConfigAll();
2261
2261
  const dispatchOff = dispatchCfg[`dispatchOff:${owner}/${repo}`] === "1";
2262
2262
  const globalDispatchOff = dispatchCfg["dispatchEnabled"] === "false";
2263
- const processingIssues = await listIssues(project.id, { state: "all" });
2264
- const processingCount = processingIssues.filter((it) => it.ai_status === "processing").length;
2263
+ const running = await getRunningSessionsForProject(`${owner}/${repo}`);
2264
+ const processingCount = new Set(running.map((r) => r.issueNumber)).size;
2265
2265
  return html(buildProjectAiPage(project, dispatchOff, globalDispatchOff, processingCount).html);
2266
2266
  }
2267
2267
 
@@ -19,6 +19,7 @@ export interface CommentView {
19
19
  avatar: string;
20
20
  created_at: string;
21
21
  body_html: string;
22
+ display_name?: string | null;
22
23
  reactions?: { e: string; n: number }[];
23
24
  }
24
25
 
@@ -59,7 +60,8 @@ export function renderCommentCard(c: CommentView, cfg?: { translateUrl?: string;
59
60
  `<div class="item item-${esc(tag)}" id="comment-${c.id}" data-id="${c.id}">` +
60
61
  `<div class="card"><div class="card-h">` +
61
62
  `<span class="tag tag-${esc(tag)}">${label} ${esc(tag)}</span>` +
62
- `<span class="who">${esc(c.login)}</span>` +
63
+ `<span class="who">${esc(c.display_name || c.login)}</span>` +
64
+ (c.display_name ? `<span class="who-login">${esc(c.login)}</span>` : "") +
63
65
  `<span class="when" data-ts="${esc(c.created_at)}" title="${esc(c.created_at)}">${relTime(c.created_at)}</span>` +
64
66
  rx +
65
67
  `<span class="card-actions">` + actionBarHTML({ cid: String(c.id), copy: true, link: true, translate: true, tts: true, translateEnabled, ttsEnabled }) + `</span>` +
@@ -61,6 +61,7 @@ header.topbar .num{opacity:.7}
61
61
  .card{background:var(--bg-elev);border:1px solid var(--border);border-radius:8px;overflow:hidden;min-width:0}
62
62
  .card-h{display:flex;align-items:center;gap:.5rem;padding:.4rem .7rem;background:var(--bg-muted);font-size:13px;flex-wrap:wrap}
63
63
  .card-h .who{font-weight:600;color:var(--text)}
64
+ .card-h .who-login{font-weight:400;color:var(--text-muted);font-size:.85em;margin-left:.25rem}
64
65
  .tag{font-size:11px;font-weight:600;padding:.05rem .4rem;border-radius:4px;line-height:1.5}
65
66
  .tag-human{background:color-mix(in srgb,var(--human) 18%,transparent);color:var(--human)}
66
67
  .tag-bot{background:color-mix(in srgb,var(--bot) 18%,transparent);color:var(--bot)}
package/src/static/app.js CHANGED
@@ -116,7 +116,8 @@
116
116
  `<div class="item item-${esc(tag)}${isNew}" id="comment-${c.id}" data-id="${c.id}">` +
117
117
  `<div class="card"><div class="card-h">` +
118
118
  `<span class="tag tag-${esc(tag)}">${label} ${esc(tag)}</span>` +
119
- `<span class="who">${esc(c.login)}</span>` +
119
+ `<span class="who">${esc(c.display_name || c.login)}</span>` +
120
+ (c.display_name ? `<span class="who-login">${esc(c.login)}</span>` : "") +
120
121
  `<span class="when" data-ts="${esc(c.created_at)}" title="${esc(c.created_at)}">${relTime(c.created_at)}</span>` +
121
122
  rx +
122
123
  `<span class="card-actions">` +
package/src/store.ts CHANGED
@@ -90,6 +90,7 @@ export interface CommentRow {
90
90
  created_at: string;
91
91
  updated_at: string;
92
92
  author_kind?: UserKind;
93
+ author_display_name?: string | null;
93
94
  }
94
95
 
95
96
  export interface LabelRow {
@@ -134,19 +135,24 @@ function now(): string {
134
135
  return new Date().toISOString();
135
136
  }
136
137
 
137
- export async function ensureUser(login: string, kind: UserKind = "human"): Promise<UserRow> {
138
+ export async function ensureUser(login: string, kind: UserKind = "human", displayName?: string | null): Promise<UserRow> {
138
139
  const db = getDB();
139
140
  const existing = await db.get<UserRow>("SELECT * FROM {{users}} WHERE login = ?", [login]);
140
- if (existing) return existing;
141
+ if (existing) {
142
+ if (displayName && displayName.trim() && existing.display_name !== displayName) {
143
+ await db.run("UPDATE {{users}} SET display_name = ?, updated_at = ? WHERE login = ?", [displayName, now(), login]);
144
+ }
145
+ return existing;
146
+ }
141
147
  const ts = now();
142
148
  await db.run(
143
- "INSERT INTO {{users}} (login, kind, created_at, updated_at) VALUES (?, ?, ?, ?)",
144
- [login, kind, ts, ts]
149
+ "INSERT INTO {{users}} (login, kind, display_name, created_at, updated_at) VALUES (?, ?, ?, ?, ?)",
150
+ [login, kind, displayName ?? null, ts, ts]
145
151
  );
146
152
  return {
147
153
  login,
148
154
  kind,
149
- display_name: null,
155
+ display_name: displayName ?? null,
150
156
  password_hash: null,
151
157
  email: null,
152
158
  is_admin: 0,
@@ -570,7 +576,7 @@ export async function listCommentsPage(issueId: number, page: number, pageSize:
570
576
  const clamped = Math.min(Math.max(1, page), totalPages);
571
577
  const offset = (clamped - 1) * pageSize;
572
578
  const rows = await getDB().all<CommentRow>(
573
- `SELECT c.*, u.kind AS author_kind
579
+ `SELECT c.*, u.kind AS author_kind, u.display_name AS author_display_name
574
580
  FROM {{comments}} c
575
581
  LEFT JOIN {{users}} u ON u.login = c.author
576
582
  WHERE c.issue_id = ?
@@ -583,7 +589,7 @@ export async function listCommentsPage(issueId: number, page: number, pageSize:
583
589
 
584
590
  export async function listCommentsSince(issueId: number, sinceISO: string): Promise<CommentRow[]> {
585
591
  return await getDB().all<CommentRow>(
586
- `SELECT c.*, u.kind AS author_kind
592
+ `SELECT c.*, u.kind AS author_kind, u.display_name AS author_display_name
587
593
  FROM {{comments}} c
588
594
  LEFT JOIN {{users}} u ON u.login = c.author
589
595
  WHERE c.issue_id = ? AND c.created_at > ?
@@ -594,7 +600,7 @@ export async function listCommentsSince(issueId: number, sinceISO: string): Prom
594
600
 
595
601
  export async function listCommentsForIssue(issueId: number): Promise<CommentRow[]> {
596
602
  return await getDB().all<CommentRow>(
597
- `SELECT c.*, u.kind AS author_kind
603
+ `SELECT c.*, u.kind AS author_kind, u.display_name AS author_display_name
598
604
  FROM {{comments}} c
599
605
  LEFT JOIN {{users}} u ON u.login = c.author
600
606
  WHERE c.issue_id = ?
@@ -628,7 +634,7 @@ export async function postComment(
628
634
  const row = await getDB().get<{ project_id: number }>("SELECT project_id FROM {{issues}} WHERE id = ?", [issueId]);
629
635
  await getDB().run("UPDATE {{projects}} SET updated_at = ? WHERE id = ?", [updatedAt, row!.project_id]);
630
636
  return (await getDB().get<CommentRow>(
631
- `SELECT c.*, u.kind AS author_kind
637
+ `SELECT c.*, u.kind AS author_kind, u.display_name AS author_display_name
632
638
  FROM {{comments}} c LEFT JOIN {{users}} u ON u.login = c.author
633
639
  WHERE c.id = ?`,
634
640
  [info.insertId]
@@ -638,7 +644,7 @@ export async function postComment(
638
644
 
639
645
  export async function getComment(commentId: number): Promise<CommentRow | null> {
640
646
  const row = await getDB().get<CommentRow>(
641
- `SELECT c.*, u.kind AS author_kind
647
+ `SELECT c.*, u.kind AS author_kind, u.display_name AS author_display_name
642
648
  FROM {{comments}} c LEFT JOIN {{users}} u ON u.login = c.author
643
649
  WHERE c.id = ?`,
644
650
  [commentId]
@@ -44,6 +44,7 @@ function toView(c: CommentRow): CommentView {
44
44
  avatar: "",
45
45
  created_at: c.created_at,
46
46
  body_html: renderMarkdown(c.body),
47
+ display_name: c.author_display_name ?? null,
47
48
  };
48
49
  }
49
50