clay-server 5.1.0-beta.1 → 5.1.0-beta.3
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/LICENSES/README.md +4 -0
- package/LICENSES/dicebear-avatars.md +16 -0
- package/bin/cli.js +9 -91
- package/lib/builtin-mates.js +7 -7
- package/lib/daemon-project-access.js +7 -1
- package/lib/daemon-settings.js +11 -0
- package/lib/daemon.js +10 -37
- package/lib/dicebear-avatar.js +62 -0
- package/lib/knowledge-db-service.js +175 -0
- package/lib/knowledge-db-validation.js +0 -0
- package/lib/knowledge-document-index.js +49 -0
- package/lib/knowledge-draft-store.js +56 -0
- package/lib/knowledge-file-store.js +199 -0
- package/lib/knowledge-markdown.js +128 -0
- package/lib/linear-store.js +35 -8
- package/lib/mate-identity-file.js +39 -0
- package/lib/mate-knowledge-mcp-server.js +29 -6
- package/lib/mate-knowledge-service.js +23 -2
- package/lib/mate-knowledge-sync.js +37 -22
- package/lib/mate-ready-creation.js +2 -1
- package/lib/mate-workspace-color.js +4 -0
- package/lib/mates-identity.js +4 -4
- package/lib/mates-prompts.js +4 -3
- package/lib/mates.js +30 -11
- package/lib/os-users.js +5 -16
- package/lib/project-connection.js +36 -9
- package/lib/project-debate-proposal.js +6 -0
- package/lib/project-debate-workspace.js +43 -0
- package/lib/project-debate.js +4 -2
- package/lib/project-filesystem.js +21 -39
- package/lib/project-knowledge.js +315 -136
- package/lib/project-mate-creation-proposal.js +1 -0
- package/lib/project-mate-interaction.js +7 -6
- package/lib/project-server-settings.js +31 -0
- package/lib/project-sessions.js +92 -182
- package/lib/project-user-knowledge.js +60 -0
- package/lib/project.js +62 -21
- package/lib/public/app.js +79 -71
- package/lib/public/clay-studio-wordmark-bold.svg +20 -0
- package/lib/public/css/clay-workspace.css +105 -0
- package/lib/public/css/debates-workbench.css +47 -0
- package/lib/public/css/home-debate-live.css +26 -0
- package/lib/public/css/home-hub.css +3 -1
- package/lib/public/css/home-mate-model-picker.css +15 -131
- package/lib/public/css/home-mate-settings.css +168 -16
- package/lib/public/css/icon-strip.css +249 -32
- package/lib/public/css/input.css +3 -1
- package/lib/public/css/mate-conversation.css +176 -0
- package/lib/public/css/mate-knowledge-workbench.css +118 -0
- package/lib/public/css/mate-workspace-color.css +16 -0
- package/lib/public/css/mates.css +28 -28
- package/lib/public/css/menus.css +3 -0
- package/lib/public/css/messages.css +1 -114
- package/lib/public/css/mobile-nav.css +16 -16
- package/lib/public/css/overlays.css +15 -0
- package/lib/public/css/project-logs.css +7 -0
- package/lib/public/css/project-mate-creation.css +105 -0
- package/lib/public/css/project-settings-modal.css +56 -0
- package/lib/public/css/right-workbench.css +3 -3
- package/lib/public/css/server-settings-system.css +125 -0
- package/lib/public/css/session-folders.css +80 -21
- package/lib/public/css/session-github.css +25 -16
- package/lib/public/css/settings-ui.css +247 -22
- package/lib/public/css/shared-browser.css +7 -3
- package/lib/public/css/sidebar.css +183 -107
- package/lib/public/css/title-bar.css +156 -1
- package/lib/public/css/worker-delegation.css +47 -0
- package/lib/public/css/worker-proposal.css +72 -150
- package/lib/public/css/you.css +74 -0
- package/lib/public/index.html +206 -548
- package/lib/public/modules/account-island.js +232 -0
- package/lib/public/modules/admin-settings-email.js +197 -0
- package/lib/public/modules/admin-settings-invitations.js +183 -0
- package/lib/public/modules/admin-settings-projects.js +198 -0
- package/lib/public/modules/admin-settings-ui.js +100 -0
- package/lib/public/modules/admin-settings-users.js +331 -0
- package/lib/public/modules/admin.js +19 -949
- package/lib/public/modules/app-cursors.js +19 -43
- package/lib/public/modules/app-debate-ui.js +4 -3
- package/lib/public/modules/app-dm.js +0 -2
- package/lib/public/modules/app-header.js +106 -0
- package/lib/public/modules/app-message-router.js +12 -3
- package/lib/public/modules/app-messages.js +47 -61
- package/lib/public/modules/app-notifications.js +4 -7
- package/lib/public/modules/app-projects.js +5 -38
- package/lib/public/modules/app-rate-limit.js +70 -12
- package/lib/public/modules/app-rendering.js +12 -13
- package/lib/public/modules/avatar.js +30 -9
- package/lib/public/modules/chat-render-runtime.js +16 -4
- package/lib/public/modules/command-palette.js +2 -15
- package/lib/public/modules/context-sources.js +27 -18
- package/lib/public/modules/cursor-sharing-preference.js +3 -3
- package/lib/public/modules/debate-controls.js +299 -0
- package/lib/public/modules/debate.js +2 -0
- package/lib/public/modules/debates-workbench.js +339 -0
- package/lib/public/modules/default-ai.js +88 -65
- package/lib/public/modules/header-tui-font.js +10 -20
- package/lib/public/modules/home-debate-controls.js +18 -289
- package/lib/public/modules/home-mate-avatar-editor.js +228 -0
- package/lib/public/modules/home-mate-color-picker.js +66 -0
- package/lib/public/modules/home-mate-creation.js +1 -1
- package/lib/public/modules/home-mate-instructions.js +90 -0
- package/lib/public/modules/home-mate-model-picker.js +80 -271
- package/lib/public/modules/home-mate-profile-editor.js +72 -0
- package/lib/public/modules/home-mate-settings.js +118 -125
- package/lib/public/modules/home-shell.js +3 -0
- package/lib/public/modules/home-surface-boot.js +1 -9
- package/lib/public/modules/icon-strip-tooltip.js +95 -0
- package/lib/public/modules/knowledge-db-edit-state.js +35 -0
- package/lib/public/modules/knowledge-db-workbench.js +234 -0
- package/lib/public/modules/knowledge-history-state.js +55 -0
- package/lib/public/modules/knowledge-markdown-editor.js +57 -0
- package/lib/public/modules/knowledge-preview-links.js +70 -0
- package/lib/public/modules/knowledge-workbench-shell.js +21 -0
- package/lib/public/modules/linear-settings.js +3 -2
- package/lib/public/modules/markdown.js +5 -6
- package/lib/public/modules/mate-knowledge-workbench-state.js +174 -0
- package/lib/public/modules/mate-knowledge-workbench.js +500 -0
- package/lib/public/modules/mate-knowledge.js +11 -3
- package/lib/public/modules/mate-management.js +54 -10
- package/lib/public/modules/mate-sidebar.js +11 -1
- package/lib/public/modules/mate-workspace-color.js +33 -0
- package/lib/public/modules/mention.js +5 -13
- package/lib/public/modules/notification-settings.js +81 -0
- package/lib/public/modules/notifications.js +44 -28
- package/lib/public/modules/personal-settings-dialog.js +51 -0
- package/lib/public/modules/profile.js +66 -24
- package/lib/public/modules/project-chat-identity.js +79 -0
- package/lib/public/modules/project-debate-planning-workspace.js +250 -0
- package/lib/public/modules/project-debate-workspace.js +185 -0
- package/lib/public/modules/project-header-identity.js +127 -0
- package/lib/public/modules/project-logs-render.js +9 -4
- package/lib/public/modules/project-mate-creation-workspace.js +414 -0
- package/lib/public/modules/project-mate-navigation.js +238 -0
- package/lib/public/modules/project-session-navigation.js +29 -0
- package/lib/public/modules/project-settings-environment.js +106 -0
- package/lib/public/modules/project-settings.js +72 -628
- package/lib/public/modules/project-switcher.js +6 -8
- package/lib/public/modules/projects-hub-view.js +5 -6
- package/lib/public/modules/projects-hub.js +2 -6
- package/lib/public/modules/qrcode.js +27 -8
- package/lib/public/modules/search-clay-chat.js +8 -11
- package/lib/public/modules/server-settings-controls.js +316 -0
- package/lib/public/modules/server-settings-environment.js +194 -0
- package/lib/public/modules/server-settings-navigation.js +39 -0
- package/lib/public/modules/server-settings-state.js +54 -0
- package/lib/public/modules/server-settings.js +116 -788
- package/lib/public/modules/server-storage-settings.js +84 -0
- package/lib/public/modules/session-activity-tooltip.js +12 -0
- package/lib/public/modules/session-create-form.js +86 -14
- package/lib/public/modules/session-create.js +50 -7
- package/lib/public/modules/session-github.js +2 -1
- package/lib/public/modules/session-list-visibility.js +41 -0
- package/lib/public/modules/session-presence-ui.js +3 -0
- package/lib/public/modules/session-title-marquee.js +51 -0
- package/lib/public/modules/settings-env-values.js +34 -0
- package/lib/public/modules/settings-select.js +121 -0
- package/lib/public/modules/shared-browser.js +22 -12
- package/lib/public/modules/sidebar-mates.js +3 -50
- package/lib/public/modules/sidebar-mobile.js +63 -60
- package/lib/public/modules/sidebar-projects.js +84 -97
- package/lib/public/modules/sidebar-session-folders-ui.js +2 -2
- package/lib/public/modules/sidebar-session-hierarchy.js +149 -70
- package/lib/public/modules/sidebar-sessions.js +49 -50
- package/lib/public/modules/sidebar.js +11 -13
- package/lib/public/modules/stt-picker.js +14 -5
- package/lib/public/modules/terminal-prefs.js +22 -0
- package/lib/public/modules/theme.js +88 -52
- package/lib/public/modules/thinking-lifecycle.js +7 -6
- package/lib/public/modules/tool-palette-order.js +4 -3
- package/lib/public/modules/tool-palette.js +13 -3
- package/lib/public/modules/tools.js +22 -22
- package/lib/public/modules/user-settings-account.js +318 -0
- package/lib/public/modules/user-settings-appearance.js +55 -0
- package/lib/public/modules/user-settings-editors.js +24 -0
- package/lib/public/modules/user-settings-integrations.js +104 -0
- package/lib/public/modules/user-settings-layout.js +80 -0
- package/lib/public/modules/user-settings-preferences.js +48 -0
- package/lib/public/modules/user-settings-profile.js +53 -0
- package/lib/public/modules/user-settings-themes.js +38 -0
- package/lib/public/modules/user-settings-voice.js +75 -0
- package/lib/public/modules/user-settings.js +53 -480
- package/lib/public/modules/worker-proposal.js +42 -8
- package/lib/public/modules/worker-runtime-picker.js +115 -0
- package/lib/public/modules/you-activity.js +121 -0
- package/lib/public/modules/you.js +251 -0
- package/lib/public/style.css +20 -8
- package/lib/public/vendor/codemirror/LICENSE +21 -0
- package/lib/public/vendor/codemirror/codemirror.css +344 -0
- package/lib/public/vendor/codemirror/codemirror.js +9884 -0
- package/lib/public/vendor/codemirror/continuelist.js +101 -0
- package/lib/public/vendor/codemirror/markdown.js +886 -0
- package/lib/public/vendor/codemirror/show-hint.css +37 -0
- package/lib/public/vendor/codemirror/show-hint.js +523 -0
- package/lib/sdk-bridge.js +15 -3
- package/lib/sdk-message-processor.js +16 -4
- package/lib/sdk-quota-snapshot.js +37 -0
- package/lib/server-admin.js +11 -0
- package/lib/server-appearance-settings.js +71 -0
- package/lib/server-home-chat-events.js +1 -1
- package/lib/server-home-chat.js +25 -3
- package/lib/server-home-debate-planning.js +4 -1
- package/lib/server-home-debates.js +2 -0
- package/lib/server-home-mate-creation.js +4 -1
- package/lib/server-linear.js +14 -8
- package/lib/server-mate-instructions.js +44 -0
- package/lib/server-mates.js +14 -4
- package/lib/server-notification-settings.js +67 -0
- package/lib/server-palette.js +1 -1
- package/lib/server-settings.js +69 -1
- package/lib/server-storage.js +57 -0
- package/lib/server-user-knowledge.js +119 -0
- package/lib/server.js +31 -3
- package/lib/session-visibility.js +7 -2
- package/lib/sessions.js +35 -10
- package/lib/startup-projects.js +40 -0
- package/lib/storage-native-walk.js +85 -0
- package/lib/storage-usage.js +144 -0
- package/lib/user-knowledge-service.js +167 -0
- package/lib/users-permissions.js +7 -0
- package/lib/users-preferences.js +0 -74
- package/lib/users-project-mate-filter-preferences.js +39 -0
- package/lib/users.js +6 -4
- package/lib/workspace-query-access.js +4 -1
- package/lib/ws-schema.js +52 -4
- package/lib/yoke/acp-process-manager.js +2 -2
- package/lib/yoke/adapters/codex.js +12 -52
- package/lib/yoke/codex-app-server.js +2 -2
- package/lib/yoke/codex-model-catalog.js +52 -0
- package/lib/yoke/codex-rate-limits.js +26 -0
- package/package.json +12 -3
|
@@ -9,13 +9,16 @@ import { parseEmojis } from './markdown.js';
|
|
|
9
9
|
import { store } from './store.js';
|
|
10
10
|
import { getWs } from './ws-ref.js';
|
|
11
11
|
import { closeSidebar } from './sidebar.js';
|
|
12
|
-
import { showIconTooltip, hideIconTooltip, closeUserCtxMenu, getCurrentDmUserId } from './sidebar-mates.js';
|
|
12
|
+
import { showIconTooltip, hideIconTooltip, bindIconTooltip, closeUserCtxMenu, getCurrentDmUserId } from './sidebar-mates.js';
|
|
13
13
|
import { switchProject, openAddProjectModal, getCachedProjects } from './app-projects.js';
|
|
14
14
|
import { showHomeHub } from './app-home-hub.js';
|
|
15
15
|
import { getPendingTuiAttention } from './app-notifications.js';
|
|
16
16
|
import { isExternalWorktree, externalWorktreeTooltip, appendExternalWorktreeBadge } from './worktree-location.js';
|
|
17
17
|
import { groupProjects } from './project-grouping.js';
|
|
18
18
|
import { showProjectAccessPopover } from './project-access.js';
|
|
19
|
+
import { renderProjectMates, mateForWorkspace } from './project-mate-navigation.js';
|
|
20
|
+
import { openProjectCreateChoice } from './project-mate-creation-workspace.js';
|
|
21
|
+
import { openHomeMateSettings } from './home-mate-settings.js';
|
|
19
22
|
|
|
20
23
|
// --- Project state ---
|
|
21
24
|
var cachedProjectList = [];
|
|
@@ -23,6 +26,7 @@ var cachedCurrentSlug = null;
|
|
|
23
26
|
|
|
24
27
|
// --- Project context menu ---
|
|
25
28
|
var projectCtxMenu = null;
|
|
29
|
+
var projectCtxAnchor = null;
|
|
26
30
|
|
|
27
31
|
// --- Emoji picker ---
|
|
28
32
|
var emojiPickerEl = null;
|
|
@@ -250,14 +254,15 @@ export function initSidebarProjects() {
|
|
|
250
254
|
var addBtn = document.getElementById("icon-strip-add");
|
|
251
255
|
if (addBtn) {
|
|
252
256
|
addBtn.addEventListener("click", function () {
|
|
253
|
-
|
|
254
|
-
openAddProjectModal();
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
257
|
+
openProjectCreateChoice(addBtn, function () {
|
|
258
|
+
if (openAddProjectModal) openAddProjectModal();
|
|
259
|
+
else {
|
|
260
|
+
var modal = document.getElementById("add-project-modal");
|
|
261
|
+
if (modal) modal.classList.remove("hidden");
|
|
262
|
+
}
|
|
263
|
+
});
|
|
259
264
|
});
|
|
260
|
-
addBtn.addEventListener("mouseenter", function () { showIconTooltip(addBtn, "Add project"); });
|
|
265
|
+
addBtn.addEventListener("mouseenter", function () { showIconTooltip(addBtn, "Add Mate or project"); });
|
|
261
266
|
addBtn.addEventListener("mouseleave", hideIconTooltip);
|
|
262
267
|
}
|
|
263
268
|
|
|
@@ -273,7 +278,7 @@ export function initSidebarProjects() {
|
|
|
273
278
|
|
|
274
279
|
// Tooltip + click for home icon
|
|
275
280
|
var homeIcon = document.querySelector(".icon-strip-home");
|
|
276
|
-
if (homeIcon) {
|
|
281
|
+
if (homeIcon && !homeIcon.classList.contains("icon-strip-brand")) {
|
|
277
282
|
homeIcon.addEventListener("mouseenter", function () { showIconTooltip(homeIcon, "Clay Studio"); });
|
|
278
283
|
homeIcon.addEventListener("mouseleave", hideIconTooltip);
|
|
279
284
|
homeIcon.addEventListener("click", function (e) {
|
|
@@ -288,6 +293,11 @@ export function initSidebarProjects() {
|
|
|
288
293
|
if (dropdownBtn) {
|
|
289
294
|
dropdownBtn.addEventListener("click", function (e) {
|
|
290
295
|
e.stopPropagation();
|
|
296
|
+
var currentMate = mateForWorkspace(store.snap());
|
|
297
|
+
if (currentMate) {
|
|
298
|
+
openHomeMateSettings(currentMate.id, dropdownBtn, { section: "general" });
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
291
301
|
var current = null;
|
|
292
302
|
for (var i = 0; i < cachedProjectList.length; i++) {
|
|
293
303
|
if (cachedProjectList[i].slug === cachedCurrentSlug) {
|
|
@@ -339,82 +349,21 @@ export { getProjectAbbrev };
|
|
|
339
349
|
|
|
340
350
|
// --- Project context menu ---
|
|
341
351
|
|
|
342
|
-
export function closeProjectCtxMenu() {
|
|
352
|
+
export function closeProjectCtxMenu(options) {
|
|
343
353
|
if (projectCtxMenu) {
|
|
344
354
|
projectCtxMenu.remove();
|
|
345
355
|
projectCtxMenu = null;
|
|
346
356
|
}
|
|
357
|
+
if (options && options.restoreFocus && projectCtxAnchor && projectCtxAnchor.isConnected) projectCtxAnchor.focus();
|
|
358
|
+
projectCtxAnchor = null;
|
|
347
359
|
}
|
|
348
360
|
|
|
349
|
-
function
|
|
350
|
-
|
|
351
|
-
if (closeUserCtxMenu) closeUserCtxMenu();
|
|
352
|
-
closeEmojiPicker();
|
|
353
|
-
|
|
354
|
-
var menu = document.createElement("div");
|
|
355
|
-
menu.className = "project-ctx-menu";
|
|
356
|
-
|
|
357
|
-
var isWorktree = slug.indexOf("--") !== -1;
|
|
358
|
-
|
|
359
|
-
var iconItem = document.createElement("button");
|
|
360
|
-
iconItem.className = "project-ctx-item";
|
|
361
|
-
iconItem.innerHTML = iconHtml("smile") + " <span>Set Icon</span>";
|
|
362
|
-
iconItem.addEventListener("click", function (e) {
|
|
363
|
-
e.stopPropagation();
|
|
364
|
-
closeProjectCtxMenu();
|
|
365
|
-
showEmojiPicker(slug, anchorEl);
|
|
366
|
-
});
|
|
367
|
-
menu.appendChild(iconItem);
|
|
368
|
-
|
|
369
|
-
if (isWorktree) {
|
|
370
|
-
if (!options || options.canRemoveWorktree !== false) {
|
|
371
|
-
var removeWtItem = document.createElement("button");
|
|
372
|
-
removeWtItem.className = "project-ctx-item project-ctx-delete";
|
|
373
|
-
removeWtItem.innerHTML = iconHtml("trash-2") + " <span>Remove Worktree</span>";
|
|
374
|
-
removeWtItem.addEventListener("click", function (e) {
|
|
375
|
-
e.stopPropagation();
|
|
376
|
-
closeProjectCtxMenu();
|
|
377
|
-
if (getWs() && store.get('connected')) {
|
|
378
|
-
getWs().send(JSON.stringify({ type: "remove_project_check", slug: slug, name: name || slug }));
|
|
379
|
-
}
|
|
380
|
-
});
|
|
381
|
-
menu.appendChild(removeWtItem);
|
|
382
|
-
}
|
|
383
|
-
} else {
|
|
384
|
-
var wtItem = document.createElement("button");
|
|
385
|
-
wtItem.className = "project-ctx-item";
|
|
386
|
-
wtItem.innerHTML = iconHtml("git-branch") + " <span>Add Worktree</span>";
|
|
387
|
-
wtItem.addEventListener("click", function (e) {
|
|
388
|
-
e.stopPropagation();
|
|
389
|
-
closeProjectCtxMenu();
|
|
390
|
-
showWorktreeModal(slug, name || slug);
|
|
391
|
-
});
|
|
392
|
-
menu.appendChild(wtItem);
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
document.body.appendChild(menu);
|
|
396
|
-
projectCtxMenu = menu;
|
|
397
|
-
refreshIcons();
|
|
398
|
-
|
|
399
|
-
requestAnimationFrame(function () {
|
|
400
|
-
var rect = anchorEl.getBoundingClientRect();
|
|
401
|
-
menu.style.position = "fixed";
|
|
402
|
-
menu.style.left = (rect.right + 6) + "px";
|
|
403
|
-
menu.style.top = rect.top + "px";
|
|
404
|
-
var menuRect = menu.getBoundingClientRect();
|
|
405
|
-
if (menuRect.right > window.innerWidth - 8) {
|
|
406
|
-
menu.style.left = (rect.left - menuRect.width - 6) + "px";
|
|
407
|
-
}
|
|
408
|
-
if (menuRect.bottom > window.innerHeight - 8) {
|
|
409
|
-
menu.style.top = (window.innerHeight - menuRect.height - 8) + "px";
|
|
410
|
-
}
|
|
411
|
-
});
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
function showProjectCtxMenu(anchorEl, slug, name, icon, position) {
|
|
361
|
+
export function showProjectCtxMenu(anchorEl, slug, name, icon, position, options) {
|
|
362
|
+
options = options || {};
|
|
415
363
|
closeProjectCtxMenu();
|
|
416
364
|
if (closeUserCtxMenu) closeUserCtxMenu();
|
|
417
365
|
closeEmojiPicker();
|
|
366
|
+
projectCtxAnchor = anchorEl;
|
|
418
367
|
var projects = getCachedProjects();
|
|
419
368
|
var targetProject = null;
|
|
420
369
|
for (var projectIndex = 0; projectIndex < projects.length; projectIndex++) {
|
|
@@ -423,10 +372,12 @@ function showProjectCtxMenu(anchorEl, slug, name, icon, position) {
|
|
|
423
372
|
|
|
424
373
|
var menu = document.createElement("div");
|
|
425
374
|
menu.className = "project-ctx-menu";
|
|
375
|
+
menu.setAttribute("role", "menu");
|
|
426
376
|
|
|
427
377
|
// --- Set Icon ---
|
|
428
378
|
var iconItem = document.createElement("button");
|
|
429
379
|
iconItem.className = "project-ctx-item";
|
|
380
|
+
iconItem.setAttribute("role", "menuitem");
|
|
430
381
|
iconItem.innerHTML = iconHtml("smile") + " <span>Set Icon</span>";
|
|
431
382
|
iconItem.addEventListener("click", function (e) {
|
|
432
383
|
e.stopPropagation();
|
|
@@ -439,6 +390,7 @@ function showProjectCtxMenu(anchorEl, slug, name, icon, position) {
|
|
|
439
390
|
if (!store.get('permissions') || store.get('permissions').projectSettings !== false) {
|
|
440
391
|
var settingsItem = document.createElement("button");
|
|
441
392
|
settingsItem.className = "project-ctx-item";
|
|
393
|
+
settingsItem.setAttribute("role", "menuitem");
|
|
442
394
|
settingsItem.innerHTML = iconHtml("settings") + " <span>Project Settings</span>";
|
|
443
395
|
settingsItem.addEventListener("click", function (e) {
|
|
444
396
|
e.stopPropagation();
|
|
@@ -461,11 +413,12 @@ function showProjectCtxMenu(anchorEl, slug, name, icon, position) {
|
|
|
461
413
|
// --- Share ---
|
|
462
414
|
var shareItem = document.createElement("button");
|
|
463
415
|
shareItem.className = "project-ctx-item";
|
|
416
|
+
shareItem.setAttribute("role", "menuitem");
|
|
464
417
|
shareItem.innerHTML = iconHtml("share") + " <span>Share</span>";
|
|
465
418
|
shareItem.addEventListener("click", function (e) {
|
|
466
419
|
e.stopPropagation();
|
|
467
420
|
closeProjectCtxMenu();
|
|
468
|
-
triggerShare();
|
|
421
|
+
triggerShare(options.shareTargetSlug ? { projectSlug: slug, title: name || slug } : undefined);
|
|
469
422
|
});
|
|
470
423
|
menu.appendChild(shareItem);
|
|
471
424
|
|
|
@@ -476,6 +429,7 @@ function showProjectCtxMenu(anchorEl, slug, name, icon, position) {
|
|
|
476
429
|
if (isProjectOwner || isAdmin) {
|
|
477
430
|
var accessItem = document.createElement("button");
|
|
478
431
|
accessItem.className = "project-ctx-item";
|
|
432
|
+
accessItem.setAttribute("role", "menuitem");
|
|
479
433
|
accessItem.innerHTML = iconHtml("users") + " <span>Manage Access</span>";
|
|
480
434
|
accessItem.addEventListener("click", function (e) {
|
|
481
435
|
e.stopPropagation();
|
|
@@ -486,14 +440,20 @@ function showProjectCtxMenu(anchorEl, slug, name, icon, position) {
|
|
|
486
440
|
}
|
|
487
441
|
}
|
|
488
442
|
|
|
489
|
-
var
|
|
490
|
-
|
|
491
|
-
|
|
443
|
+
var isWorktree = slug.indexOf("--") !== -1;
|
|
444
|
+
var canRemoveTarget = !isWorktree || options.canRemoveWorktree !== false;
|
|
445
|
+
var canDeleteTarget = canRemoveTarget && (!store.get('permissions') || store.get('permissions').deleteProject !== false);
|
|
446
|
+
if (!isWorktree || canDeleteTarget) {
|
|
447
|
+
var sep2 = document.createElement("div");
|
|
448
|
+
sep2.className = "project-ctx-separator";
|
|
449
|
+
menu.appendChild(sep2);
|
|
450
|
+
}
|
|
492
451
|
|
|
493
452
|
// --- Add Worktree ---
|
|
494
453
|
if (slug.indexOf("--") === -1) {
|
|
495
454
|
var wtItem = document.createElement("button");
|
|
496
455
|
wtItem.className = "project-ctx-item";
|
|
456
|
+
wtItem.setAttribute("role", "menuitem");
|
|
497
457
|
wtItem.innerHTML = iconHtml("git-branch") + " <span>Add Worktree</span>";
|
|
498
458
|
wtItem.addEventListener("click", function (e) {
|
|
499
459
|
e.stopPropagation();
|
|
@@ -503,14 +463,17 @@ function showProjectCtxMenu(anchorEl, slug, name, icon, position) {
|
|
|
503
463
|
menu.appendChild(wtItem);
|
|
504
464
|
}
|
|
505
465
|
|
|
506
|
-
if (
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
466
|
+
if (canDeleteTarget) {
|
|
467
|
+
if (!isWorktree) {
|
|
468
|
+
var sep3 = document.createElement("div");
|
|
469
|
+
sep3.className = "project-ctx-separator";
|
|
470
|
+
menu.appendChild(sep3);
|
|
471
|
+
}
|
|
510
472
|
|
|
511
473
|
var deleteItem = document.createElement("button");
|
|
512
474
|
deleteItem.className = "project-ctx-item project-ctx-delete";
|
|
513
|
-
deleteItem.
|
|
475
|
+
deleteItem.setAttribute("role", "menuitem");
|
|
476
|
+
deleteItem.innerHTML = iconHtml("trash-2") + " <span>" + (isWorktree ? "Remove Worktree" : "Remove Project") + "</span>";
|
|
514
477
|
deleteItem.addEventListener("click", function (e) {
|
|
515
478
|
e.stopPropagation();
|
|
516
479
|
closeProjectCtxMenu();
|
|
@@ -525,6 +488,28 @@ function showProjectCtxMenu(anchorEl, slug, name, icon, position) {
|
|
|
525
488
|
projectCtxMenu = menu;
|
|
526
489
|
refreshIcons();
|
|
527
490
|
|
|
491
|
+
menu.addEventListener("keydown", function (event) {
|
|
492
|
+
var items = Array.from(menu.querySelectorAll('.project-ctx-item:not([disabled])'));
|
|
493
|
+
var index = items.indexOf(document.activeElement);
|
|
494
|
+
if (event.key === "Escape") {
|
|
495
|
+
event.preventDefault();
|
|
496
|
+
closeProjectCtxMenu({ restoreFocus: true });
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
499
|
+
if (event.key === "Tab") {
|
|
500
|
+
closeProjectCtxMenu();
|
|
501
|
+
return;
|
|
502
|
+
}
|
|
503
|
+
if (event.key === "Home" || event.key === "End" || event.key === "ArrowDown" || event.key === "ArrowUp") {
|
|
504
|
+
event.preventDefault();
|
|
505
|
+
if (event.key === "Home") index = 0;
|
|
506
|
+
else if (event.key === "End") index = items.length - 1;
|
|
507
|
+
else if (event.key === "ArrowDown") index = (index + 1 + items.length) % items.length;
|
|
508
|
+
else index = (index - 1 + items.length) % items.length;
|
|
509
|
+
if (items[index]) items[index].focus();
|
|
510
|
+
}
|
|
511
|
+
});
|
|
512
|
+
|
|
528
513
|
requestAnimationFrame(function () {
|
|
529
514
|
var rect = anchorEl.getBoundingClientRect();
|
|
530
515
|
menu.style.position = "fixed";
|
|
@@ -542,6 +527,8 @@ function showProjectCtxMenu(anchorEl, slug, name, icon, position) {
|
|
|
542
527
|
if (menuRect.bottom > window.innerHeight - 8) {
|
|
543
528
|
menu.style.top = (window.innerHeight - menuRect.height - 8) + "px";
|
|
544
529
|
}
|
|
530
|
+
var firstItem = menu.querySelector('.project-ctx-item:not([disabled])');
|
|
531
|
+
if (firstItem) firstItem.focus();
|
|
545
532
|
});
|
|
546
533
|
}
|
|
547
534
|
|
|
@@ -797,7 +784,7 @@ function setupDragHandlers(el, slug) {
|
|
|
797
784
|
var insertBefore = e.clientY < midY;
|
|
798
785
|
|
|
799
786
|
var container = document.getElementById("icon-strip-projects");
|
|
800
|
-
var items = container.querySelectorAll(".icon-strip-item");
|
|
787
|
+
var items = container.querySelectorAll(".icon-strip-item[data-slug]");
|
|
801
788
|
var slugs = [];
|
|
802
789
|
for (var i = 0; i < items.length; i++) {
|
|
803
790
|
if (items[i].dataset.slug !== draggedSlug) {
|
|
@@ -873,10 +860,7 @@ function createIconItem(p, currentSlug) {
|
|
|
873
860
|
el.classList.add("has-pending-perm");
|
|
874
861
|
}
|
|
875
862
|
|
|
876
|
-
(
|
|
877
|
-
elem.addEventListener("mouseenter", function () { showIconTooltip(elem, name); });
|
|
878
|
-
elem.addEventListener("mouseleave", hideIconTooltip);
|
|
879
|
-
})(p.name, el);
|
|
863
|
+
bindIconTooltip(el, { text: p.name, kind: "project" });
|
|
880
864
|
|
|
881
865
|
(function (slug) {
|
|
882
866
|
el.addEventListener("click", function (e) {
|
|
@@ -1037,6 +1021,7 @@ export function renderIconStrip(projects, currentSlug) {
|
|
|
1037
1021
|
|
|
1038
1022
|
var container = document.getElementById("icon-strip-projects");
|
|
1039
1023
|
if (!container) return;
|
|
1024
|
+
var focusedMateId = container.contains(document.activeElement) ? document.activeElement.dataset.mateId : null;
|
|
1040
1025
|
container.innerHTML = "";
|
|
1041
1026
|
|
|
1042
1027
|
var currentDmUserId = getCurrentDmUserId ? getCurrentDmUserId() : null;
|
|
@@ -1053,7 +1038,7 @@ export function renderIconStrip(projects, currentSlug) {
|
|
|
1053
1038
|
elem.addEventListener("contextmenu", function (e) {
|
|
1054
1039
|
e.preventDefault();
|
|
1055
1040
|
e.stopPropagation();
|
|
1056
|
-
|
|
1041
|
+
showProjectCtxMenu(elem, slug, name, null, null, { shareTargetSlug: true });
|
|
1057
1042
|
});
|
|
1058
1043
|
})(p.slug, p.name || p.slug, el);
|
|
1059
1044
|
setupDragHandlers(el, p.slug);
|
|
@@ -1079,7 +1064,7 @@ export function renderIconStrip(projects, currentSlug) {
|
|
|
1079
1064
|
elem.addEventListener("contextmenu", function (e) {
|
|
1080
1065
|
e.preventDefault();
|
|
1081
1066
|
e.stopPropagation();
|
|
1082
|
-
|
|
1067
|
+
showProjectCtxMenu(elem, slug, name, null, null, { shareTargetSlug: true });
|
|
1083
1068
|
});
|
|
1084
1069
|
})(p.slug, p.name || p.slug, header);
|
|
1085
1070
|
setupDragHandlers(header, p.slug);
|
|
@@ -1136,10 +1121,7 @@ export function renderIconStrip(projects, currentSlug) {
|
|
|
1136
1121
|
if (isExternal) appendExternalWorktreeBadge(wtEl, "worktree-external-badge");
|
|
1137
1122
|
|
|
1138
1123
|
var tooltipText = isExternal ? externalWorktreeTooltip(wt.name) : wt.name;
|
|
1139
|
-
(
|
|
1140
|
-
elem.addEventListener("mouseenter", function () { showIconTooltip(elem, text); });
|
|
1141
|
-
elem.addEventListener("mouseleave", hideIconTooltip);
|
|
1142
|
-
})(tooltipText, wtEl);
|
|
1124
|
+
bindIconTooltip(wtEl, { text: tooltipText, kind: "project" });
|
|
1143
1125
|
|
|
1144
1126
|
(function (slug) {
|
|
1145
1127
|
wtEl.addEventListener("click", function (e) {
|
|
@@ -1152,7 +1134,7 @@ export function renderIconStrip(projects, currentSlug) {
|
|
|
1152
1134
|
elem.addEventListener("contextmenu", function (e) {
|
|
1153
1135
|
e.preventDefault();
|
|
1154
1136
|
e.stopPropagation();
|
|
1155
|
-
|
|
1137
|
+
showProjectCtxMenu(elem, slug, name, null, null, { shareTargetSlug: true, canRemoveWorktree: !external });
|
|
1156
1138
|
});
|
|
1157
1139
|
})(wt.slug, wt.name, wtEl, isExternal);
|
|
1158
1140
|
|
|
@@ -1202,6 +1184,11 @@ export function renderIconStrip(projects, currentSlug) {
|
|
|
1202
1184
|
}
|
|
1203
1185
|
|
|
1204
1186
|
renderProjectList(projects, currentSlug);
|
|
1187
|
+
renderProjectMates();
|
|
1188
|
+
if (focusedMateId) {
|
|
1189
|
+
var mateButton = container.querySelector('[data-mate-id="' + CSS.escape(focusedMateId) + '"]');
|
|
1190
|
+
if (mateButton) mateButton.focus({ preventScroll: true });
|
|
1191
|
+
}
|
|
1205
1192
|
|
|
1206
1193
|
var iconNodes = [container];
|
|
1207
1194
|
var mobileProjectList = document.getElementById("project-list");
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
} from './session-folder-layout.js';
|
|
18
18
|
import { openFolderNameDialog, openFolderPicker, closeFolderModal } from './session-folder-dialogs.js';
|
|
19
19
|
import { openFolderDelete } from './session-folder-delete.js';
|
|
20
|
-
import {
|
|
20
|
+
import { beginSessionCreate } from './session-create.js';
|
|
21
21
|
import { renderNewSessionButton, renderCreateRow } from './session-create-form.js';
|
|
22
22
|
import { restoreFolderCollapse, toggleFolderCollapse } from './session-folder-collapse.js';
|
|
23
23
|
import { groupUnitsByDate, groupRootSessionIds } from './session-date-groups.js';
|
|
@@ -286,7 +286,7 @@ function folderMenuEntries(section, ctx) {
|
|
|
286
286
|
var at = folders.map(function (f) { return f.id; }).indexOf(section.id);
|
|
287
287
|
var folder = { id: section.id, label: section.label };
|
|
288
288
|
return [
|
|
289
|
-
{ label: "New session here", icon: "plus", run: function () {
|
|
289
|
+
{ label: "New session here", icon: "plus", run: function () { beginSessionCreate(section.id); } },
|
|
290
290
|
{ label: "Rename", icon: "pencil", run: function () { renameFolder(folder); } },
|
|
291
291
|
{ label: "Move up", icon: "arrow-up", disabled: at <= 0, run: function () { shiftFolder(section.id, -1); } },
|
|
292
292
|
{ label: "Move down", icon: "arrow-down", disabled: at === -1 || at >= folders.length - 1, run: function () { shiftFolder(section.id, 1); } },
|
|
@@ -2,13 +2,150 @@
|
|
|
2
2
|
|
|
3
3
|
import { iconHtml } from './icons.js';
|
|
4
4
|
import { store } from './store.js';
|
|
5
|
+
import { getWs } from './ws-ref.js';
|
|
5
6
|
import { buildSessionHierarchy } from './session-hierarchy.js';
|
|
7
|
+
import { splitGroupRoles } from './split-group-helpers.js';
|
|
6
8
|
|
|
7
9
|
var expansionBySurface = {
|
|
8
10
|
desktop: new Map(),
|
|
9
11
|
mobile: new Map(),
|
|
10
12
|
};
|
|
11
13
|
|
|
14
|
+
var workerHistoryMenu = null;
|
|
15
|
+
var workerHistoryOpener = null;
|
|
16
|
+
var workerHistoryKeyHandler = null;
|
|
17
|
+
var workerHistoryOutsideHandler = null;
|
|
18
|
+
|
|
19
|
+
export function closeWorkerHistoryMenu(restoreFocus) {
|
|
20
|
+
if (workerHistoryMenu) {
|
|
21
|
+
workerHistoryMenu.remove();
|
|
22
|
+
workerHistoryMenu = null;
|
|
23
|
+
}
|
|
24
|
+
if (typeof document !== "undefined" && workerHistoryKeyHandler) document.removeEventListener("keydown", workerHistoryKeyHandler, true);
|
|
25
|
+
if (typeof document !== "undefined" && workerHistoryOutsideHandler) document.removeEventListener("click", workerHistoryOutsideHandler, true);
|
|
26
|
+
workerHistoryKeyHandler = null;
|
|
27
|
+
workerHistoryOutsideHandler = null;
|
|
28
|
+
var opener = workerHistoryOpener;
|
|
29
|
+
workerHistoryOpener = null;
|
|
30
|
+
if (restoreFocus !== false && opener && typeof document !== "undefined" && document.contains(opener)) opener.focus();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function workerIsCurrent(worker) {
|
|
34
|
+
var groups = store.get('splitGroups') || [];
|
|
35
|
+
for (var i = 0; i < groups.length; i++) {
|
|
36
|
+
var roles = splitGroupRoles(groups[i]);
|
|
37
|
+
if (roles && roles.workerIds.indexOf(worker.id) !== -1) return true;
|
|
38
|
+
}
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function workerLabel(worker) {
|
|
43
|
+
var generation = worker && worker.workerGeneration ? "Generation " + worker.workerGeneration : "Worker";
|
|
44
|
+
return generation + (workerIsCurrent(worker) ? " · Current" : " · History");
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function openWorkerHistoryMenu(button, driver, workers, options) {
|
|
48
|
+
var opts = options || {};
|
|
49
|
+
if (opts.validate && !opts.validate(driver, workers)) return;
|
|
50
|
+
closeWorkerHistoryMenu();
|
|
51
|
+
var menu = document.createElement("div");
|
|
52
|
+
menu.className = "session-worker-history-menu";
|
|
53
|
+
menu.setAttribute("role", "menu");
|
|
54
|
+
menu.setAttribute("aria-label", "Worker history for " + (driver.title || "this session"));
|
|
55
|
+
var heading = document.createElement("div");
|
|
56
|
+
heading.className = "session-worker-history-heading";
|
|
57
|
+
heading.textContent = "Worker history";
|
|
58
|
+
menu.appendChild(heading);
|
|
59
|
+
for (var i = 0; i < workers.length; i++) {
|
|
60
|
+
var worker = workers[i];
|
|
61
|
+
var item = document.createElement("button");
|
|
62
|
+
item.type = "button";
|
|
63
|
+
item.className = "session-worker-history-item" + (workerIsCurrent(worker) ? " current" : "");
|
|
64
|
+
item.setAttribute("role", "menuitem");
|
|
65
|
+
item.setAttribute("aria-label", workerLabel(worker));
|
|
66
|
+
var label = document.createElement("span");
|
|
67
|
+
label.className = "session-worker-history-label";
|
|
68
|
+
label.textContent = workerLabel(worker);
|
|
69
|
+
var title = document.createElement("span");
|
|
70
|
+
title.className = "session-worker-history-title";
|
|
71
|
+
title.textContent = worker.title || "Untitled Worker";
|
|
72
|
+
item.appendChild(label);
|
|
73
|
+
item.appendChild(title);
|
|
74
|
+
item.addEventListener("click", (function (id, historyWorker) {
|
|
75
|
+
return function (event) {
|
|
76
|
+
event.preventDefault();
|
|
77
|
+
event.stopPropagation();
|
|
78
|
+
var ws = getWs();
|
|
79
|
+
var valid = ws && ws.readyState === 1 && store.get('connected') && (!opts.validate || opts.validate(driver, workers));
|
|
80
|
+
var navigated = false;
|
|
81
|
+
if (valid && opts.navigate) navigated = opts.navigate(historyWorker) !== false;
|
|
82
|
+
else if (valid) {
|
|
83
|
+
ws.send(JSON.stringify({ type: "switch_session", id: id }));
|
|
84
|
+
navigated = true;
|
|
85
|
+
}
|
|
86
|
+
if (navigated) closeWorkerHistoryMenu(false);
|
|
87
|
+
else closeWorkerHistoryMenu();
|
|
88
|
+
};
|
|
89
|
+
})(worker.id, worker));
|
|
90
|
+
menu.appendChild(item);
|
|
91
|
+
}
|
|
92
|
+
document.body.appendChild(menu);
|
|
93
|
+
var rect = button.getBoundingClientRect();
|
|
94
|
+
var menuRect = menu.getBoundingClientRect();
|
|
95
|
+
var left = Math.max(8, Math.min(rect.right - menuRect.width, window.innerWidth - menuRect.width - 8));
|
|
96
|
+
var top = rect.bottom + 4;
|
|
97
|
+
if (top + menuRect.height > window.innerHeight - 8) top = Math.max(8, rect.top - menuRect.height - 4);
|
|
98
|
+
menu.style.left = left + "px";
|
|
99
|
+
menu.style.top = top + "px";
|
|
100
|
+
workerHistoryMenu = menu;
|
|
101
|
+
workerHistoryOpener = button;
|
|
102
|
+
workerHistoryKeyHandler = function (event) {
|
|
103
|
+
var items = menu.querySelectorAll(".session-worker-history-item");
|
|
104
|
+
var currentIndex = -1;
|
|
105
|
+
for (var ii = 0; ii < items.length; ii++) if (items[ii] === document.activeElement) currentIndex = ii;
|
|
106
|
+
if (event.key === "Escape") {
|
|
107
|
+
event.preventDefault();
|
|
108
|
+
closeWorkerHistoryMenu();
|
|
109
|
+
} else if (event.key === "ArrowDown" || event.key === "ArrowUp" || event.key === "Home" || event.key === "End") {
|
|
110
|
+
event.preventDefault();
|
|
111
|
+
if (!items.length) return;
|
|
112
|
+
var nextIndex = event.key === "Home" ? 0 : event.key === "End" ? items.length - 1 : currentIndex + (event.key === "ArrowDown" ? 1 : -1);
|
|
113
|
+
if (nextIndex < 0) nextIndex = items.length - 1;
|
|
114
|
+
if (nextIndex >= items.length) nextIndex = 0;
|
|
115
|
+
items[nextIndex].focus();
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
workerHistoryOutsideHandler = function (event) {
|
|
119
|
+
if (!menu.contains(event.target) && event.target !== button) closeWorkerHistoryMenu();
|
|
120
|
+
};
|
|
121
|
+
document.addEventListener("keydown", workerHistoryKeyHandler, true);
|
|
122
|
+
document.addEventListener("click", workerHistoryOutsideHandler, true);
|
|
123
|
+
var firstItem = menu.querySelector(".session-worker-history-item");
|
|
124
|
+
if (firstItem) firstItem.focus();
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export function createWorkerHistoryControl(driver, workers, options) {
|
|
128
|
+
if (!workers || !workers.length) return null;
|
|
129
|
+
var opts = options || {};
|
|
130
|
+
var button = document.createElement("button");
|
|
131
|
+
button.type = "button";
|
|
132
|
+
button.className = "session-worker-history-btn" + (opts.className ? " " + opts.className : "");
|
|
133
|
+
button.setAttribute("aria-label", opts.label || "Show Worker history");
|
|
134
|
+
button.setAttribute("aria-haspopup", "menu");
|
|
135
|
+
button.innerHTML = iconHtml("history");
|
|
136
|
+
button.addEventListener("click", function (event) {
|
|
137
|
+
event.preventDefault();
|
|
138
|
+
event.stopPropagation();
|
|
139
|
+
if (workerHistoryMenu) closeWorkerHistoryMenu();
|
|
140
|
+
else openWorkerHistoryMenu(button, driver, workers, opts);
|
|
141
|
+
});
|
|
142
|
+
return button;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
store.subscribe(function (state, previous) {
|
|
146
|
+
if (state.activeSessionId !== previous.activeSessionId || state.currentSlug !== previous.currentSlug || state.activeProjectMateId !== previous.activeProjectMateId || state.splitPanes !== previous.splitPanes) closeWorkerHistoryMenu(false);
|
|
147
|
+
});
|
|
148
|
+
|
|
12
149
|
export function prepareSidebarHierarchy(sessions) {
|
|
13
150
|
var hierarchy = buildSessionHierarchy(sessions);
|
|
14
151
|
var byDriver = new Map();
|
|
@@ -32,15 +169,8 @@ export function currentWorkerIds() {
|
|
|
32
169
|
var result = new Set();
|
|
33
170
|
var groups = store.get('splitGroups') || [];
|
|
34
171
|
for (var i = 0; i < groups.length; i++) {
|
|
35
|
-
var
|
|
36
|
-
if (
|
|
37
|
-
if (Array.isArray(pair.workerIds)) {
|
|
38
|
-
for (var j = 0; j < pair.workerIds.length; j++) {
|
|
39
|
-
if (Number.isInteger(pair.workerIds[j])) result.add(pair.workerIds[j]);
|
|
40
|
-
}
|
|
41
|
-
} else if (Number.isInteger(pair.workerId)) {
|
|
42
|
-
result.add(pair.workerId);
|
|
43
|
-
}
|
|
172
|
+
var roles = splitGroupRoles(groups[i]);
|
|
173
|
+
if (roles) for (var j = 0; j < roles.workerIds.length; j++) result.add(roles.workerIds[j]);
|
|
44
174
|
}
|
|
45
175
|
return result;
|
|
46
176
|
}
|
|
@@ -90,46 +220,16 @@ function visibleWorker(worker, driver, matchIds) {
|
|
|
90
220
|
export function renderDesktopDriverHierarchy(root, renderSession, rerender, matchIds) {
|
|
91
221
|
var wrapper = document.createElement("div");
|
|
92
222
|
wrapper.className = "session-driver-hierarchy";
|
|
93
|
-
var key = "driver:" + root.driver.id;
|
|
94
|
-
var isExpanded = expanded("desktop", key);
|
|
95
|
-
var childrenId = "session-workers-" + root.driver.id;
|
|
96
223
|
var header = document.createElement("div");
|
|
97
224
|
header.className = "session-driver-header";
|
|
98
|
-
var
|
|
225
|
+
var selectedSessionId = store.get('activeSessionId');
|
|
226
|
+
var anyActive = !!root.driver.active || root.workers.some(function (worker) { return worker.id === selectedSessionId; });
|
|
227
|
+
var anyProcessing = root.workers.some(function (worker) { return worker.isProcessing; });
|
|
228
|
+
var workerUnread = root.workers.reduce(function (total, worker) { return total + (worker.unread || 0); }, 0);
|
|
229
|
+
var row = renderSession(root.driver, { promotedActive: anyActive, promotedProcessing: anyProcessing, promotedUnread: workerUnread });
|
|
99
230
|
row.classList.add("session-driver-item");
|
|
100
|
-
var control = document.createElement("button");
|
|
101
|
-
control.type = "button";
|
|
102
|
-
control.className = "session-driver-toggle";
|
|
103
|
-
control.setAttribute("aria-expanded", String(isExpanded));
|
|
104
|
-
control.setAttribute("aria-controls", childrenId);
|
|
105
|
-
control.setAttribute("aria-label", (isExpanded ? "Collapse" : "Expand") + " Workers for " + (root.driver.title || "New Session"));
|
|
106
|
-
control.innerHTML = iconHtml("chevron-right");
|
|
107
|
-
var children = document.createElement("div");
|
|
108
|
-
children.id = childrenId;
|
|
109
|
-
children.className = "session-worker-children";
|
|
110
|
-
children.setAttribute("role", "group");
|
|
111
|
-
children.setAttribute("aria-label", "Workers for " + (root.driver.title || "New Session"));
|
|
112
|
-
children.hidden = !isExpanded;
|
|
113
|
-
control.addEventListener("click", function (event) {
|
|
114
|
-
event.preventDefault();
|
|
115
|
-
event.stopPropagation();
|
|
116
|
-
var nextExpanded = !isExpanded;
|
|
117
|
-
expansionBySurface.desktop.set(expansionKey(key), nextExpanded);
|
|
118
|
-
control.setAttribute("aria-expanded", String(nextExpanded));
|
|
119
|
-
control.setAttribute("aria-label", (nextExpanded ? "Collapse" : "Expand") + " Workers for " + (root.driver.title || "New Session"));
|
|
120
|
-
children.hidden = !nextExpanded;
|
|
121
|
-
isExpanded = nextExpanded;
|
|
122
|
-
});
|
|
123
|
-
header.appendChild(control);
|
|
124
231
|
header.appendChild(row);
|
|
125
232
|
wrapper.appendChild(header);
|
|
126
|
-
|
|
127
|
-
var current = currentWorkerIds();
|
|
128
|
-
for (var i = 0; i < root.workers.length; i++) {
|
|
129
|
-
if (!visibleWorker(root.workers[i], root.driver, matchIds)) continue;
|
|
130
|
-
children.appendChild(renderSession(root.workers[i], { worker: true, current: current.has(root.workers[i].id) }));
|
|
131
|
-
}
|
|
132
|
-
wrapper.appendChild(children);
|
|
133
233
|
return wrapper;
|
|
134
234
|
}
|
|
135
235
|
|
|
@@ -164,35 +264,14 @@ export function renderDesktopOrphanHierarchy(workers, renderSession, rerender, m
|
|
|
164
264
|
export function renderMobileDriverHierarchy(root, renderSession, rerender, matchIds) {
|
|
165
265
|
var wrapper = document.createElement("div");
|
|
166
266
|
wrapper.className = "mobile-driver-hierarchy";
|
|
167
|
-
var key = "driver:" + root.driver.id;
|
|
168
|
-
var isExpanded = expanded("mobile", key);
|
|
169
|
-
var childrenId = "mobile-session-workers-" + root.driver.id;
|
|
170
267
|
var header = document.createElement("div");
|
|
171
268
|
header.className = "mobile-driver-header";
|
|
172
|
-
var
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
control.setAttribute("aria-label", (isExpanded ? "Collapse" : "Expand") + " Workers for " + (root.driver.title || "New Session"));
|
|
178
|
-
control.innerHTML = iconHtml("chevron-right");
|
|
179
|
-
control.addEventListener("click", function () { toggle("mobile", key, isExpanded, rerender); });
|
|
180
|
-
header.appendChild(control);
|
|
181
|
-
header.appendChild(renderSession(root.driver));
|
|
269
|
+
var selectedSessionId = store.get('activeSessionId');
|
|
270
|
+
var anyActive = !!root.driver.active || root.workers.some(function (worker) { return worker.id === selectedSessionId; });
|
|
271
|
+
var anyProcessing = root.workers.some(function (worker) { return worker.isProcessing; });
|
|
272
|
+
var workerUnread = root.workers.reduce(function (total, worker) { return total + (worker.unread || 0); }, 0);
|
|
273
|
+
header.appendChild(renderSession(root.driver, { promotedActive: anyActive, promotedProcessing: anyProcessing, promotedUnread: workerUnread }));
|
|
182
274
|
wrapper.appendChild(header);
|
|
183
|
-
|
|
184
|
-
var children = document.createElement("div");
|
|
185
|
-
children.id = childrenId;
|
|
186
|
-
children.className = "mobile-worker-children";
|
|
187
|
-
children.setAttribute("role", "group");
|
|
188
|
-
children.setAttribute("aria-label", "Workers for " + (root.driver.title || "New Session"));
|
|
189
|
-
children.hidden = !isExpanded;
|
|
190
|
-
var current = currentWorkerIds();
|
|
191
|
-
for (var i = 0; i < root.workers.length; i++) {
|
|
192
|
-
if (!visibleWorker(root.workers[i], root.driver, matchIds === undefined ? null : matchIds)) continue;
|
|
193
|
-
children.appendChild(renderSession(root.workers[i], { worker: true, current: current.has(root.workers[i].id) }));
|
|
194
|
-
}
|
|
195
|
-
wrapper.appendChild(children);
|
|
196
275
|
return wrapper;
|
|
197
276
|
}
|
|
198
277
|
|