texlite 0.8.4 → 0.9.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/DESIGN.md +75 -8
- package/OPERATIONS.md +19 -2
- package/dist/client/assets/{AdminUsers-CqOmV9rq.js → AdminUsers-3CHb5012.js} +1 -1
- package/dist/client/assets/{CitationLibraryDialog-BmWFXTW2.js → CitationLibraryDialog-zPpsUhWJ.js} +1 -1
- package/dist/client/assets/Dashboard-CWfSLzD3.js +2 -0
- package/dist/client/assets/{GitDialog-BCfSHuMB.js → GitDialog-BUU2U_LV.js} +2 -2
- package/dist/client/assets/HistoryDialog-B6aopsrw.js +7 -0
- package/dist/client/assets/{LatexEditor-DSopAHbC.js → LatexEditor-CM445Tk0.js} +1 -1
- package/dist/client/assets/{PdfPreview-BDkU20jP.js → PdfPreview-BFVNczSk.js} +1 -1
- package/dist/client/assets/{ProjectIconPickerDialog-GAd8HGOx.js → ProjectIconPickerDialog-Cf0zBf8u.js} +1 -1
- package/dist/client/assets/{ProjectNavigationDialogs-BTLcRY7i.js → ProjectNavigationDialogs-TPbe11iR.js} +1 -1
- package/dist/client/assets/{ProjectSettings-BJWTkoZq.js → ProjectSettings-CDQvIlQ4.js} +1 -1
- package/dist/client/assets/ProjectWorkspace-C6GrvKN6.js +27 -0
- package/dist/client/assets/SelectionHistoryDialog-CyE0_YDs.js +3 -0
- package/dist/client/assets/{SystemMetricsDialog-C9P4TSQl.js → SystemMetricsDialog-CuqHPUnn.js} +1 -1
- package/dist/client/assets/{TagManagementDialog-LYbib36_.js → TagManagementDialog-gRLM3lLx.js} +1 -1
- package/dist/client/assets/{WordCountDialog-BFg0GeJy.js → WordCountDialog-B4PI0vEk.js} +1 -1
- package/dist/client/assets/check-BXvzrdoz.js +1 -0
- package/dist/client/assets/chevron-left-BB5MYb7g.js +1 -0
- package/dist/client/assets/hard-drive-6uYFyezl.js +1 -0
- package/dist/client/assets/index-BRT5O-Hg.js +5 -0
- package/dist/client/assets/index-C0t11tlT.js +14 -0
- package/dist/client/assets/index-DXWp2bzM.css +1 -0
- package/dist/client/assets/{key-round-BaIj7Jch.js → key-round-DOAxDSfz.js} +1 -1
- package/dist/client/assets/minimize-2-BWtbag2I.js +1 -0
- package/dist/client/assets/{minus-Beso_n-6.js → minus-9eVJnugf.js} +1 -1
- package/dist/client/assets/{plus-BfEC7mzf.js → plus-BGXipRoG.js} +1 -1
- package/dist/client/assets/{refresh-cw-FZs9MtoA.js → refresh-cw-Dvp3O90f.js} +1 -1
- package/dist/client/assets/{search-DL2UGvdj.js → search-b1ORp1k8.js} +1 -1
- package/dist/client/assets/{sigma-CSRwPPkk.js → sigma-Bk0_MzWi.js} +1 -1
- package/dist/client/assets/{spellCheck-L9gD2d1M.js → spellCheck-BJjWgnef.js} +1 -1
- package/dist/client/assets/{tags-CjkWzXqX.js → tags-JAkbmWns.js} +1 -1
- package/dist/client/assets/{type-D1mmDdLM.js → type-CE2DYkPH.js} +1 -1
- package/dist/client/assets/{user-plus-YJ3ftuL5.js → user-plus-CKalKSsw.js} +1 -1
- package/dist/client/assets/x-Bq29njHL.js +1 -0
- package/dist/client/index.html +2 -2
- package/dist/server/app.js +45 -4
- package/dist/server/cli.js +4 -0
- package/dist/server/collaboration.js +219 -7
- package/dist/server/commentMentions.js +139 -0
- package/dist/server/config.js +9 -2
- package/dist/server/db.js +59 -0
- package/dist/server/editHistory.js +411 -0
- package/dist/server/editHistoryRetry.js +90 -0
- package/dist/server/history.js +136 -20
- package/dist/server/historyRetention.js +37 -0
- package/dist/server/i18n.js +4 -0
- package/dist/server/index.js +6 -0
- package/dist/server/logRotation.js +82 -0
- package/dist/server/pm2.js +7 -0
- package/dist/server/routes/comments.js +107 -16
- package/dist/server/routes/projectHistory.js +93 -7
- package/dist/server/routes/projectShared.js +2 -1
- package/dist/server/routes/projects.js +3 -1
- package/package.json +1 -1
- package/texlite.config.example.json +4 -1
- package/dist/client/assets/Dashboard-BfN2bCgZ.js +0 -2
- package/dist/client/assets/HistoryDialog-BtQhyTr9.js +0 -5
- package/dist/client/assets/ProjectWorkspace-WLYA7BSv.js +0 -27
- package/dist/client/assets/check-bnimQPun.js +0 -1
- package/dist/client/assets/chevron-left-DNM7mhNi.js +0 -1
- package/dist/client/assets/hard-drive-CF3WDfkG.js +0 -1
- package/dist/client/assets/index-CzVDvC5h.js +0 -14
- package/dist/client/assets/index-RjUuWk8F.css +0 -1
- package/dist/client/assets/x-BDSEosRE.js +0 -1
|
@@ -5,10 +5,71 @@ import { createSourceAnchor, offsetToLine } from "../anchors.js";
|
|
|
5
5
|
import { resolveSourcePath, safeRelativePath } from "../files.js";
|
|
6
6
|
import { apiError, httpError } from "../http.js";
|
|
7
7
|
import { accessibleProject } from "../projects.js";
|
|
8
|
+
import { commentMentionForUser, createCommentMentions, listCommentMentions, markAllCommentMentionsRead, markCommentMentionRead, markCommentMentionsResolved, mentionableUsersForProject } from "../commentMentions.js";
|
|
8
9
|
import { commentsForFile, now, repliesForComment, text } from "./projectShared.js";
|
|
9
10
|
/** Register source-anchored comments and reply routes. */
|
|
10
11
|
export function registerCommentRoutes(app, context) {
|
|
11
12
|
const { config, db, collaboration, projectMutations } = context;
|
|
13
|
+
app.get("/api/projects/:id/mention-candidates", async (request, reply) => {
|
|
14
|
+
const user = requireUser(request, reply, db);
|
|
15
|
+
if (!user)
|
|
16
|
+
return;
|
|
17
|
+
const { id } = request.params;
|
|
18
|
+
if (!accessibleProject(db, id, user))
|
|
19
|
+
return apiError(reply, 404, "PROJECT_NOT_FOUND");
|
|
20
|
+
// Mentions are intended to notify another participant. Excluding the
|
|
21
|
+
// author avoids offering a no-op self notification in every composer.
|
|
22
|
+
return { users: mentionableUsersForProject(db, id, user.id) };
|
|
23
|
+
});
|
|
24
|
+
app.get("/api/projects/:id/mentions", async (request, reply) => {
|
|
25
|
+
const user = requireUser(request, reply, db);
|
|
26
|
+
if (!user)
|
|
27
|
+
return;
|
|
28
|
+
const { id } = request.params;
|
|
29
|
+
if (!accessibleProject(db, id, user))
|
|
30
|
+
return apiError(reply, 404, "PROJECT_NOT_FOUND");
|
|
31
|
+
const query = request.query;
|
|
32
|
+
const requestedLimit = Number.parseInt(query.limit ?? "50", 10);
|
|
33
|
+
return {
|
|
34
|
+
mentions: listCommentMentions(db, id, user.id, {
|
|
35
|
+
unreadOnly: query.unread === "1" || query.unread === "true",
|
|
36
|
+
limit: Number.isFinite(requestedLimit) ? requestedLimit : 50,
|
|
37
|
+
filePath: typeof query.path === "string" && query.path ? safeRelativePath(query.path) : undefined
|
|
38
|
+
})
|
|
39
|
+
};
|
|
40
|
+
});
|
|
41
|
+
app.get("/api/projects/:id/mentions/:mentionId", async (request, reply) => {
|
|
42
|
+
const user = requireUser(request, reply, db);
|
|
43
|
+
if (!user)
|
|
44
|
+
return;
|
|
45
|
+
const { id, mentionId } = request.params;
|
|
46
|
+
if (!accessibleProject(db, id, user))
|
|
47
|
+
return apiError(reply, 404, "PROJECT_NOT_FOUND");
|
|
48
|
+
const mention = commentMentionForUser(db, mentionId, id, user.id);
|
|
49
|
+
if (!mention)
|
|
50
|
+
return apiError(reply, 404, "MENTION_NOT_FOUND");
|
|
51
|
+
return { mention };
|
|
52
|
+
});
|
|
53
|
+
app.post("/api/projects/:id/mentions/:mentionId/read", async (request, reply) => {
|
|
54
|
+
const user = requireUser(request, reply, db);
|
|
55
|
+
if (!user)
|
|
56
|
+
return;
|
|
57
|
+
const { id, mentionId } = request.params;
|
|
58
|
+
if (!accessibleProject(db, id, user))
|
|
59
|
+
return apiError(reply, 404, "PROJECT_NOT_FOUND");
|
|
60
|
+
if (!commentMentionForUser(db, mentionId, id, user.id))
|
|
61
|
+
return apiError(reply, 404, "MENTION_NOT_FOUND");
|
|
62
|
+
return { ok: true, changed: markCommentMentionRead(db, mentionId, user.id, now(), "manual") };
|
|
63
|
+
});
|
|
64
|
+
app.post("/api/projects/:id/mentions/read-all", async (request, reply) => {
|
|
65
|
+
const user = requireUser(request, reply, db);
|
|
66
|
+
if (!user)
|
|
67
|
+
return;
|
|
68
|
+
const { id } = request.params;
|
|
69
|
+
if (!accessibleProject(db, id, user))
|
|
70
|
+
return apiError(reply, 404, "PROJECT_NOT_FOUND");
|
|
71
|
+
return { ok: true, changed: markAllCommentMentionsRead(db, id, user.id, now()) };
|
|
72
|
+
});
|
|
12
73
|
app.get("/api/projects/:id/comments", async (request, reply) => {
|
|
13
74
|
const user = requireUser(request, reply, db);
|
|
14
75
|
if (!user)
|
|
@@ -50,11 +111,17 @@ export function registerCommentRoutes(app, context) {
|
|
|
50
111
|
id: randomUUID(), filePath,
|
|
51
112
|
content: text(body.content, 5000)
|
|
52
113
|
};
|
|
53
|
-
db.
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
114
|
+
db.transaction(() => {
|
|
115
|
+
db.prepare(`INSERT INTO comments
|
|
116
|
+
(id, project_id, file_path, author_id, selected_text, start_offset, end_offset,
|
|
117
|
+
context_before, context_after, orphaned, start_line, end_line, content, created_at, updated_at)
|
|
118
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 0, ?, ?, ?, ?, ?)`)
|
|
119
|
+
.run(comment.id, id, comment.filePath, user.id, anchor.selectedText, anchor.startOffset, anchor.endOffset, anchor.contextBefore, anchor.contextAfter, offsetToLine(source, anchor.startOffset), offsetToLine(source, anchor.endOffset), comment.content, createdAt, createdAt);
|
|
120
|
+
createCommentMentions(db, {
|
|
121
|
+
projectId: id, commentId: comment.id, authorId: user.id,
|
|
122
|
+
content: comment.content, createdAt
|
|
123
|
+
});
|
|
124
|
+
})();
|
|
58
125
|
const created = commentsForFile(db, config, id, filePath).find((item) => item.id === comment.id);
|
|
59
126
|
collaboration.signalComments(id);
|
|
60
127
|
return reply.code(201).send({ comment: created });
|
|
@@ -76,9 +143,15 @@ export function registerCommentRoutes(app, context) {
|
|
|
76
143
|
const body = request.body;
|
|
77
144
|
const createdAt = now();
|
|
78
145
|
const replyId = randomUUID();
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
.
|
|
146
|
+
const content = text(body.content, 5000);
|
|
147
|
+
db.transaction(() => {
|
|
148
|
+
db.prepare(`INSERT INTO comment_replies (id, comment_id, author_id, content, created_at, updated_at)
|
|
149
|
+
VALUES (?, ?, ?, ?, ?, ?)`)
|
|
150
|
+
.run(replyId, commentId, user.id, content, createdAt, createdAt);
|
|
151
|
+
createCommentMentions(db, {
|
|
152
|
+
projectId: id, commentId, replyId, authorId: user.id, content, createdAt
|
|
153
|
+
});
|
|
154
|
+
})();
|
|
82
155
|
const created = repliesForComment(db, commentId).find((item) => item.id === replyId);
|
|
83
156
|
collaboration.signalComments(id);
|
|
84
157
|
return reply.code(201).send({ reply: created });
|
|
@@ -90,27 +163,39 @@ export function registerCommentRoutes(app, context) {
|
|
|
90
163
|
const { id, commentId } = request.params;
|
|
91
164
|
if (!accessibleProject(db, id, user))
|
|
92
165
|
return apiError(reply, 404, "PROJECT_NOT_FOUND");
|
|
93
|
-
const comment = db.prepare("SELECT author_id FROM comments WHERE id = ? AND project_id = ?")
|
|
166
|
+
const comment = db.prepare("SELECT author_id, resolved, content FROM comments WHERE id = ? AND project_id = ?")
|
|
94
167
|
.get(commentId, id);
|
|
95
168
|
if (!comment)
|
|
96
169
|
return apiError(reply, 404, "COMMENT_NOT_FOUND");
|
|
97
170
|
const body = request.body;
|
|
98
171
|
const changedAt = now();
|
|
99
172
|
let changed = false;
|
|
173
|
+
const content = typeof body.content === "string" ? text(body.content, 5000) : null;
|
|
100
174
|
if (typeof body.content === "string") {
|
|
101
175
|
if (comment.author_id !== user.id)
|
|
102
176
|
return apiError(reply, 403, "COMMENT_EDIT_FORBIDDEN");
|
|
103
|
-
db.prepare("UPDATE comments SET content = ?, updated_at = ?, edited_at = ? WHERE id = ?")
|
|
104
|
-
.run(text(body.content, 5000), changedAt, changedAt, commentId);
|
|
105
177
|
changed = true;
|
|
106
178
|
}
|
|
107
179
|
if (typeof body.resolved === "boolean") {
|
|
108
|
-
db.prepare("UPDATE comments SET resolved = ?, updated_at = ? WHERE id = ?")
|
|
109
|
-
.run(body.resolved ? 1 : 0, changedAt, commentId);
|
|
110
180
|
changed = true;
|
|
111
181
|
}
|
|
112
182
|
if (!changed)
|
|
113
183
|
return apiError(reply, 400, "COMMENT_UPDATE_EMPTY");
|
|
184
|
+
db.transaction(() => {
|
|
185
|
+
if (content !== null) {
|
|
186
|
+
db.prepare("UPDATE comments SET content = ?, updated_at = ?, edited_at = ? WHERE id = ?")
|
|
187
|
+
.run(content, changedAt, changedAt, commentId);
|
|
188
|
+
createCommentMentions(db, {
|
|
189
|
+
projectId: id, commentId, authorId: user.id, content, previousContent: comment.content, createdAt: changedAt
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
if (typeof body.resolved === "boolean") {
|
|
193
|
+
db.prepare("UPDATE comments SET resolved = ?, updated_at = ? WHERE id = ?")
|
|
194
|
+
.run(body.resolved ? 1 : 0, changedAt, commentId);
|
|
195
|
+
if (body.resolved && !comment.resolved)
|
|
196
|
+
markCommentMentionsResolved(db, commentId, changedAt);
|
|
197
|
+
}
|
|
198
|
+
})();
|
|
114
199
|
collaboration.signalComments(id);
|
|
115
200
|
return { ok: true };
|
|
116
201
|
});
|
|
@@ -138,7 +223,7 @@ export function registerCommentRoutes(app, context) {
|
|
|
138
223
|
const { id, commentId, replyId } = request.params;
|
|
139
224
|
if (!accessibleProject(db, id, user))
|
|
140
225
|
return apiError(reply, 404, "PROJECT_NOT_FOUND");
|
|
141
|
-
const commentReply = db.prepare(`SELECT reply.author_id FROM comment_replies reply
|
|
226
|
+
const commentReply = db.prepare(`SELECT reply.author_id, reply.content FROM comment_replies reply
|
|
142
227
|
JOIN comments comment ON comment.id = reply.comment_id
|
|
143
228
|
WHERE reply.id = ? AND reply.comment_id = ? AND comment.project_id = ?`)
|
|
144
229
|
.get(replyId, commentId, id);
|
|
@@ -148,8 +233,14 @@ export function registerCommentRoutes(app, context) {
|
|
|
148
233
|
return apiError(reply, 403, "REPLY_EDIT_FORBIDDEN");
|
|
149
234
|
const body = request.body;
|
|
150
235
|
const changedAt = now();
|
|
151
|
-
|
|
152
|
-
|
|
236
|
+
const content = text(body.content, 5000);
|
|
237
|
+
db.transaction(() => {
|
|
238
|
+
db.prepare("UPDATE comment_replies SET content = ?, updated_at = ?, edited_at = ? WHERE id = ?")
|
|
239
|
+
.run(content, changedAt, changedAt, replyId);
|
|
240
|
+
createCommentMentions(db, {
|
|
241
|
+
projectId: id, commentId, replyId, authorId: user.id, content, previousContent: commentReply.content, createdAt: changedAt
|
|
242
|
+
});
|
|
243
|
+
})();
|
|
153
244
|
const updated = repliesForComment(db, commentId).find((item) => item.id === replyId);
|
|
154
245
|
collaboration.signalComments(id);
|
|
155
246
|
return { reply: updated };
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import { requireUser } from "../auth.js";
|
|
3
|
+
import { isCollaborativeTextFile, maxCollaborativeFileBytes } from "../collaboration.js";
|
|
4
|
+
import { hashText } from "../editHistory.js";
|
|
5
|
+
import { HISTORY_RETENTION_DELAY_MS } from "../historyRetention.js";
|
|
3
6
|
import { resolveSourcePath, safeRelativePath } from "../files.js";
|
|
4
7
|
import { apiError, httpError } from "../http.js";
|
|
5
8
|
import { MAX_TEXT_PREVIEW_BYTES } from "../limits.js";
|
|
@@ -7,7 +10,75 @@ import { accessibleProject, canEdit } from "../projects.js";
|
|
|
7
10
|
import { commentsSummaryForProject, projectJson, projectTextSnapshot, reanchorProjectSnapshot, requireEditableProject, requireProjectOwnerPermission, tagsForProject, text, touchProject } from "./projectShared.js";
|
|
8
11
|
/** Register retained project version listing, inspection, restoration, and cleanup routes. */
|
|
9
12
|
export function registerProjectHistoryRoutes(app, context) {
|
|
10
|
-
const { config, db, history, projectMutations, recordHistory } = context;
|
|
13
|
+
const { config, db, history, editHistory, projectMutations, recordHistory } = context;
|
|
14
|
+
app.get("/api/projects/:id/edit-history/stats", async (request, reply) => {
|
|
15
|
+
const user = requireUser(request, reply, db);
|
|
16
|
+
if (!user)
|
|
17
|
+
return;
|
|
18
|
+
const { id } = request.params;
|
|
19
|
+
if (accessibleProject(db, id, user)?.permission !== "owner")
|
|
20
|
+
return apiError(reply, 403, "PROJECT_OWNER_ONLY");
|
|
21
|
+
return editHistory.stats(id);
|
|
22
|
+
});
|
|
23
|
+
app.delete("/api/projects/:id/edit-history", async (request, reply) => {
|
|
24
|
+
const user = requireUser(request, reply, db);
|
|
25
|
+
if (!user)
|
|
26
|
+
return;
|
|
27
|
+
const { id } = request.params;
|
|
28
|
+
if (accessibleProject(db, id, user)?.permission !== "owner")
|
|
29
|
+
return apiError(reply, 403, "PROJECT_OWNER_ONLY");
|
|
30
|
+
return await projectMutations.runWrite(id, () => {
|
|
31
|
+
editHistory.clear(id);
|
|
32
|
+
context.clearPendingEdits(id);
|
|
33
|
+
return editHistory.stats(id);
|
|
34
|
+
}, { preflight: () => { requireProjectOwnerPermission(db, id, user); } });
|
|
35
|
+
});
|
|
36
|
+
/**
|
|
37
|
+
* Return only author-attributed edits that can be mapped to the caller's
|
|
38
|
+
* current selection. Recovery snapshots live under /history and deliberately
|
|
39
|
+
* remain a separate concern.
|
|
40
|
+
*/
|
|
41
|
+
app.get("/api/projects/:id/edit-history", async (request, reply) => {
|
|
42
|
+
const user = requireUser(request, reply, db);
|
|
43
|
+
if (!user)
|
|
44
|
+
return;
|
|
45
|
+
const { id } = request.params;
|
|
46
|
+
if (!accessibleProject(db, id, user))
|
|
47
|
+
return apiError(reply, 404, "PROJECT_NOT_FOUND");
|
|
48
|
+
const query = request.query;
|
|
49
|
+
if (typeof query.sourceHash !== "string" || !/^[a-f0-9]{64}$/.test(query.sourceHash))
|
|
50
|
+
return apiError(reply, 400, "REQUEST_INVALID");
|
|
51
|
+
let filePath;
|
|
52
|
+
try {
|
|
53
|
+
filePath = safeRelativePath(query.path ?? "");
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
return apiError(reply, 400, "REQUEST_INVALID");
|
|
57
|
+
}
|
|
58
|
+
if (!isCollaborativeTextFile(filePath))
|
|
59
|
+
return apiError(reply, 400, "REQUEST_INVALID");
|
|
60
|
+
const start = parseOffset(query.start);
|
|
61
|
+
const end = parseOffset(query.end);
|
|
62
|
+
if (start === null || end === null || start === end)
|
|
63
|
+
return apiError(reply, 400, "REQUEST_INVALID");
|
|
64
|
+
const requestedLimit = parseOffset(query.limit);
|
|
65
|
+
return await projectMutations.runConsistentRead(id, () => {
|
|
66
|
+
const source = resolveSourcePath(config, id, filePath);
|
|
67
|
+
if (!fs.existsSync(source) || !fs.statSync(source).isFile())
|
|
68
|
+
return apiError(reply, 404, "FILE_NOT_FOUND", { path: filePath });
|
|
69
|
+
if (fs.statSync(source).size > maxCollaborativeFileBytes(config))
|
|
70
|
+
return apiError(reply, 413, "FILE_TOO_LARGE", { path: filePath });
|
|
71
|
+
const content = fs.readFileSync(source, "utf8");
|
|
72
|
+
if (hashText(content) !== query.sourceHash)
|
|
73
|
+
return apiError(reply, 409, "SELECTION_HISTORY_SOURCE_CHANGED");
|
|
74
|
+
if (start > end || end > content.length)
|
|
75
|
+
return apiError(reply, 400, "REQUEST_INVALID");
|
|
76
|
+
return editHistory.selectionHistory(id, filePath, content, start, end, requestedLimit ?? undefined);
|
|
77
|
+
}, { preflight: () => {
|
|
78
|
+
if (!accessibleProject(db, id, user))
|
|
79
|
+
throw httpError(404, "PROJECT_NOT_FOUND");
|
|
80
|
+
} });
|
|
81
|
+
});
|
|
11
82
|
app.get("/api/projects/:id/history", async (request, reply) => {
|
|
12
83
|
const user = requireUser(request, reply, db);
|
|
13
84
|
if (!user)
|
|
@@ -16,10 +87,14 @@ export function registerProjectHistoryRoutes(app, context) {
|
|
|
16
87
|
const project = accessibleProject(db, id, user);
|
|
17
88
|
if (!project)
|
|
18
89
|
return apiError(reply, 404, "PROJECT_NOT_FOUND");
|
|
19
|
-
const
|
|
20
|
-
|
|
90
|
+
const query = request.query;
|
|
91
|
+
if (query.before !== undefined && typeof query.before !== "string")
|
|
92
|
+
return apiError(reply, 400, "REQUEST_INVALID");
|
|
93
|
+
const limit = typeof query.limit === "string" ? Number.parseInt(query.limit, 10) : 100;
|
|
94
|
+
const page = history.listPage(id, Number.isFinite(limit) ? limit : 100, query.before);
|
|
21
95
|
return {
|
|
22
|
-
versions:
|
|
96
|
+
versions: page.versions,
|
|
97
|
+
nextCursor: page.nextCursor,
|
|
23
98
|
stats: project.permission === "owner" ? history.stats(id) : null
|
|
24
99
|
};
|
|
25
100
|
});
|
|
@@ -54,8 +129,10 @@ export function registerProjectHistoryRoutes(app, context) {
|
|
|
54
129
|
if (historical === null)
|
|
55
130
|
return apiError(reply, 415, "HISTORY_FILE_PREVIEW_UNSUPPORTED", { path: filePath });
|
|
56
131
|
let comparison = "";
|
|
132
|
+
const previousVersion = query.against === "__previous__" ? history.previousVersion(id, versionId) : null;
|
|
133
|
+
const against = query.against === "__previous__" ? previousVersion?.id ?? "__none__" : query.against;
|
|
57
134
|
if (query.against) {
|
|
58
|
-
comparison = history.readTextFile(id,
|
|
135
|
+
comparison = history.readTextFile(id, against, filePath) ?? "";
|
|
59
136
|
}
|
|
60
137
|
else {
|
|
61
138
|
const current = resolveSourcePath(config, id, filePath);
|
|
@@ -63,7 +140,7 @@ export function registerProjectHistoryRoutes(app, context) {
|
|
|
63
140
|
comparison = fs.readFileSync(current, "utf8");
|
|
64
141
|
}
|
|
65
142
|
}
|
|
66
|
-
return { path: filePath, historical, comparison, against:
|
|
143
|
+
return { path: filePath, historical, comparison, against: against ?? "current", previousVersion };
|
|
67
144
|
}, { preflight: () => {
|
|
68
145
|
if (!accessibleProject(db, id, user))
|
|
69
146
|
throw httpError(404, "PROJECT_NOT_FOUND");
|
|
@@ -82,7 +159,10 @@ export function registerProjectHistoryRoutes(app, context) {
|
|
|
82
159
|
const version = history.setLabel(id, versionId, label);
|
|
83
160
|
if (!version)
|
|
84
161
|
return apiError(reply, 404, "HISTORY_VERSION_NOT_FOUND");
|
|
85
|
-
|
|
162
|
+
if (!label)
|
|
163
|
+
context.scheduleHistoryRetention(id);
|
|
164
|
+
return { version, retentionScheduled: !label, retentionRefreshAfterMs: !label ? HISTORY_RETENTION_DELAY_MS + 1_000 : 0,
|
|
165
|
+
stats: project.permission === "owner" ? history.stats(id) : null };
|
|
86
166
|
});
|
|
87
167
|
app.delete("/api/projects/:id/history/:versionId", async (request, reply) => {
|
|
88
168
|
const user = requireUser(request, reply, db);
|
|
@@ -148,3 +228,9 @@ export function registerProjectHistoryRoutes(app, context) {
|
|
|
148
228
|
} });
|
|
149
229
|
});
|
|
150
230
|
}
|
|
231
|
+
function parseOffset(value) {
|
|
232
|
+
if (value === undefined || !/^\d+$/.test(value))
|
|
233
|
+
return null;
|
|
234
|
+
const parsed = Number.parseInt(value, 10);
|
|
235
|
+
return Number.isSafeInteger(parsed) ? parsed : null;
|
|
236
|
+
}
|
|
@@ -83,7 +83,7 @@ export function commentsSummaryForProject(db, projectId) {
|
|
|
83
83
|
unresolvedCount: Number(row?.unresolved_count) || 0
|
|
84
84
|
};
|
|
85
85
|
}
|
|
86
|
-
export function projectJson(project, tags = [], commentsSummary) {
|
|
86
|
+
export function projectJson(project, tags = [], commentsSummary, unreadMentionCount = 0) {
|
|
87
87
|
return {
|
|
88
88
|
id: project.id,
|
|
89
89
|
ownerId: project.owner_id,
|
|
@@ -101,6 +101,7 @@ export function projectJson(project, tags = [], commentsSummary) {
|
|
|
101
101
|
tags,
|
|
102
102
|
unresolvedCommentCount: commentsSummary?.unresolvedCount ?? 0,
|
|
103
103
|
commentCount: commentsSummary?.totalCount ?? 0,
|
|
104
|
+
unreadMentionCount,
|
|
104
105
|
archived: Boolean(project.archived),
|
|
105
106
|
createdAt: project.created_at,
|
|
106
107
|
updatedAt: project.updated_at
|
|
@@ -11,6 +11,7 @@ import { accessibleProject, canEdit } from "../projects.js";
|
|
|
11
11
|
import { writeProjectArchive } from "../archive.js";
|
|
12
12
|
import { extractProjectZip, ZipValidationError } from "../zip.js";
|
|
13
13
|
import { HarperUnavailableError } from "../harper.js";
|
|
14
|
+
import { unreadMentionCountsForProjects } from "../commentMentions.js";
|
|
14
15
|
import { commentsSummaryForProject, commentsSummaryForProjects, dictionaryWord, escapeLikePattern, now, projectJson, requireProjectOwnerPermission, tagColors, tagsForProject, tagsForProjects, text } from "./projectShared.js";
|
|
15
16
|
/** Register project catalog, metadata, archive, dictionary, tag, export, and deletion routes. */
|
|
16
17
|
export function registerProjectCatalogRoutes(app, context) {
|
|
@@ -172,8 +173,9 @@ export function registerProjectCatalogRoutes(app, context) {
|
|
|
172
173
|
const projectIds = projects.map((project) => project.id);
|
|
173
174
|
const projectTags = tagsForProjects(db, projectIds, user.id);
|
|
174
175
|
const commentsSummaries = commentsSummaryForProjects(db, projectIds);
|
|
176
|
+
const unreadMentionCounts = unreadMentionCountsForProjects(db, projectIds, user.id);
|
|
175
177
|
return {
|
|
176
|
-
projects: projects.map((project) => projectJson({ ...project, archived: archivedOnly }, projectTags.get(project.id) ?? [], commentsSummaries.get(project.id))),
|
|
178
|
+
projects: projects.map((project) => projectJson({ ...project, archived: archivedOnly }, projectTags.get(project.id) ?? [], commentsSummaries.get(project.id), unreadMentionCounts.get(project.id) ?? 0)),
|
|
177
179
|
pagination: { page: currentPage, pageSize, total, totalPages }
|
|
178
180
|
};
|
|
179
181
|
});
|
package/package.json
CHANGED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/SystemMetricsDialog-C9P4TSQl.js","assets/react-BVUjbTTn.js","assets/index-CzVDvC5h.js","assets/index-RjUuWk8F.css","assets/refresh-cw-FZs9MtoA.js","assets/hard-drive-CF3WDfkG.js","assets/x-BDSEosRE.js","assets/sigma-CSRwPPkk.js","assets/tags-CjkWzXqX.js","assets/chevron-left-DNM7mhNi.js","assets/CitationLibraryDialog-BmWFXTW2.js","assets/citationLibrary-ZeQPCv5O.js","assets/plus-BfEC7mzf.js","assets/check-bnimQPun.js","assets/search-DL2UGvdj.js","assets/AdminUsers-CqOmV9rq.js","assets/user-plus-YJ3ftuL5.js","assets/key-round-BaIj7Jch.js","assets/TagManagementDialog-LYbib36_.js","assets/ProjectIconPickerDialog-GAd8HGOx.js"])))=>i.map(i=>d[i]);
|
|
2
|
-
import{c as r,S as ca,L as la,a as Nt,M as se,b as Re,d as _e,C as da,e as ha,f as C,g as D,_ as me,i as Ze}from"./index-CzVDvC5h.js";import{j as e,r as o,u as pa}from"./react-BVUjbTTn.js";import{H as ma}from"./hard-drive-CF3WDfkG.js";import{G as ua,F as ya,L as ka,a as Ke,b as ga,S as ja,B as At,c as xa,d as fa,P as va,D as Ma,T as ba,M as Lt,A as zt,U as wa,e as St,f as Ca,C as Tt,g as Na,X as za,h as Sa}from"./x-BDSEosRE.js";import{S as Ta}from"./sigma-CSRwPPkk.js";import{T as We}from"./tags-CjkWzXqX.js";import{C as Pa}from"./chevron-left-DNM7mhNi.js";const Aa=r("Activity",[["path",{d:"M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2",key:"169zse"}]]);const La=r("ArchiveRestore",[["rect",{width:"20",height:"5",x:"2",y:"3",rx:"1",key:"1wp1u1"}],["path",{d:"M4 8v11a2 2 0 0 0 2 2h2",key:"tvwodi"}],["path",{d:"M20 8v11a2 2 0 0 1-2 2h-2",key:"1gkqxj"}],["path",{d:"m9 15 3-3 3 3",key:"1pd0qc"}],["path",{d:"M12 12v9",key:"192myk"}]]);const Ge=r("Archive",[["rect",{width:"20",height:"5",x:"2",y:"3",rx:"1",key:"1wp1u1"}],["path",{d:"M4 8v11a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8",key:"1s80jp"}],["path",{d:"M10 12h4",key:"a56b0p"}]]);const Da=r("ArrowDownUp",[["path",{d:"m3 16 4 4 4-4",key:"1co6wj"}],["path",{d:"M7 20V4",key:"1yoxec"}],["path",{d:"m21 8-4-4-4 4",key:"1c9v7m"}],["path",{d:"M17 4v16",key:"7dpous"}]]);const Dt=r("ArrowRightLeft",[["path",{d:"m16 3 4 4-4 4",key:"1x1c3m"}],["path",{d:"M20 7H4",key:"zbl0bi"}],["path",{d:"m8 21-4-4 4-4",key:"h9nckh"}],["path",{d:"M4 17h16",key:"g4d7ey"}]]);const Ea=r("Atom",[["circle",{cx:"12",cy:"12",r:"1",key:"41hilf"}],["path",{d:"M20.2 20.2c2.04-2.03.02-7.36-4.5-11.9-4.54-4.52-9.87-6.54-11.9-4.5-2.04 2.03-.02 7.36 4.5 11.9 4.54 4.52 9.87 6.54 11.9 4.5Z",key:"1l2ple"}],["path",{d:"M15.7 15.7c4.52-4.54 6.54-9.87 4.5-11.9-2.03-2.04-7.36-.02-11.9 4.5-4.52 4.54-6.54 9.87-4.5 11.9 2.03 2.04 7.36.02 11.9-4.5Z",key:"1wam0m"}]]);const Fa=r("Beaker",[["path",{d:"M4.5 3h15",key:"c7n0jr"}],["path",{d:"M6 3v16a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V3",key:"m1uhx7"}],["path",{d:"M6 14h12",key:"4cwo0f"}]]);const Ia=r("Bookmark",[["path",{d:"m19 21-7-4-7 4V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v16z",key:"1fy3hk"}]]);const qa=r("Bot",[["path",{d:"M12 8V4H8",key:"hb8ula"}],["rect",{width:"16",height:"12",x:"4",y:"8",rx:"2",key:"enze0r"}],["path",{d:"M2 14h2",key:"vft8re"}],["path",{d:"M20 14h2",key:"4cs60a"}],["path",{d:"M15 13v2",key:"1xurst"}],["path",{d:"M9 13v2",key:"rq6x2g"}]]);const $a=r("Braces",[["path",{d:"M8 3H7a2 2 0 0 0-2 2v5a2 2 0 0 1-2 2 2 2 0 0 1 2 2v5c0 1.1.9 2 2 2h1",key:"ezmyqa"}],["path",{d:"M16 21h1a2 2 0 0 0 2-2v-5c0-1.1.9-2 2-2a2 2 0 0 1-2-2V5a2 2 0 0 0-2-2h-1",key:"e1hn23"}]]);const Oa=r("BrainCircuit",[["path",{d:"M12 5a3 3 0 1 0-5.997.125 4 4 0 0 0-2.526 5.77 4 4 0 0 0 .556 6.588A4 4 0 1 0 12 18Z",key:"l5xja"}],["path",{d:"M9 13a4.5 4.5 0 0 0 3-4",key:"10igwf"}],["path",{d:"M6.003 5.125A3 3 0 0 0 6.401 6.5",key:"105sqy"}],["path",{d:"M3.477 10.896a4 4 0 0 1 .585-.396",key:"ql3yin"}],["path",{d:"M6 18a4 4 0 0 1-1.967-.516",key:"2e4loj"}],["path",{d:"M12 13h4",key:"1ku699"}],["path",{d:"M12 18h6a2 2 0 0 1 2 2v1",key:"105ag5"}],["path",{d:"M12 8h8",key:"1lhi5i"}],["path",{d:"M16 8V5a2 2 0 0 1 2-2",key:"u6izg6"}],["circle",{cx:"16",cy:"13",r:".5",key:"ry7gng"}],["circle",{cx:"18",cy:"3",r:".5",key:"1aiba7"}],["circle",{cx:"20",cy:"21",r:".5",key:"yhc1fs"}],["circle",{cx:"20",cy:"8",r:".5",key:"1e43v0"}]]);const Va=r("Brain",[["path",{d:"M12 5a3 3 0 1 0-5.997.125 4 4 0 0 0-2.526 5.77 4 4 0 0 0 .556 6.588A4 4 0 1 0 12 18Z",key:"l5xja"}],["path",{d:"M12 5a3 3 0 1 1 5.997.125 4 4 0 0 1 2.526 5.77 4 4 0 0 1-.556 6.588A4 4 0 1 1 12 18Z",key:"ep3f8r"}],["path",{d:"M15 13a4.5 4.5 0 0 1-3-4 4.5 4.5 0 0 1-3 4",key:"1p4c4q"}],["path",{d:"M17.599 6.5a3 3 0 0 0 .399-1.375",key:"tmeiqw"}],["path",{d:"M6.003 5.125A3 3 0 0 0 6.401 6.5",key:"105sqy"}],["path",{d:"M3.477 10.896a4 4 0 0 1 .585-.396",key:"ql3yin"}],["path",{d:"M19.938 10.5a4 4 0 0 1 .585.396",key:"1qfode"}],["path",{d:"M6 18a4 4 0 0 1-1.967-.516",key:"2e4loj"}],["path",{d:"M19.967 17.484A4 4 0 0 1 18 18",key:"159ez6"}]]);const Ba=r("Calculator",[["rect",{width:"16",height:"20",x:"4",y:"2",rx:"2",key:"1nb95v"}],["line",{x1:"8",x2:"16",y1:"6",y2:"6",key:"x4nwl0"}],["line",{x1:"16",x2:"16",y1:"14",y2:"18",key:"wjye3r"}],["path",{d:"M16 10h.01",key:"1m94wz"}],["path",{d:"M12 10h.01",key:"1nrarc"}],["path",{d:"M8 10h.01",key:"19clt8"}],["path",{d:"M12 14h.01",key:"1etili"}],["path",{d:"M8 14h.01",key:"6423bh"}],["path",{d:"M12 18h.01",key:"mhygvu"}],["path",{d:"M8 18h.01",key:"lrp35t"}]]);const Et=r("CalendarDays",[["path",{d:"M8 2v4",key:"1cmpym"}],["path",{d:"M16 2v4",key:"4m81vk"}],["rect",{width:"18",height:"18",x:"3",y:"4",rx:"2",key:"1hopcy"}],["path",{d:"M3 10h18",key:"8toen8"}],["path",{d:"M8 14h.01",key:"6423bh"}],["path",{d:"M12 14h.01",key:"1etili"}],["path",{d:"M16 14h.01",key:"1gbofw"}],["path",{d:"M8 18h.01",key:"lrp35t"}],["path",{d:"M12 18h.01",key:"mhygvu"}],["path",{d:"M16 18h.01",key:"kzsmim"}]]);const Ua=r("ChartColumn",[["path",{d:"M3 3v16a2 2 0 0 0 2 2h16",key:"c24i48"}],["path",{d:"M18 17V9",key:"2bz60n"}],["path",{d:"M13 17V5",key:"1frdt8"}],["path",{d:"M8 17v-3",key:"17ska0"}]]);const Ha=r("ChartLine",[["path",{d:"M3 3v16a2 2 0 0 0 2 2h16",key:"c24i48"}],["path",{d:"m19 9-5 5-4-4-3 3",key:"2osh9i"}]]);const Ra=r("ChartNoAxesCombined",[["path",{d:"M12 16v5",key:"zza2cw"}],["path",{d:"M16 14v7",key:"1g90b9"}],["path",{d:"M20 10v11",key:"1iqoj0"}],["path",{d:"m22 3-8.646 8.646a.5.5 0 0 1-.708 0L9.354 8.354a.5.5 0 0 0-.707 0L2 15",key:"1fw8x9"}],["path",{d:"M4 18v3",key:"1yp0dc"}],["path",{d:"M8 14v7",key:"n3cwzv"}]]);const _a=r("ChartPie",[["path",{d:"M21 12c.552 0 1.005-.449.95-.998a10 10 0 0 0-8.953-8.951c-.55-.055-.998.398-.998.95v8a1 1 0 0 0 1 1z",key:"pzmjnu"}],["path",{d:"M21.21 15.89A10 10 0 1 1 8 2.83",key:"k2fpak"}]]);const Za=r("ChartScatter",[["circle",{cx:"7.5",cy:"7.5",r:".5",fill:"currentColor",key:"kqv944"}],["circle",{cx:"18.5",cy:"5.5",r:".5",fill:"currentColor",key:"lysivs"}],["circle",{cx:"11.5",cy:"11.5",r:".5",fill:"currentColor",key:"byv1b8"}],["circle",{cx:"7.5",cy:"16.5",r:".5",fill:"currentColor",key:"nkw3mc"}],["circle",{cx:"17.5",cy:"14.5",r:".5",fill:"currentColor",key:"1gjh6j"}],["path",{d:"M3 3v16a2 2 0 0 0 2 2h16",key:"c24i48"}]]);const Ka=r("CircuitBoard",[["rect",{width:"18",height:"18",x:"3",y:"3",rx:"2",key:"afitv7"}],["path",{d:"M11 9h4a2 2 0 0 0 2-2V3",key:"1ve2rv"}],["circle",{cx:"9",cy:"9",r:"2",key:"af1f0g"}],["path",{d:"M7 21v-4a2 2 0 0 1 2-2h4",key:"1fwkro"}],["circle",{cx:"15",cy:"15",r:"2",key:"3i40o0"}]]);const Wa=r("Cloud",[["path",{d:"M17.5 19H9a7 7 0 1 1 6.71-9h1.79a4.5 4.5 0 1 1 0 9Z",key:"p7xjir"}]]);const Ga=r("CodeXml",[["path",{d:"m18 16 4-4-4-4",key:"1inbqp"}],["path",{d:"m6 8-4 4 4 4",key:"15zrgr"}],["path",{d:"m14.5 4-5 16",key:"e7oirm"}]]);const Ja=r("Copy",[["rect",{width:"14",height:"14",x:"8",y:"8",rx:"2",ry:"2",key:"17jyea"}],["path",{d:"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2",key:"zix9uf"}]]);const Qa=r("Cpu",[["rect",{width:"16",height:"16",x:"4",y:"4",rx:"2",key:"14l7u7"}],["rect",{width:"6",height:"6",x:"9",y:"9",rx:"1",key:"5aljv4"}],["path",{d:"M15 2v2",key:"13l42r"}],["path",{d:"M15 20v2",key:"15mkzm"}],["path",{d:"M2 15h2",key:"1gxd5l"}],["path",{d:"M2 9h2",key:"1bbxkp"}],["path",{d:"M20 15h2",key:"19e6y8"}],["path",{d:"M20 9h2",key:"19tzq7"}],["path",{d:"M9 2v2",key:"165o2o"}],["path",{d:"M9 20v2",key:"i2bqo8"}]]);const Xa=r("Database",[["ellipse",{cx:"12",cy:"5",rx:"9",ry:"3",key:"msslwz"}],["path",{d:"M3 5V19A9 3 0 0 0 21 19V5",key:"1wlel7"}],["path",{d:"M3 12A9 3 0 0 0 21 12",key:"mv7ke4"}]]);const Ya=r("Dna",[["path",{d:"m10 16 1.5 1.5",key:"11lckj"}],["path",{d:"m14 8-1.5-1.5",key:"1ohn8i"}],["path",{d:"M15 2c-1.798 1.998-2.518 3.995-2.807 5.993",key:"80uv8i"}],["path",{d:"m16.5 10.5 1 1",key:"696xn5"}],["path",{d:"m17 6-2.891-2.891",key:"xu6p2f"}],["path",{d:"M2 15c6.667-6 13.333 0 20-6",key:"1pyr53"}],["path",{d:"m20 9 .891.891",key:"3xwk7g"}],["path",{d:"M3.109 14.109 4 15",key:"q76aoh"}],["path",{d:"m6.5 12.5 1 1",key:"cs35ky"}],["path",{d:"m7 18 2.891 2.891",key:"1sisit"}],["path",{d:"M9 22c1.798-1.998 2.518-3.995 2.807-5.993",key:"q3hbxp"}]]);const es=r("Earth",[["path",{d:"M21.54 15H17a2 2 0 0 0-2 2v4.54",key:"1djwo0"}],["path",{d:"M7 3.34V5a3 3 0 0 0 3 3a2 2 0 0 1 2 2c0 1.1.9 2 2 2a2 2 0 0 0 2-2c0-1.1.9-2 2-2h3.17",key:"1tzkfa"}],["path",{d:"M11 21.95V18a2 2 0 0 0-2-2a2 2 0 0 1-2-2v-1a2 2 0 0 0-2-2H2.05",key:"14pb5j"}],["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}]]);const ts=r("Ellipsis",[["circle",{cx:"12",cy:"12",r:"1",key:"41hilf"}],["circle",{cx:"19",cy:"12",r:"1",key:"1wjl8i"}],["circle",{cx:"5",cy:"12",r:"1",key:"1pcz8c"}]]);const as=r("FileChartColumnIncreasing",[["path",{d:"M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z",key:"1rqfz7"}],["path",{d:"M14 2v4a2 2 0 0 0 2 2h4",key:"tnqrlb"}],["path",{d:"M8 18v-2",key:"qcmpov"}],["path",{d:"M12 18v-4",key:"q1q25u"}],["path",{d:"M16 18v-6",key:"15y0np"}]]);const ss=r("FileCode2",[["path",{d:"M4 22h14a2 2 0 0 0 2-2V7l-5-5H6a2 2 0 0 0-2 2v4",key:"1pf5j1"}],["path",{d:"M14 2v4a2 2 0 0 0 2 2h4",key:"tnqrlb"}],["path",{d:"m5 12-3 3 3 3",key:"oke12k"}],["path",{d:"m9 18 3-3-3-3",key:"112psh"}]]);const ns=r("FilePenLine",[["path",{d:"m18 5-2.414-2.414A2 2 0 0 0 14.172 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2",key:"142zxg"}],["path",{d:"M21.378 12.626a1 1 0 0 0-3.004-3.004l-4.01 4.012a2 2 0 0 0-.506.854l-.837 2.87a.5.5 0 0 0 .62.62l2.87-.837a2 2 0 0 0 .854-.506z",key:"2t3380"}],["path",{d:"M8 18h1",key:"13wk12"}]]);const rs=r("FileSpreadsheet",[["path",{d:"M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z",key:"1rqfz7"}],["path",{d:"M14 2v4a2 2 0 0 0 2 2h4",key:"tnqrlb"}],["path",{d:"M8 13h2",key:"yr2amv"}],["path",{d:"M14 13h2",key:"un5t4a"}],["path",{d:"M8 17h2",key:"2yhykz"}],["path",{d:"M14 17h2",key:"10kma7"}]]);const os=r("FileStack",[["path",{d:"M21 7h-3a2 2 0 0 1-2-2V2",key:"9rb54x"}],["path",{d:"M21 6v6.5c0 .8-.7 1.5-1.5 1.5h-7c-.8 0-1.5-.7-1.5-1.5v-9c0-.8.7-1.5 1.5-1.5H17Z",key:"1059l0"}],["path",{d:"M7 8v8.8c0 .3.2.6.4.8.2.2.5.4.8.4H15",key:"16874u"}],["path",{d:"M3 12v8.8c0 .3.2.6.4.8.2.2.5.4.8.4H11",key:"k2ox98"}]]);const is=r("FlaskConical",[["path",{d:"M14 2v6a2 2 0 0 0 .245.96l5.51 10.08A2 2 0 0 1 18 22H6a2 2 0 0 1-1.755-2.96l5.51-10.08A2 2 0 0 0 10 8V2",key:"18mbvz"}],["path",{d:"M6.453 15h11.094",key:"3shlmq"}],["path",{d:"M8.5 2h7",key:"csnxdl"}]]);const cs=r("FolderArchive",[["circle",{cx:"15",cy:"19",r:"2",key:"u2pros"}],["path",{d:"M20.9 19.8A2 2 0 0 0 22 18V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2h5.1",key:"1jj40k"}],["path",{d:"M15 11v-1",key:"cntcp"}],["path",{d:"M15 17v-2",key:"1279jj"}]]);const ls=r("FolderGit2",[["path",{d:"M9 20H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H20a2 2 0 0 1 2 2v5",key:"1w6njk"}],["circle",{cx:"13",cy:"12",r:"2",key:"1j92g6"}],["path",{d:"M18 19c-2.8 0-5-2.2-5-5v8",key:"pkpw2h"}],["circle",{cx:"20",cy:"19",r:"2",key:"1obnsp"}]]);const ds=r("FolderKanban",[["path",{d:"M4 20h16a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.93a2 2 0 0 1-1.66-.9l-.82-1.2A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13c0 1.1.9 2 2 2Z",key:"1fr9dc"}],["path",{d:"M8 10v4",key:"tgpxqk"}],["path",{d:"M12 10v2",key:"hh53o1"}],["path",{d:"M16 10v6",key:"1d6xys"}]]);const hs=r("GraduationCap",[["path",{d:"M21.42 10.922a1 1 0 0 0-.019-1.838L12.83 5.18a2 2 0 0 0-1.66 0L2.6 9.08a1 1 0 0 0 0 1.832l8.57 3.908a2 2 0 0 0 1.66 0z",key:"j76jl0"}],["path",{d:"M22 10v6",key:"1lu8f3"}],["path",{d:"M6 12.5V16a6 3 0 0 0 12 0v-3.5",key:"1r8lef"}]]);const ps=r("History",[["path",{d:"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8",key:"1357e3"}],["path",{d:"M3 3v5h5",key:"1xhq8a"}],["path",{d:"M12 7v5l4 2",key:"1fdv2h"}]]);const ms=r("Image",[["rect",{width:"18",height:"18",x:"3",y:"3",rx:"2",ry:"2",key:"1m3agn"}],["circle",{cx:"9",cy:"9",r:"2",key:"af1f0g"}],["path",{d:"m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21",key:"1xmnt7"}]]);const us=r("Languages",[["path",{d:"m5 8 6 6",key:"1wu5hv"}],["path",{d:"m4 14 6-6 2-3",key:"1k1g8d"}],["path",{d:"M2 5h12",key:"or177f"}],["path",{d:"M7 2h1",key:"1t2jsx"}],["path",{d:"m22 22-5-10-5 10",key:"don7ne"}],["path",{d:"M14 18h6",key:"1m8k6r"}]]);const ys=r("Library",[["path",{d:"m16 6 4 14",key:"ji33uf"}],["path",{d:"M12 6v14",key:"1n7gus"}],["path",{d:"M8 8v12",key:"1gg7y9"}],["path",{d:"M4 4v16",key:"6qkkli"}]]);const ks=r("Lightbulb",[["path",{d:"M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5",key:"1gvzjb"}],["path",{d:"M9 18h6",key:"x1upvd"}],["path",{d:"M10 22h4",key:"ceow96"}]]);const gs=r("Map",[["path",{d:"M14.106 5.553a2 2 0 0 0 1.788 0l3.659-1.83A1 1 0 0 1 21 4.619v12.764a1 1 0 0 1-.553.894l-4.553 2.277a2 2 0 0 1-1.788 0l-4.212-2.106a2 2 0 0 0-1.788 0l-3.659 1.83A1 1 0 0 1 3 19.381V6.618a1 1 0 0 1 .553-.894l4.553-2.277a2 2 0 0 1 1.788 0z",key:"169xi5"}],["path",{d:"M15 5.764v15",key:"1pn4in"}],["path",{d:"M9 3.236v15",key:"1uimfh"}]]);const js=r("Microscope",[["path",{d:"M6 18h8",key:"1borvv"}],["path",{d:"M3 22h18",key:"8prr45"}],["path",{d:"M14 22a7 7 0 1 0 0-14h-1",key:"1jwaiy"}],["path",{d:"M9 14h2",key:"197e7h"}],["path",{d:"M9 12a2 2 0 0 1-2-2V6h6v4a2 2 0 0 1-2 2Z",key:"1bmzmy"}],["path",{d:"M12 6V3a1 1 0 0 0-1-1H9a1 1 0 0 0-1 1v3",key:"1drr47"}]]);const xs=r("Network",[["rect",{x:"16",y:"16",width:"6",height:"6",rx:"1",key:"4q2zg0"}],["rect",{x:"2",y:"16",width:"6",height:"6",rx:"1",key:"8cvhb9"}],["rect",{x:"9",y:"2",width:"6",height:"6",rx:"1",key:"1egb70"}],["path",{d:"M5 16v-3a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v3",key:"1jsf9p"}],["path",{d:"M12 12V8",key:"2874zd"}]]);const fs=r("Newspaper",[["path",{d:"M4 22h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H8a2 2 0 0 0-2 2v16a2 2 0 0 1-2 2Zm0 0a2 2 0 0 1-2-2v-9c0-1.1.9-2 2-2h2",key:"7pis2x"}],["path",{d:"M18 14h-8",key:"sponae"}],["path",{d:"M15 18h-5",key:"95g1m2"}],["path",{d:"M10 6h8v4h-8V6Z",key:"smlsk5"}]]);const vs=r("NotebookPen",[["path",{d:"M13.4 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-7.4",key:"re6nr2"}],["path",{d:"M2 6h4",key:"aawbzj"}],["path",{d:"M2 10h4",key:"l0bgd4"}],["path",{d:"M2 14h4",key:"1gsvsf"}],["path",{d:"M2 18h4",key:"1bu2t1"}],["path",{d:"M21.378 5.626a1 1 0 1 0-3.004-3.004l-5.01 5.012a2 2 0 0 0-.506.854l-.837 2.87a.5.5 0 0 0 .62.62l2.87-.837a2 2 0 0 0 .854-.506z",key:"pqwjuv"}]]);const Ms=r("NotepadText",[["path",{d:"M8 2v4",key:"1cmpym"}],["path",{d:"M12 2v4",key:"3427ic"}],["path",{d:"M16 2v4",key:"4m81vk"}],["rect",{width:"16",height:"18",x:"4",y:"4",rx:"2",key:"1u9h20"}],["path",{d:"M8 10h6",key:"3oa6kw"}],["path",{d:"M8 14h8",key:"1fgep2"}],["path",{d:"M8 18h5",key:"17enja"}]]);const bs=r("PenTool",[["path",{d:"M15.707 21.293a1 1 0 0 1-1.414 0l-1.586-1.586a1 1 0 0 1 0-1.414l5.586-5.586a1 1 0 0 1 1.414 0l1.586 1.586a1 1 0 0 1 0 1.414z",key:"nt11vn"}],["path",{d:"m18 13-1.375-6.874a1 1 0 0 0-.746-.776L3.235 2.028a1 1 0 0 0-1.207 1.207L5.35 15.879a1 1 0 0 0 .776.746L13 18",key:"15qc1e"}],["path",{d:"m2.3 2.3 7.286 7.286",key:"1wuzzi"}],["circle",{cx:"11",cy:"11",r:"2",key:"xmgehs"}]]);const ws=r("Presentation",[["path",{d:"M2 3h20",key:"91anmk"}],["path",{d:"M21 3v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V3",key:"2k9sn8"}],["path",{d:"m7 21 5-5 5 5",key:"bip4we"}]]);const Cs=r("Quote",[["path",{d:"M16 3a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2 1 1 0 0 1 1 1v1a2 2 0 0 1-2 2 1 1 0 0 0-1 1v2a1 1 0 0 0 1 1 6 6 0 0 0 6-6V5a2 2 0 0 0-2-2z",key:"rib7q0"}],["path",{d:"M5 3a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2 1 1 0 0 1 1 1v1a2 2 0 0 1-2 2 1 1 0 0 0-1 1v2a1 1 0 0 0 1 1 6 6 0 0 0 6-6V5a2 2 0 0 0-2-2z",key:"1ymkrd"}]]);const Ns=r("Regex",[["path",{d:"M17 3v10",key:"15fgeh"}],["path",{d:"m12.67 5.5 8.66 5",key:"1gpheq"}],["path",{d:"m12.67 10.5 8.66-5",key:"1dkfa6"}],["path",{d:"M9 17a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v2a2 2 0 0 0 2 2h2a2 2 0 0 0 2-2v-2z",key:"swwfx4"}]]);const zs=r("Rocket",[["path",{d:"M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.71-.84.7-2.13-.09-2.91a2.18 2.18 0 0 0-2.91-.09z",key:"m3kijz"}],["path",{d:"m12 15-3-3a22 22 0 0 1 2-3.95A12.88 12.88 0 0 1 22 2c0 2.72-.78 7.5-6 11a22.35 22.35 0 0 1-4 2z",key:"1fmvmk"}],["path",{d:"M9 12H4s.55-3.03 2-4c1.62-1.08 5 0 5 0",key:"1f8sc4"}],["path",{d:"M12 15v5s3.03-.55 4-2c1.08-1.62 0-5 0-5",key:"qeys4"}]]);const Ss=r("Server",[["rect",{width:"20",height:"8",x:"2",y:"2",rx:"2",ry:"2",key:"ngkwjq"}],["rect",{width:"20",height:"8",x:"2",y:"14",rx:"2",ry:"2",key:"iecqi9"}],["line",{x1:"6",x2:"6.01",y1:"6",y2:"6",key:"16zg32"}],["line",{x1:"6",x2:"6.01",y1:"18",y2:"18",key:"nzw8ys"}]]);const Ts=r("ShieldCheck",[["path",{d:"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z",key:"oel41y"}],["path",{d:"m9 12 2 2 4-4",key:"dzmm74"}]]);const Ft=r("Sparkles",[["path",{d:"M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .963 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.581a.5.5 0 0 1 0 .964L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.963 0z",key:"4pj2yx"}],["path",{d:"M20 3v4",key:"1olli1"}],["path",{d:"M22 5h-4",key:"1gvqau"}],["path",{d:"M4 17v2",key:"vumght"}],["path",{d:"M5 18H3",key:"zchphs"}]]);const Ps=r("StickyNote",[["path",{d:"M16 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V8Z",key:"qazsjp"}],["path",{d:"M15 3v4a2 2 0 0 0 2 2h4",key:"40519r"}]]);const As=r("Target",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["circle",{cx:"12",cy:"12",r:"6",key:"1vlfrh"}],["circle",{cx:"12",cy:"12",r:"2",key:"1c9p78"}]]);const Ls=r("Telescope",[["path",{d:"m10.065 12.493-6.18 1.318a.934.934 0 0 1-1.108-.702l-.537-2.15a1.07 1.07 0 0 1 .691-1.265l13.504-4.44",key:"k4qptu"}],["path",{d:"m13.56 11.747 4.332-.924",key:"19l80z"}],["path",{d:"m16 21-3.105-6.21",key:"7oh9d"}],["path",{d:"M16.485 5.94a2 2 0 0 1 1.455-2.425l1.09-.272a1 1 0 0 1 1.212.727l1.515 6.06a1 1 0 0 1-.727 1.213l-1.09.272a2 2 0 0 1-2.425-1.455z",key:"m7xp4m"}],["path",{d:"m6.158 8.633 1.114 4.456",key:"74o979"}],["path",{d:"m8 21 3.105-6.21",key:"1fvxut"}],["circle",{cx:"12",cy:"13",r:"2",key:"1c1ljs"}]]);const Ds=r("Terminal",[["polyline",{points:"4 17 10 11 4 5",key:"akl6gq"}],["line",{x1:"12",x2:"20",y1:"19",y2:"19",key:"q2wloq"}]]);const Es=r("TestTubeDiagonal",[["path",{d:"M21 7 6.82 21.18a2.83 2.83 0 0 1-3.99-.01a2.83 2.83 0 0 1 0-4L17 3",key:"1ub6xw"}],["path",{d:"m16 2 6 6",key:"1gw87d"}],["path",{d:"M12 16H4",key:"1cjfip"}]]);const Fs=r("TestTubes",[["path",{d:"M9 2v17.5A2.5 2.5 0 0 1 6.5 22A2.5 2.5 0 0 1 4 19.5V2",key:"1hjrqt"}],["path",{d:"M20 2v17.5a2.5 2.5 0 0 1-2.5 2.5a2.5 2.5 0 0 1-2.5-2.5V2",key:"16lc8n"}],["path",{d:"M3 2h7",key:"7s29d5"}],["path",{d:"M14 2h7",key:"7sicin"}],["path",{d:"M9 16H4",key:"1bfye3"}],["path",{d:"M20 16h-5",key:"ddnjpe"}]]);const Is=r("University",[["circle",{cx:"12",cy:"10",r:"1",key:"1gnqs8"}],["path",{d:"M22 20V8h-4l-6-4-6 4H2v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2",key:"1qj5sn"}],["path",{d:"M6 17v.01",key:"roodi6"}],["path",{d:"M6 13v.01",key:"67c122"}],["path",{d:"M18 17v.01",key:"12ktxm"}],["path",{d:"M18 13v.01",key:"tn1rt1"}],["path",{d:"M14 22v-5a2 2 0 0 0-2-2a2 2 0 0 0-2 2v5",key:"11g7fi"}]]);const qs=r("UsersRound",[["path",{d:"M18 21a8 8 0 0 0-16 0",key:"3ypg7q"}],["circle",{cx:"10",cy:"8",r:"5",key:"o932ke"}],["path",{d:"M22 20c0-3.37-2-6.5-4-8a5 5 0 0 0-.45-8.3",key:"10s06x"}]]);const $s=r("Workflow",[["rect",{width:"8",height:"8",x:"3",y:"3",rx:"2",key:"by2w9f"}],["path",{d:"M7 11v4a2 2 0 0 0 2 2h4",key:"xkn7yn"}],["rect",{width:"8",height:"8",x:"13",y:"13",rx:"2",key:"1cgmvn"}]]),It=["file-text","book-open","notebook-pen","book-marked","scroll-text","library","graduation-cap","presentation","image","folder-kanban","microscope","flask-conical","test-tube-diagonal","atom","dna","telescope","earth","map","languages","university","code-2","file-code-2","database","server","network","circuit-board","brain","brain-circuit","bot","shield-check","workflow","sigma","calculator","chart-no-axes-combined","line-chart","bar-chart-3","pie-chart","chart-scatter","file-spreadsheet","file-chart-column-increasing","lightbulb","rocket","target","sparkles","file-pen-line","file-stack","folder","folder-open","folder-archive","archive","bookmark","newspaper","notepad-text","sticky-note","pen-tool","quote","list-tree","file-search","beaker","test-tubes","folder-git-2","git-branch","terminal","braces","regex","cpu","hard-drive","cloud","users-round","calendar-days"],Os=new Set(It);function Vs(s){return typeof s=="string"&&Os.has(s)}function Bs(s){if(typeof s!="string")return null;const h=s.trim().replace(/^lucide:/i,"");return!h||h.length>96?null:/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(h)?h:null}const Us={"file-text":fa,"book-open":xa,"notebook-pen":vs,"book-marked":At,"scroll-text":ja,library:ys,"graduation-cap":hs,presentation:ws,image:ms,"folder-kanban":ds,microscope:js,"flask-conical":is,"test-tube-diagonal":Es,atom:Ea,dna:Ya,telescope:Ls,earth:es,map:gs,languages:us,university:Is,"code-2":Ga,"file-code-2":ss,database:Xa,server:Ss,network:xs,"circuit-board":Ka,brain:Va,"brain-circuit":Oa,bot:qa,"shield-check":Ts,workflow:$s,sigma:Ta,calculator:Ba,"chart-no-axes-combined":Ra,"line-chart":Ha,"bar-chart-3":Ua,"pie-chart":_a,"chart-scatter":Za,"file-spreadsheet":rs,"file-chart-column-increasing":as,lightbulb:ks,rocket:zs,target:As,sparkles:Ft,"file-pen-line":ns,"file-stack":os,folder:ga,"folder-open":Ke,"folder-archive":cs,archive:Ge,bookmark:Ia,newspaper:fs,"notepad-text":Ms,"sticky-note":Ps,"pen-tool":bs,quote:Cs,"list-tree":ka,"file-search":ya,beaker:Fa,"test-tubes":Fs,"folder-git-2":ls,"git-branch":ua,terminal:Ds,braces:$a,regex:Ns,cpu:Qa,"hard-drive":ma,cloud:Wa,"users-round":qs,"calendar-days":Et},ln=It.map(s=>({name:s}));function Hs(s){const h=Array.from(s.trim())[0];return h?h.toLocaleUpperCase():"?"}function Rs({icon:s,fallback:h,size:x=18}){const f=Vs(s)?Us[s]:null;if(f)return e.jsx(f,{"aria-hidden":"true",size:x,strokeWidth:1.9});const v=Bs(s);if(v){const a=`url(${`/api/project-icons/${encodeURIComponent(v)}`})`,y={maskImage:a,WebkitMaskImage:a};return e.jsx("span",{"aria-hidden":"true",className:"project-icon-external-glyph",style:y})}return e.jsx("span",{"aria-hidden":"true",children:h})}function qt({icon:s,projectName:h,editable:x=!1,onEdit:f,editLabel:v,title:c,className:a=""}){const y=e.jsx(Rs,{icon:s,fallback:Hs(h)}),m=`project-icon-avatar${x?" editable":""}${a?` ${a}`:""}`;return x&&f?e.jsx("button",{type:"button",className:m,title:v,"aria-label":v,onClick:f,children:y}):e.jsx("span",{className:m,title:c,"aria-hidden":"true",children:y})}function $t({project:s,currentUser:h,showArchived:x,archiveBusy:f,menuOpen:v,t:c,variant:a,onToggleMenu:y,onCloseMenu:m,onAssignTags:g,onRename:L,onDuplicate:d,onArchive:N,onTransfer:V,onDelete:z}){const M=o.useRef(null),S=s.permission==="owner",E=h.role==="admin"||h.canCreateProjects,R=s.ownerId===h.id,F=s.permission==="owner";o.useEffect(()=>{if(!v)return;const l=A=>{A.target instanceof Node&&!M.current?.contains(A.target)&&m()},P=A=>{A.key==="Escape"&&m()};return document.addEventListener("pointerdown",l),document.addEventListener("keydown",P),()=>{document.removeEventListener("pointerdown",l),document.removeEventListener("keydown",P)}},[v,m]);const T=[{id:"tags",label:c("tags.assign"),icon:e.jsx(We,{"aria-hidden":!0,size:15}),section:"main",onSelect:g},...S?[{id:"rename",label:c("projects.rename"),icon:e.jsx(va,{"aria-hidden":!0,size:15}),section:"main",onSelect:L}]:[],...E?[{id:"duplicate",label:c("projects.duplicate"),icon:e.jsx(Ja,{"aria-hidden":!0,size:15}),section:"main",onSelect:d}]:[],{id:"download",label:c("projects.download"),icon:e.jsx(Ma,{"aria-hidden":!0,size:15}),section:"main",href:`/api/projects/${s.id}/download`},{id:"archive",label:c(x?"projects.unarchive":"projects.archive"),icon:x?e.jsx(La,{"aria-hidden":!0,size:15}):e.jsx(Ge,{"aria-hidden":!0,size:15}),section:"main",disabled:f,onSelect:N},...R?[{id:"transfer",label:c("projects.transfer"),icon:e.jsx(Dt,{"aria-hidden":!0,size:15}),section:"main",onSelect:V}]:[],...F?[{id:"delete",label:c("common.delete"),icon:e.jsx(ba,{"aria-hidden":!0,size:15}),section:"danger",onSelect:z}]:[]],I=T.filter(l=>l.section==="main"),X=T.filter(l=>l.section==="danger"),ne=l=>{l.disabled||(m(),l.onSelect?.())};return e.jsxs("div",{ref:M,className:`project-action-menu-root project-action-menu-${a}`,onClick:l=>l.stopPropagation(),children:[e.jsx("button",{type:"button",className:"project-action-menu-trigger","aria-label":c("projects.projectActions",{project:s.name}),"aria-expanded":v,"aria-controls":`project-actions-${s.id}`,onClick:l=>{l.stopPropagation(),y()},children:e.jsx(ts,{"aria-hidden":!0,size:19})}),v&&e.jsxs("div",{id:`project-actions-${s.id}`,className:"project-action-menu",role:"group","aria-label":c("projects.projectActions",{project:s.name}),children:[I.map(l=>l.href?e.jsxs("a",{href:l.href,download:!0,onClick:P=>{P.stopPropagation(),m()},children:[l.icon,l.label]},l.id):e.jsxs("button",{type:"button",disabled:l.disabled,onClick:P=>{P.stopPropagation(),ne(l)},children:[l.icon,l.label]},l.id)),X.length>0&&e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"project-action-menu-separator","aria-hidden":"true"}),X.map(l=>e.jsxs("button",{type:"button",className:"danger",onClick:P=>{P.stopPropagation(),ne(l)},children:[l.icon,l.label]},l.id))]})]})]})}function _s({project:s,currentUser:h,showArchived:x,archiveBusy:f,menuOpen:v,t:c,formatCreatedDate:a,formatUpdatedTime:y,formatExactTime:m,onOpenProject:g,onToggleMenu:L,onCloseMenu:d,onAssignTags:N,onRename:V,onDuplicate:z,onArchive:M,onTransfer:S,onDelete:E,onChooseIcon:R}){const F=s.ownerDisplayName??s.ownerUsername??c("projects.deletedUser"),T=s.lastModifiedDisplayName??s.lastModifiedUsername??c("projects.deletedUser");return e.jsxs("article",{className:`project-card project-list-row${s.ownerId===h.id?" owned-project":""}${v?" project-list-menu-open":""}`,children:[e.jsx(qt,{icon:s.icon,projectName:s.name,title:s.name,editable:s.permission==="owner",editLabel:c("projectIcons.change"),onEdit:R,className:"project-list-avatar"}),e.jsxs("button",{type:"button",className:"project-list-open",onClick:g,"aria-label":c("projects.openProject",{project:s.name}),children:[e.jsx("span",{className:"project-list-summary",children:e.jsxs("span",{className:"project-list-title-line",children:[e.jsx("strong",{className:"project-list-title",title:s.name,children:s.name}),!!(s.unresolvedCommentCount&&s.unresolvedCommentCount>0)&&e.jsxs("span",{className:"project-comments-badge unresolved",title:c("projects.unresolvedCommentsTooltip",{unresolved:s.unresolvedCommentCount,total:s.commentCount??s.unresolvedCommentCount}),children:[e.jsx(Lt,{"aria-hidden":!0,size:10}),e.jsx("span",{children:c("projects.unresolvedCount",{count:s.unresolvedCommentCount})})]}),s.tags?.length>0&&e.jsx("span",{className:"project-list-tags",children:s.tags.map(I=>e.jsx("span",{className:`tag tag-${I.color} project-list-tag`,title:I.name,children:I.name},I.id))})]})}),e.jsxs("span",{className:"project-list-owner",title:F,children:[e.jsxs("span",{className:"sr-only",children:[c("projects.owner"),": "]}),F]}),e.jsxs("span",{className:"project-list-created",title:m(s.createdAt),children:[e.jsxs("span",{className:"sr-only",children:[c("projects.created"),": "]}),e.jsx("time",{dateTime:s.createdAt,children:a(s.createdAt)})]}),e.jsxs("span",{className:"project-list-modified",title:c("projects.modifiedByUser",{time:m(s.updatedAt),user:T}),children:[e.jsxs("span",{className:"sr-only",children:[c("projects.modified"),": "]}),e.jsx("time",{dateTime:s.updatedAt,children:y(s.updatedAt)}),e.jsx("small",{children:c("projects.byUser",{user:T})})]})]}),e.jsx($t,{variant:"list",project:s,currentUser:h,showArchived:x,archiveBusy:f,menuOpen:v,t:c,onToggleMenu:L,onCloseMenu:d,onAssignTags:N,onRename:V,onDuplicate:z,onArchive:M,onTransfer:S,onDelete:E})]})}const Zs=o.lazy(()=>me(()=>import("./SystemMetricsDialog-C9P4TSQl.js"),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9])).then(s=>({default:s.SystemMetricsDialog}))),Ks=o.lazy(()=>me(()=>import("./CitationLibraryDialog-BmWFXTW2.js"),__vite__mapDeps([10,1,2,3,11,6,12,13,14,9,8])).then(s=>({default:s.CitationLibraryDialog}))),Ws=o.lazy(()=>me(()=>import("./AdminUsers-CqOmV9rq.js"),__vite__mapDeps([15,1,2,3,6,16,17,5,7,8,9])).then(s=>({default:s.AdminUsers}))),Gs=o.lazy(()=>me(()=>import("./TagManagementDialog-LYbib36_.js"),__vite__mapDeps([18,1,2,3,12,6,13])).then(s=>({default:s.TagManagementDialog}))),Js=o.lazy(()=>me(()=>import("./ProjectIconPickerDialog-GAd8HGOx.js"),__vite__mapDeps([19,1,2,3,14,5,6,7,8,9])).then(s=>({default:s.ProjectIconPickerDialog})));function Qs(s){return s instanceof Error&&s.name==="AbortError"}function Xs(s,h,x,f){const v=new Date(s).getTime();if(!Number.isFinite(v))return s;const c=v-x,a=Math.abs(c),y=60*1e3,m=60*y,g=24*m,L=3*g;if(a>L){const z=Math.floor(a/g),M=c<0?"Past":"Future";return f(`projects.relativeDays${M}`,{days:z,hours:0,minutes:0})}if(a>=g){const z=Math.floor(a/g),M=Math.floor(a%g/m),S=c<0?"Past":"Future",E=M>0?"DaysHours":"Days";return f(`projects.relative${E}${S}`,{days:z,hours:M,minutes:0})}if(a>=m){const z=Math.floor(a/m),M=Math.floor(a%m/y),S=c<0?"Past":"Future",E=M>0?"HoursMinutes":"Hours";return f(`projects.relative${E}${S}`,{days:0,hours:z,minutes:M})}const d="minute",N=y,V=Math.sign(c)*Math.max(1,Math.floor(a/N));return new Intl.RelativeTimeFormat(h,{numeric:"always"}).format(V,d)}function Ys(s){return s<1024?`${s} B`:s<1024*1024?`${(s/1024).toFixed(1)} KB`:`${(s/1024/1024).toFixed(1)} MB`}function en({site:s,user:h,initialData:x,onDataChange:f,onUser:v,onOpenProject:c}){const{t:a}=pa(),[y,m]=o.useState(()=>x?.projects??[]),[g,L]=o.useState(()=>x?.tags??[]),[d,N]=o.useState(()=>x?.pagination??{page:1,pageSize:20,total:x?.projects.length??0,totalPages:x?.projects.length?1:0}),[V,z]=o.useState(!!x),[M,S]=o.useState(!1),[E,R]=o.useState(!1),[F,T]=o.useState(!1),[I,X]=o.useState(""),[ne,l]=o.useState(""),[P,A]=o.useState(""),[Je,_]=o.useState(""),[Qe,Z]=o.useState(""),[Ot,re]=o.useState(""),[Vt,ue]=o.useState(!1),[ye,Xe]=o.useState(""),[K,Ye]=o.useState(!1),[Bt,ke]=o.useState(!1),[Fe,Ie]=o.useState(""),[q,et]=o.useState(null),[tt,B]=o.useState(""),ge=o.useRef(null),at=o.useRef(null),[st,nt]=o.useState(!1),[U,Ut]=o.useState(""),[b,rt]=o.useState(""),[je,qe]=o.useState(!1),[Ht,$e]=o.useState(!1),[W,G]=o.useState(null),[ot,xe]=o.useState(null),[Oe,oe]=o.useState(null),[fe,ve]=o.useState(""),[J,it]=o.useState(!1),[Me,ie]=o.useState(null),[be,Y]=o.useState(""),[we,ct]=o.useState(!1),[ce,Ce]=o.useState(null),[Ne,lt]=o.useState(!1),[ze,Se]=o.useState(null),[Ve,dt]=o.useState([]),[Te,le]=o.useState(""),[ee,Pe]=o.useState(!1),[ht,te]=o.useState(""),[de,Rt]=o.useState(()=>localStorage.getItem("texlite-project-view")==="list"?"list":"grid"),[$,_t]=o.useState(()=>localStorage.getItem("texlite-project-sort")==="created"?"created":"updated"),[u,Zt]=o.useState(!1),[pt,mt]=o.useState(""),[Ae,H]=o.useState(null),[w,O]=o.useState(1),[Kt,Wt]=o.useState(()=>Date.now()),[ut,Gt]=o.useState(""),Be=o.useRef(0),he=o.useRef(null),yt=(t,n,i,p,k)=>`${t?"archived":"active"}|${n}|${i}|${p}|${k}`,kt=yt(u,w,U,b,$),pe=(t,n,i,p,k)=>{const j=new URLSearchParams({page:String(n),pageSize:"20",sort:k});t&&j.set("archived","1"),i.trim()&&j.set("search",i.trim()),p&&j.set("tag",p);const Q=yt(t,n,i,p,k),De=++Be.current;he.current?.abort();const Ee=new AbortController;return he.current=Ee,Promise.all([C(`/api/projects?${j.toString()}`,{signal:Ee.signal}),C("/api/tags",{signal:Ee.signal})]).then(([ae,ia])=>{De===Be.current&&(m(ae.projects),L(ia.tags),N(ae.pagination),O(ae.pagination.page),z(!0),Gt(Q))}).catch(ae=>{!Qs(ae)&&De===Be.current&&X(D(ae))}).finally(()=>{he.current===Ee&&(he.current=null)})};o.useEffect(()=>(pe(u,w,U,b,$),()=>he.current?.abort()),[u,w,U,b,$]),o.useEffect(()=>{V&&!u&&ut===kt&&f(y,g,d)},[y,g,d,V,ut,kt,u]),o.useEffect(()=>{const t=window.setInterval(()=>Wt(Date.now()),6e4);return()=>window.clearInterval(t)},[]),o.useEffect(()=>{if(!je)return;const t=i=>{i.target instanceof Node&&!at.current?.contains(i.target)&&qe(!1)},n=i=>{i.key==="Escape"&&qe(!1)};return document.addEventListener("pointerdown",t),document.addEventListener("keydown",n),()=>{document.removeEventListener("pointerdown",t),document.removeEventListener("keydown",n)}},[je]);const gt=t=>{H(null),Rt(t),localStorage.setItem("texlite-project-view",t)},Jt=t=>{_t(t),O(1),localStorage.setItem("texlite-project-sort",t)},jt=t=>{Zt(t),O(1)},xt=t=>{rt(t),O(1)},ft=async()=>{if(!(!ye.trim()||K)){Ye(!0),l("");try{const{project:t}=await C("/api/projects",{method:"POST",body:JSON.stringify({name:ye})});ue(!1),Xe("");const n=u||w!==1?y:[t,...y].slice(0,d.pageSize),i=u?d:{...d,total:d.total+1,totalPages:Math.ceil((d.total+1)/d.pageSize)};m(n),N(i),u||f(n,g,i),c(t.id)}catch(t){l(D(t))}finally{Ye(!1)}}},Qt=async()=>{if(!q)return;const t=s.maxUploadSizeMB;if(q.size>t*1024*1024)return B(a("errors.fileTooLarge",{size:t}));nt(!0),B("");const n=new FormData;n.append("file",q);try{const{project:i}=await C(`/api/projects/import?name=${encodeURIComponent(Fe.trim())}`,{method:"POST",body:n}),p=u||w!==1?y:[i,...y].slice(0,d.pageSize),k=u?d:{...d,total:d.total+1,totalPages:Math.ceil((d.total+1)/d.pageSize)};m(p),N(k),u||f(p,g,k),ke(!1),et(null),Ie(""),c(i.id)}catch(i){B(D(i))}finally{nt(!1)}},Ue=t=>{if(t&&!t.name.toLocaleLowerCase().endsWith(".zip")){B(a("errors.zipOnly"));return}B(""),et(t),t&&!Fe&&Ie(t.name.replace(/\.zip$/i,""))},Xt=async()=>{await C("/api/auth/logout",{method:"POST"}),v(null)},Yt=async t=>{if(!W)return;const n=W.tags.some(i=>i.id===t.id);A("");try{const p=(await C(n?`/api/projects/${W.id}/tags/${t.id}`:`/api/projects/${W.id}/tags`,n?{method:"DELETE"}:{method:"POST",body:JSON.stringify({tagId:t.id})})).project;G(p),m(k=>k.map(j=>j.id===p.id?p:j))}catch(i){A(D(i))}},ea=t=>{L(n=>[...n,t].sort((i,p)=>i.name.localeCompare(p.name)))},ta=t=>{const n=i=>i.map(p=>p.id===t.id?t:p);L(i=>n(i).sort((p,k)=>p.name.localeCompare(k.name))),m(i=>i.map(p=>({...p,tags:n(p.tags)}))),G(i=>i?{...i,tags:n(i.tags)}:null)},aa=t=>{L(n=>n.filter(i=>i.id!==t)),m(n=>n.map(i=>({...i,tags:i.tags.filter(p=>p.id!==t)}))),G(n=>n?{...n,tags:n.tags.filter(i=>i.id!==t)}:null),rt(n=>n===t?"":n)},sa=async(t,n)=>{const i=await C(`/api/projects/${t}/icon`,{method:"PATCH",body:JSON.stringify({icon:n})});m(p=>{const k=p.map(j=>j.id===i.project.id?i.project:j);return $==="updated"?k.sort((j,Q)=>Q.updatedAt.localeCompare(j.updatedAt)||j.name.localeCompare(Q.name)):k})},vt=async()=>{if(!(!Oe||!fe.trim()||J)){it(!0),_("");try{const t=await C(`/api/projects/${Oe.id}`,{method:"PATCH",body:JSON.stringify({name:fe})});m(n=>n.map(i=>i.id===t.project.id?t.project:i)),oe(null),ve("")}catch(t){_(D(t))}finally{it(!1)}}},Mt=async()=>{if(!(!Me||!be.trim())){ct(!0),Z("");try{await C(`/api/projects/${Me.id}/duplicate`,{method:"POST",body:JSON.stringify({name:be})}),ie(null),Y(""),pe(u,w,U,b,$)}catch(t){Z(D(t))}finally{ct(!1)}}},na=async()=>{if(!(!ce||Ne)){lt(!0),re("");try{await C(`/api/projects/${ce.id}`,{method:"DELETE"}),m(k=>k.filter(j=>j.id!==ce.id));const t=Math.max(0,d.total-1),n=Math.ceil(t/d.pageSize),i=n===0?1:Math.min(w,n),p={...d,page:i,total:t,totalPages:n};N(p),Ce(null),i!==w?O(i):pe(u,w,U,b,$)}catch(t){re(D(t))}finally{lt(!1)}}},bt=async t=>{Se(t),le(""),dt([]),te(""),Pe(!0);try{const n=await C("/api/users");dt(n.users.filter(i=>i.id!==t.ownerId))}catch(n){te(D(n))}finally{Pe(!1)}},ra=async()=>{if(!(!ze||!Te)){Pe(!0),te("");try{await C(`/api/projects/${ze.id}/owner`,{method:"PUT",body:JSON.stringify({userId:Te})}),Se(null),le(""),pe(u,w,U,b,$)}catch(t){te(D(t))}finally{Pe(!1)}}},wt=async t=>{const n=!u;mt(t.id),X("");try{await C(`/api/projects/${t.id}/archive`,{method:n?"PUT":"DELETE"});const i=y.filter(De=>De.id!==t.id);m(i);const p=Math.max(0,d.total-1),k=Math.ceil(p/d.pageSize),j=k===0?1:Math.min(w,k),Q={...d,page:j,total:p,totalPages:k};N(Q),u||f(i,g,Q),j!==w?O(j):pe(u,w,U,b,$)}catch(i){X(D(i))}finally{mt("")}},Le=y,He=t=>new Date(t).toLocaleString(Ze.resolvedLanguage),oa=t=>{const n=new Date(t);return Number.isFinite(n.getTime())?new Intl.DateTimeFormat(Ze.resolvedLanguage??"en",{year:"numeric",month:"2-digit",day:"2-digit"}).format(n):t},Ct=t=>Xs(t,Ze.resolvedLanguage??"en",Kt,(n,i)=>a(n,i));return e.jsxs("div",{className:"page",children:[e.jsxs("header",{className:"topbar",children:[e.jsxs("a",{className:"brand-link",href:"/","aria-label":s.siteName,children:[e.jsx("span",{className:"site-title",children:s.siteName}),e.jsx(ca,{siteName:s.siteName})]}),e.jsxs("div",{className:"top-actions",children:[h.role==="admin"&&e.jsxs(e.Fragment,{children:[e.jsxs("button",{className:"ghost",onClick:()=>R(!0),children:[e.jsx(Aa,{"aria-hidden":!0,size:14}),a("metrics.title")]}),e.jsxs("button",{className:`ghost${M?" top-return-action":""}`,onClick:()=>{S(t=>!t),T(!1)},children:[M?e.jsx(zt,{"aria-hidden":!0,size:14}):e.jsx(wa,{"aria-hidden":!0,size:14}),a(M?"users.back":"users.manage")]})]}),e.jsxs("button",{className:`ghost${F?" top-return-action":""}`,onClick:()=>{S(!1),T(t=>!t)},children:[F?e.jsx(zt,{"aria-hidden":!0,size:14}):e.jsx(At,{"aria-hidden":!0,size:14}),a(F?"users.back":"citationLibrary.title")]}),e.jsx(la,{compact:!0}),e.jsxs("span",{className:"top-user-identity",children:[e.jsx("strong",{children:h.displayName}),e.jsxs("small",{children:["@",h.username]})]}),e.jsx("button",{className:"ghost",onClick:Xt,children:a("auth.logout")})]})]}),M?e.jsx("main",{className:"dashboard",children:e.jsx(Nt,{onClose:()=>S(!1),children:e.jsx(Ws,{currentUser:h,minPasswordLength:s.minPasswordLength})})}):F?e.jsx("main",{className:"dashboard citation-library-page-shell",children:e.jsx(Nt,{onClose:()=>T(!1),children:e.jsx(Ks,{page:!0,open:!0,onOpenChange:T,onBack:()=>T(!1),currentUserId:h.id,maxBibtexBytes:s.maxCitationBibtexBytes})})}):e.jsxs("main",{className:"dashboard",children:[e.jsxs("div",{className:"section-title",children:[e.jsxs("div",{children:[e.jsxs("h1",{children:[e.jsx(Ke,{"aria-hidden":!0,size:25}),a("projects.title")]}),e.jsx("p",{className:"muted",children:h.canCreateProjects?a("projects.subtitle"):a("projects.restricted")})]}),e.jsxs("div",{className:"section-actions",children:[e.jsxs("button",{onClick:()=>$e(!0),children:[e.jsx(We,{"aria-hidden":!0,size:15}),a("tags.manage")]}),h.canCreateProjects&&e.jsxs(e.Fragment,{children:[e.jsxs("button",{onClick:()=>{B(""),ke(!0)},children:[e.jsx(St,{"aria-hidden":!0,size:15}),a("projects.upload")]}),e.jsxs("button",{className:"primary",onClick:()=>{l(""),ue(!0)},children:[e.jsx(Ca,{"aria-hidden":!0,size:15}),a("projects.new")]})]})]})]}),I&&e.jsx("p",{className:"error",children:I}),e.jsxs("div",{className:"project-catalog-layout",children:[e.jsxs("aside",{ref:at,className:`project-tag-sidebar${b?" has-active-filter":""}`,children:[e.jsxs("button",{type:"button",className:"project-tag-toggle",title:a("projects.filterTags"),"aria-label":a("projects.filterTags"),"aria-expanded":je,"aria-controls":"dashboard-tag-filters",onClick:()=>qe(t=>!t),children:[e.jsxs("span",{className:"project-tag-toggle-copy",children:[e.jsx(We,{"aria-hidden":!0,size:15}),e.jsx("span",{children:a("projects.filterTags")})]}),e.jsx(Tt,{className:"project-tag-toggle-chevron","aria-hidden":!0,size:15})]}),je&&e.jsxs("div",{id:"dashboard-tag-filters",className:"project-tag-filters",role:"group","aria-label":a("projects.filterTags"),children:[e.jsx("button",{type:"button",className:b?"":"active","aria-pressed":!b,onClick:()=>xt(""),children:a("projects.allTags")}),g.length>0?g.map(t=>e.jsxs("button",{type:"button",className:b===t.id?"active":"",title:t.name,"aria-pressed":b===t.id,onClick:()=>xt(b===t.id?"":t.id),children:[e.jsx(Pt,{color:t.color}),e.jsx("span",{children:t.name})]},t.id)):e.jsx("p",{className:"project-tag-empty",children:a("tags.none")})]})]}),e.jsxs("div",{className:"project-catalog-content",children:[e.jsxs("div",{className:"project-toolbar",children:[e.jsx("input",{type:"search",placeholder:a("projects.search"),value:U,onChange:t=>{Ut(t.target.value),O(1)}}),e.jsxs("div",{className:"project-scope",role:"tablist","aria-label":a("projects.scope"),children:[e.jsxs("button",{className:u?"":"active",onClick:()=>jt(!1),role:"tab","aria-selected":!u,children:[e.jsx(Ke,{size:14}),a("projects.active")]}),e.jsxs("button",{className:u?"active":"",onClick:()=>jt(!0),role:"tab","aria-selected":u,children:[e.jsx(Ge,{size:14}),a("projects.archived")]})]}),e.jsxs("label",{className:"project-sort",children:[e.jsx(Da,{size:14}),e.jsx("span",{children:a("projects.sortBy")}),e.jsxs("select",{value:$,onChange:t=>Jt(t.target.value),children:[e.jsx("option",{value:"updated",children:a("projects.sortModified")}),e.jsx("option",{value:"created",children:a("projects.sortCreated")})]})]}),e.jsxs("div",{className:"view-toggle",children:[e.jsx("button",{className:de==="grid"?"active":"",onClick:()=>gt("grid"),title:a("projects.grid"),children:"▦"}),e.jsx("button",{className:de==="list"?"active":"",onClick:()=>gt("list"),title:a("projects.list"),children:"☷"})]})]}),e.jsxs("div",{className:`project-grid ${de==="list"?"list-view":""}${Ae?" project-list-menu-active":""}`,children:[de==="list"&&Le.length>0&&e.jsxs("div",{className:"project-list-header","aria-hidden":"true",children:[e.jsx("span",{children:a("projects.title")}),e.jsx("span",{children:a("projects.owner")}),e.jsx("span",{children:a("projects.created")}),e.jsx("span",{children:a("projects.modified")}),e.jsx("span",{children:a("projects.actions")})]}),de==="list"?Le.map(t=>e.jsx(_s,{project:t,currentUser:h,showArchived:u,archiveBusy:pt===t.id,menuOpen:Ae===t.id,t:a,formatCreatedDate:oa,formatUpdatedTime:Ct,formatExactTime:He,onOpenProject:()=>{H(null),c(t.id)},onToggleMenu:()=>H(n=>n===t.id?null:t.id),onCloseMenu:()=>H(n=>n===t.id?null:n),onAssignTags:()=>{A(""),G(t)},onRename:()=>{_(""),oe(t),ve(t.name)},onDuplicate:()=>{Z(""),ie(t),Y(`${t.name} (1)`)},onArchive:()=>{wt(t)},onTransfer:()=>{bt(t)},onDelete:()=>{Ce(t),re("")},onChooseIcon:()=>xe(t)},t.id)):Le.map(t=>e.jsxs("article",{className:`project-card project-grid-card${t.ownerId===h.id?" owned-project":""}${Ae===t.id?" project-card-menu-open":""}`,role:"button",tabIndex:0,"aria-label":a("projects.openProject",{project:t.name}),onClick:()=>{H(null),c(t.id)},onKeyDown:n=>{n.target!==n.currentTarget||n.key!=="Enter"&&n.key!==" "||(n.preventDefault(),H(null),c(t.id))},children:[e.jsxs("div",{className:"project-card-meta-row",children:[e.jsx("div",{className:"project-card-badges",children:e.jsx("span",{className:"owner-badge",title:t.ownerDisplayName??t.ownerUsername??a("projects.deletedUser"),children:t.ownerDisplayName??t.ownerUsername??a("projects.deletedUser")})}),e.jsx($t,{variant:"grid",project:t,currentUser:h,showArchived:u,archiveBusy:pt===t.id,menuOpen:Ae===t.id,t:a,onToggleMenu:()=>H(n=>n===t.id?null:t.id),onCloseMenu:()=>H(n=>n===t.id?null:n),onAssignTags:()=>{A(""),G(t)},onRename:()=>{_(""),oe(t),ve(t.name)},onDuplicate:()=>{Z(""),ie(t),Y(`${t.name} (1)`)},onArchive:()=>{wt(t)},onTransfer:()=>{bt(t)},onDelete:()=>{Ce(t),re("")}})]}),e.jsxs("div",{className:"project-card-title-row",children:[e.jsx("span",{className:"project-card-icon-control",onClick:t.permission==="owner"?n=>n.stopPropagation():void 0,children:e.jsx(qt,{icon:t.icon,projectName:t.name,title:t.name,editable:t.permission==="owner",editLabel:a("projectIcons.change"),onEdit:()=>xe(t),className:"project-card-icon"})}),e.jsx("strong",{className:"project-card-title",title:t.name,children:t.name})]}),e.jsx("div",{className:"project-card-tags","aria-label":a("tags.assignTitle",{project:t.name}),title:t.tags?.map(n=>n.name).join(", ")||void 0,children:t.tags?.map(n=>e.jsx("span",{className:`tag tag-${n.color}`,title:n.name,children:n.name},n.id))}),e.jsxs("dl",{className:"project-meta",children:[e.jsxs("div",{children:[e.jsxs("dt",{className:"project-meta-created-label",children:[e.jsxs("span",{children:[e.jsx(Et,{"aria-hidden":!0,size:13}),a("projects.created")]}),!!(t.unresolvedCommentCount&&t.unresolvedCommentCount>0)&&e.jsxs("span",{className:"project-comments-badge unresolved",title:a("projects.unresolvedCommentsTooltip",{unresolved:t.unresolvedCommentCount,total:t.commentCount??t.unresolvedCommentCount}),children:[e.jsx(Lt,{"aria-hidden":!0,size:11}),e.jsx("span",{children:a("projects.unresolvedCount",{count:t.unresolvedCommentCount})})]})]}),e.jsx("dd",{children:e.jsx("time",{dateTime:t.createdAt,children:He(t.createdAt)})})]}),e.jsxs("div",{children:[e.jsxs("dt",{children:[e.jsx(ps,{"aria-hidden":!0,size:13}),a("projects.modified")]}),e.jsxs("dd",{title:a("projects.modifiedByUser",{time:He(t.updatedAt),user:t.lastModifiedDisplayName??t.lastModifiedUsername??a("projects.deletedUser")}),children:[e.jsx("time",{dateTime:t.updatedAt,children:Ct(t.updatedAt)}),e.jsxs("span",{className:"project-modified-by",children:[" · ",a("projects.byUser",{user:t.lastModifiedDisplayName??t.lastModifiedUsername??a("projects.deletedUser")})]})]})]})]})]},t.id)),Le.length===0&&(y.length===0?u?e.jsx("div",{className:"empty",children:a("projects.noArchived")}):e.jsxs("div",{className:"project-empty",children:[e.jsx("span",{className:"project-empty-icon",children:e.jsx(Ft,{size:28})}),e.jsx("h2",{children:a("projects.emptyTitle")}),e.jsx("p",{children:h.canCreateProjects?a("projects.emptyDescription"):a("projects.emptyRestricted")})]}):e.jsx("div",{className:"empty",children:a("projects.noMatches")}))]}),d.totalPages>1&&e.jsxs("nav",{className:"project-pagination","aria-label":a("projects.pagination"),children:[e.jsxs("button",{disabled:d.page<=1,onClick:()=>O(t=>Math.max(1,t-1)),title:a("projects.previousPage"),children:[e.jsx(Pa,{size:15}),a("projects.previousPage")]}),e.jsx("span",{children:a("projects.pageOf",{page:d.page,totalPages:d.totalPages,count:d.total})}),e.jsxs("button",{disabled:d.page>=d.totalPages,onClick:()=>O(t=>Math.min(d.totalPages,t+1)),title:a("projects.nextPage"),children:[e.jsx(Tt,{size:15}),a("projects.nextPage")]})]})]})]}),e.jsx(se,{open:Vt,title:a("projects.new"),description:a("projects.newDescription"),onOpenChange:t=>{!t&&K||(ue(t),t||l(""))},footer:e.jsxs(e.Fragment,{children:[e.jsx("button",{disabled:K,onClick:()=>ue(!1),children:a("common.cancel")}),e.jsxs("button",{className:"primary",disabled:K||!ye.trim(),"aria-busy":K,onClick:()=>{ft()},children:[K&&e.jsx(Re,{className:"spin",size:14}),a(K?"common.loading":"common.create")]})]}),children:e.jsxs(e.Fragment,{children:[ne&&e.jsx("p",{className:"error dialog-error",children:ne}),e.jsxs("label",{className:"form-field",children:[a("projects.name"),e.jsx("input",{autoFocus:!0,value:ye,onChange:t=>{Xe(t.target.value),l("")},onKeyDown:t=>{t.key==="Enter"&&ft()}})]})]})}),e.jsx(se,{open:Bt,title:a("projects.upload"),description:a("projects.uploadDescription",{size:s.maxUploadSizeMB}),onOpenChange:t=>{ke(t),t||B("")},footer:e.jsxs(e.Fragment,{children:[e.jsx("button",{onClick:()=>{ke(!1),B("")},children:a("common.cancel")}),e.jsx("button",{className:"primary",disabled:!q||st,onClick:()=>{Qt()},children:a(st?"projects.importing":"projects.import")})]}),children:e.jsxs("div",{className:"form-stack",children:[tt&&e.jsx("p",{className:"error import-error",children:tt}),e.jsxs("div",{className:`upload-picker${q?" has-file":""}`,onDragOver:t=>{t.preventDefault(),t.dataTransfer.dropEffect="copy"},onDrop:t=>{t.preventDefault(),Ue(t.dataTransfer.files[0]??null)},children:[e.jsx("input",{ref:ge,className:"sr-only",type:"file",accept:".zip,application/zip",onChange:t=>Ue(t.target.files?.[0]??null)}),e.jsx(Na,{size:34}),e.jsxs("div",{className:"upload-picker-copy",children:[e.jsx("strong",{children:q?.name??a("projects.chooseZip")}),e.jsx("span",{children:q?a("projects.selectedFileSize",{size:Ys(q.size)}):a("projects.dropZip")})]}),e.jsxs("button",{type:"button",onClick:()=>ge.current?.click(),children:[e.jsx(St,{size:15}),a("projects.browse")]}),q&&e.jsx("button",{className:"upload-clear",type:"button",title:a("projects.clearFile"),"aria-label":a("projects.clearFile"),onClick:()=>{Ue(null),ge.current&&(ge.current.value="")},children:e.jsx(za,{size:14})})]}),e.jsxs("label",{className:"form-field",children:[a("projects.name"),e.jsx("input",{value:Fe,onChange:t=>Ie(t.target.value)})]})]})}),Ht&&e.jsx(_e,{title:a("tags.manage"),onClose:()=>$e(!1),children:e.jsx(Gs,{open:!0,onOpenChange:$e,onTagCreated:ea,onTagUpdated:ta,onTagDeleted:aa})}),ot&&e.jsx(_e,{title:a("projectIcons.title"),onClose:()=>xe(null),children:e.jsx(Js,{project:ot,open:!0,onOpenChange:t=>{t||xe(null)},onSave:sa})}),e.jsx(se,{open:!!W,title:a("tags.assignTitle",{project:W?.name??""}),description:a("tags.assignDescription"),onOpenChange:t=>{t||(G(null),A(""))},footer:e.jsx("button",{onClick:()=>{G(null),A("")},children:a("common.close")}),children:e.jsxs("div",{className:"tag-assignment-list",children:[P&&e.jsx("p",{className:"error dialog-error",children:P}),g.map(t=>e.jsxs("label",{children:[e.jsx("input",{type:"checkbox",checked:!!W?.tags.some(n=>n.id===t.id),onChange:()=>{Yt(t)}}),e.jsx(Pt,{color:t.color}),e.jsx("span",{children:t.name})]},t.id)),g.length===0&&e.jsx("p",{className:"muted",children:a("tags.empty")})]})}),e.jsx(se,{open:!!Oe,title:a("projects.renameTitle"),onOpenChange:t=>{!t&&J||t||(oe(null),_(""))},footer:e.jsxs(e.Fragment,{children:[e.jsx("button",{disabled:J,onClick:()=>{oe(null),_("")},children:a("common.cancel")}),e.jsxs("button",{className:"primary",disabled:J||!fe.trim(),"aria-busy":J,onClick:()=>{vt()},children:[J&&e.jsx(Re,{className:"spin",size:14}),a(J?"common.loading":"projects.rename")]})]}),children:e.jsxs(e.Fragment,{children:[Je&&e.jsx("p",{className:"error dialog-error",children:Je}),e.jsxs("label",{className:"form-field",children:[a("projects.name"),e.jsx("input",{autoFocus:!0,value:fe,onChange:t=>{ve(t.target.value),_("")},onKeyDown:t=>{t.key==="Enter"&&vt()}})]})]})}),e.jsx(se,{open:!!Me,title:a("projects.duplicateTitle"),description:a("projects.duplicateDescription",{project:Me?.name??""}),onOpenChange:t=>{!t&&!we&&(ie(null),Y(""),Z(""))},footer:e.jsxs(e.Fragment,{children:[e.jsx("button",{disabled:we,onClick:()=>{ie(null),Y(""),Z("")},children:a("common.cancel")}),e.jsx("button",{className:"primary",disabled:we||!be.trim(),onClick:()=>{Mt()},children:a(we?"projects.duplicating":"projects.duplicate")})]}),children:e.jsxs(e.Fragment,{children:[Qe&&e.jsx("p",{className:"error dialog-error",children:Qe}),e.jsxs("label",{className:"form-field",children:[a("projects.name"),e.jsx("input",{autoFocus:!0,value:be,onChange:t=>{Y(t.target.value),Z("")},onKeyDown:t=>{t.key==="Enter"&&Mt()}})]})]})}),e.jsx(se,{open:!!ze,title:a("projects.transferOwnership"),description:a("projects.transferDescription",{project:ze?.name??""}),onOpenChange:t=>{!t&&!ee&&(Se(null),le(""),te(""))},footer:e.jsxs(e.Fragment,{children:[e.jsx("button",{disabled:ee,onClick:()=>{Se(null),le(""),te("")},children:a("common.cancel")}),e.jsxs("button",{className:"primary",disabled:ee||!Te,onClick:()=>{ra()},children:[ee?e.jsx(Re,{className:"spin",size:14}):e.jsx(Dt,{size:14}),a("projects.transfer")]})]}),children:e.jsxs("div",{className:"form-stack",children:[ht&&e.jsx("p",{className:"error dialog-error",children:ht}),e.jsxs("label",{className:"form-field",children:[a("projects.newOwner"),e.jsxs("select",{disabled:ee||Ve.length===0,value:Te,onChange:t=>le(t.target.value),children:[e.jsx("option",{value:"",children:ee?a("common.loading"):Ve.length>0?a("projects.chooseNewOwner"):a("projects.noTransferUsers")}),Ve.map(t=>e.jsxs("option",{value:t.id,children:[t.displayName??t.username," (@",t.username,")"]},t.id))]})]}),e.jsxs("p",{className:"warning",children:[e.jsx(Sa,{size:15}),a("projects.transferWarning")]})]})}),e.jsx(da,{open:!!ce,title:a("projects.deleteTitle"),description:a("projects.deleteDescription",{project:ce?.name??""}),confirmLabel:a(Ne?"common.loading":"common.delete"),danger:!0,busy:Ne,error:Ot,onCancel:()=>{Ne||(Ce(null),re(""))},onConfirm:()=>{na()}})]}),E&&e.jsx(_e,{title:a("metrics.title"),onClose:()=>R(!1),children:e.jsx(Zs,{open:!0,onOpenChange:R})}),e.jsx(ha,{})]})}function Pt({color:s}){return e.jsx("span",{className:`tag-dot tag-${s}`})}const dn=Object.freeze(Object.defineProperty({__proto__:null,Dashboard:en},Symbol.toStringTag,{value:"Module"}));export{Aa as A,dn as D,Rs as P,Ts as S,Hs as a,Vs as i,Bs as n,ln as p};
|