clay-server 4.0.1-beta.1 → 4.1.0-beta.2
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/lib/daemon-project-access.js +118 -0
- package/lib/daemon-projects.js +19 -5
- package/lib/daemon.js +19 -18
- package/lib/project-logs-access-scope.js +94 -0
- package/lib/project-logs-query.js +3 -0
- package/lib/project-logs-service.js +86 -84
- package/lib/project-logs-store.js +5 -3
- package/lib/project-pair-lifecycle.js +140 -102
- package/lib/project-pair-message.js +50 -0
- package/lib/project-pair-replacement-state.js +72 -0
- package/lib/project-pair-task-control.js +264 -0
- package/lib/project-pair-usage.js +76 -0
- package/lib/project-session-pair.js +115 -116
- package/lib/project-sessions.js +25 -1
- package/lib/project-worker-proposal.js +69 -58
- package/lib/project.js +21 -4
- package/lib/public/css/icon-strip.css +40 -0
- package/lib/public/modules/app-messages.js +9 -0
- package/lib/public/modules/project-access.js +141 -0
- package/lib/public/modules/project-grouping.js +22 -0
- package/lib/public/modules/sidebar-projects.js +14 -171
- package/lib/public/modules/worker-proposal.js +4 -0
- package/lib/sdk-bridge.js +20 -0
- package/lib/server-admin.js +3 -3
- package/lib/server-global-ws.js +10 -0
- package/lib/server-mates.js +4 -3
- package/lib/server-palette.js +17 -14
- package/lib/server.js +184 -102
- package/lib/session-pair-factory.js +3 -0
- package/lib/session-pair-history.js +40 -0
- package/lib/session-pair-mcp-server.js +19 -2
- package/lib/session-pair-operation.js +11 -0
- package/lib/session-pair-prompts.js +24 -2
- package/lib/session-pair-turn-control.js +8 -3
- package/lib/session-provenance.js +1 -0
- package/lib/session-spawn-mcp-server.js +2 -1
- package/lib/sessions.js +2 -0
- package/lib/worker-proposal-control.js +69 -0
- package/lib/worker-proposal-decision.js +7 -0
- package/lib/worker-runtime-catalog.js +52 -0
- package/lib/workspace-query-access.js +3 -2
- package/lib/workspace-query-service.js +1 -1
- package/lib/worktree.js +8 -4
- package/lib/ws-schema.js +1 -0
- package/lib/yoke/adapters/codex.js +25 -7
- package/package.json +1 -1
|
@@ -14,6 +14,8 @@ import { switchProject, openAddProjectModal, getCachedProjects } from './app-pro
|
|
|
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
|
+
import { groupProjects } from './project-grouping.js';
|
|
18
|
+
import { showProjectAccessPopover } from './project-access.js';
|
|
17
19
|
|
|
18
20
|
// --- Project state ---
|
|
19
21
|
var cachedProjectList = [];
|
|
@@ -22,9 +24,6 @@ var cachedCurrentSlug = null;
|
|
|
22
24
|
// --- Project context menu ---
|
|
23
25
|
var projectCtxMenu = null;
|
|
24
26
|
|
|
25
|
-
// --- Project Access Popover ---
|
|
26
|
-
var projectAccessPopover = null;
|
|
27
|
-
|
|
28
27
|
// --- Emoji picker ---
|
|
29
28
|
var emojiPickerEl = null;
|
|
30
29
|
|
|
@@ -338,149 +337,6 @@ function getProjectAbbrev(name) {
|
|
|
338
337
|
|
|
339
338
|
export { getProjectAbbrev };
|
|
340
339
|
|
|
341
|
-
// --- Project Access Popover ---
|
|
342
|
-
|
|
343
|
-
function closeAccessOnOutside(e) {
|
|
344
|
-
if (projectAccessPopover && !projectAccessPopover.contains(e.target)) closeProjectAccessPopover();
|
|
345
|
-
}
|
|
346
|
-
function closeAccessOnEscape(e) {
|
|
347
|
-
if (e.key === "Escape") closeProjectAccessPopover();
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
function closeProjectAccessPopover() {
|
|
351
|
-
if (projectAccessPopover) {
|
|
352
|
-
projectAccessPopover.remove();
|
|
353
|
-
projectAccessPopover = null;
|
|
354
|
-
document.removeEventListener("click", closeAccessOnOutside);
|
|
355
|
-
document.removeEventListener("keydown", closeAccessOnEscape);
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
function showProjectAccessPopover(anchorEl, slug) {
|
|
360
|
-
closeProjectAccessPopover();
|
|
361
|
-
|
|
362
|
-
var popover = document.createElement("div");
|
|
363
|
-
popover.className = "project-access-popover";
|
|
364
|
-
popover.innerHTML = '<div class="project-access-loading">Loading...</div>';
|
|
365
|
-
popover.addEventListener("click", function (e) { e.stopPropagation(); });
|
|
366
|
-
document.body.appendChild(popover);
|
|
367
|
-
projectAccessPopover = popover;
|
|
368
|
-
|
|
369
|
-
requestAnimationFrame(function () {
|
|
370
|
-
var rect = anchorEl.getBoundingClientRect();
|
|
371
|
-
popover.style.position = "fixed";
|
|
372
|
-
popover.style.left = (rect.right + 8) + "px";
|
|
373
|
-
popover.style.top = rect.top + "px";
|
|
374
|
-
popover.style.zIndex = "9999";
|
|
375
|
-
var popRect = popover.getBoundingClientRect();
|
|
376
|
-
if (popRect.right > window.innerWidth - 8) {
|
|
377
|
-
popover.style.left = (rect.left - popRect.width - 8) + "px";
|
|
378
|
-
}
|
|
379
|
-
if (popRect.bottom > window.innerHeight - 8) {
|
|
380
|
-
popover.style.top = (window.innerHeight - popRect.height - 8) + "px";
|
|
381
|
-
}
|
|
382
|
-
});
|
|
383
|
-
|
|
384
|
-
setTimeout(function () {
|
|
385
|
-
document.addEventListener("click", closeAccessOnOutside);
|
|
386
|
-
document.addEventListener("keydown", closeAccessOnEscape);
|
|
387
|
-
}, 0);
|
|
388
|
-
|
|
389
|
-
Promise.all([
|
|
390
|
-
fetch("/api/admin/projects/" + encodeURIComponent(slug) + "/access").then(function (r) { return r.json(); }),
|
|
391
|
-
fetch("/api/admin/users").then(function (r) { return r.json(); }),
|
|
392
|
-
]).then(function (results) {
|
|
393
|
-
var access = results[0];
|
|
394
|
-
var usersData = results[1];
|
|
395
|
-
if (access.error || usersData.error) {
|
|
396
|
-
popover.innerHTML = '<div class="project-access-loading">Failed to load</div>';
|
|
397
|
-
return;
|
|
398
|
-
}
|
|
399
|
-
renderAccessPopover(popover, slug, access, usersData.users || []);
|
|
400
|
-
}).catch(function () {
|
|
401
|
-
popover.innerHTML = '<div class="project-access-loading">Failed to load</div>';
|
|
402
|
-
});
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
function renderAccessPopover(popover, slug, access, allUsers) {
|
|
406
|
-
var visibility = access.visibility || "public";
|
|
407
|
-
var allowedUsers = access.allowedUsers || [];
|
|
408
|
-
var ownerId = access.ownerId;
|
|
409
|
-
|
|
410
|
-
var selectableUsers = allUsers.filter(function (u) { return u.id !== ownerId; });
|
|
411
|
-
|
|
412
|
-
var html = '';
|
|
413
|
-
html += '<div class="project-access-header">';
|
|
414
|
-
html += '<span class="project-access-title">Project Access</span>';
|
|
415
|
-
html += '<button class="project-access-close">×</button>';
|
|
416
|
-
html += '</div>';
|
|
417
|
-
|
|
418
|
-
html += '<div class="project-access-section">';
|
|
419
|
-
html += '<label class="project-access-label">Visibility</label>';
|
|
420
|
-
html += '<div class="project-access-vis-row">';
|
|
421
|
-
html += '<button class="project-access-vis-btn' + (visibility === "private" ? ' active' : '') + '" data-vis="private">';
|
|
422
|
-
html += iconHtml("lock") + ' Private';
|
|
423
|
-
html += '</button>';
|
|
424
|
-
html += '<button class="project-access-vis-btn' + (visibility === "public" ? ' active' : '') + '" data-vis="public">';
|
|
425
|
-
html += iconHtml("globe") + ' Public';
|
|
426
|
-
html += '</button>';
|
|
427
|
-
html += '</div>';
|
|
428
|
-
html += '</div>';
|
|
429
|
-
|
|
430
|
-
html += '<div class="project-access-section project-access-users-section"' + (visibility !== "private" ? ' style="display:none"' : '') + '>';
|
|
431
|
-
html += '<label class="project-access-label">Allowed Users</label>';
|
|
432
|
-
html += '<div class="project-access-user-list">';
|
|
433
|
-
for (var i = 0; i < selectableUsers.length; i++) {
|
|
434
|
-
var u = selectableUsers[i];
|
|
435
|
-
var checked = allowedUsers.indexOf(u.id) !== -1 ? " checked" : "";
|
|
436
|
-
html += '<label class="project-access-user-item">';
|
|
437
|
-
html += '<input type="checkbox" data-uid="' + u.id + '"' + checked + '>';
|
|
438
|
-
html += '<span>' + escapeHtml(u.displayName || u.username || u.id) + '</span>';
|
|
439
|
-
html += '</label>';
|
|
440
|
-
}
|
|
441
|
-
if (selectableUsers.length === 0) {
|
|
442
|
-
html += '<div class="project-access-empty">No other users</div>';
|
|
443
|
-
}
|
|
444
|
-
html += '</div>';
|
|
445
|
-
html += '</div>';
|
|
446
|
-
|
|
447
|
-
popover.innerHTML = html;
|
|
448
|
-
refreshIcons();
|
|
449
|
-
|
|
450
|
-
popover.querySelector(".project-access-close").addEventListener("click", function () {
|
|
451
|
-
closeProjectAccessPopover();
|
|
452
|
-
});
|
|
453
|
-
|
|
454
|
-
popover.querySelectorAll(".project-access-vis-btn").forEach(function (btn) {
|
|
455
|
-
btn.addEventListener("click", function () {
|
|
456
|
-
var newVis = btn.dataset.vis;
|
|
457
|
-
popover.querySelectorAll(".project-access-vis-btn").forEach(function (b) { b.classList.remove("active"); });
|
|
458
|
-
btn.classList.add("active");
|
|
459
|
-
var usersSection = popover.querySelector(".project-access-users-section");
|
|
460
|
-
if (usersSection) usersSection.style.display = newVis === "private" ? "" : "none";
|
|
461
|
-
fetch("/api/admin/projects/" + encodeURIComponent(slug) + "/visibility", {
|
|
462
|
-
method: "PUT",
|
|
463
|
-
headers: { "Content-Type": "application/json" },
|
|
464
|
-
body: JSON.stringify({ visibility: newVis }),
|
|
465
|
-
});
|
|
466
|
-
});
|
|
467
|
-
});
|
|
468
|
-
|
|
469
|
-
popover.querySelectorAll('.project-access-user-item input[type="checkbox"]').forEach(function (cb) {
|
|
470
|
-
cb.addEventListener("change", function () {
|
|
471
|
-
var selected = [];
|
|
472
|
-
popover.querySelectorAll('.project-access-user-item input[type="checkbox"]:checked').forEach(function (c) {
|
|
473
|
-
selected.push(c.dataset.uid);
|
|
474
|
-
});
|
|
475
|
-
fetch("/api/admin/projects/" + encodeURIComponent(slug) + "/users", {
|
|
476
|
-
method: "PUT",
|
|
477
|
-
headers: { "Content-Type": "application/json" },
|
|
478
|
-
body: JSON.stringify({ allowedUsers: selected }),
|
|
479
|
-
});
|
|
480
|
-
});
|
|
481
|
-
});
|
|
482
|
-
}
|
|
483
|
-
|
|
484
340
|
// --- Project context menu ---
|
|
485
341
|
|
|
486
342
|
export function closeProjectCtxMenu() {
|
|
@@ -603,7 +459,7 @@ function showProjectCtxMenu(anchorEl, slug, name, icon, position) {
|
|
|
603
459
|
menu.appendChild(shareItem);
|
|
604
460
|
|
|
605
461
|
// --- Manage Access ---
|
|
606
|
-
if (store.get('isMultiUserMode')
|
|
462
|
+
if (store.get('isMultiUserMode')) {
|
|
607
463
|
var isProjectOwner = store.get('myUserId') && store.get('currentProjectOwnerId') && store.get('myUserId') === store.get('currentProjectOwnerId');
|
|
608
464
|
var isAdmin = store.get('permissions') && store.get('permissions').projectSettings !== false;
|
|
609
465
|
if (isProjectOwner || isAdmin) {
|
|
@@ -624,15 +480,17 @@ function showProjectCtxMenu(anchorEl, slug, name, icon, position) {
|
|
|
624
480
|
menu.appendChild(sep2);
|
|
625
481
|
|
|
626
482
|
// --- Add Worktree ---
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
483
|
+
if (slug.indexOf("--") === -1) {
|
|
484
|
+
var wtItem = document.createElement("button");
|
|
485
|
+
wtItem.className = "project-ctx-item";
|
|
486
|
+
wtItem.innerHTML = iconHtml("git-branch") + " <span>Add Worktree</span>";
|
|
487
|
+
wtItem.addEventListener("click", function (e) {
|
|
488
|
+
e.stopPropagation();
|
|
489
|
+
closeProjectCtxMenu();
|
|
490
|
+
showWorktreeModal(slug, name || slug);
|
|
491
|
+
});
|
|
492
|
+
menu.appendChild(wtItem);
|
|
493
|
+
}
|
|
636
494
|
|
|
637
495
|
if (!store.get('permissions') || store.get('permissions').deleteProject !== false) {
|
|
638
496
|
var sep3 = document.createElement("div");
|
|
@@ -959,21 +817,6 @@ function setWtCollapsed(slug, collapsed) {
|
|
|
959
817
|
wtCollapsed[slug] = collapsed;
|
|
960
818
|
}
|
|
961
819
|
|
|
962
|
-
function groupProjects(projects) {
|
|
963
|
-
var parents = [];
|
|
964
|
-
var wtByParent = {};
|
|
965
|
-
for (var i = 0; i < projects.length; i++) {
|
|
966
|
-
var p = projects[i];
|
|
967
|
-
if (p.isWorktree && p.parentSlug) {
|
|
968
|
-
if (!wtByParent[p.parentSlug]) wtByParent[p.parentSlug] = [];
|
|
969
|
-
wtByParent[p.parentSlug].push(p);
|
|
970
|
-
} else {
|
|
971
|
-
parents.push(p);
|
|
972
|
-
}
|
|
973
|
-
}
|
|
974
|
-
return { parents: parents, wtByParent: wtByParent };
|
|
975
|
-
}
|
|
976
|
-
|
|
977
820
|
// --- Icon item creation ---
|
|
978
821
|
|
|
979
822
|
function createIconItem(p, currentSlug) {
|
|
@@ -98,6 +98,8 @@ function statusLabel(status) {
|
|
|
98
98
|
if (status === "completed") return "Completed";
|
|
99
99
|
if (status === "interrupted") return "Interrupted";
|
|
100
100
|
if (status === "declined") return "Continuing here";
|
|
101
|
+
if (status === "cancelled") return "Cancelled";
|
|
102
|
+
if (status === "superseded") return "Superseded";
|
|
101
103
|
if (status === "error") return "Needs attention";
|
|
102
104
|
return "Awaiting your choice";
|
|
103
105
|
}
|
|
@@ -106,6 +108,8 @@ function decisionLabel(status, autoAccepted) {
|
|
|
106
108
|
if (autoAccepted) return "Driver recommendation auto-accepted under Full auto";
|
|
107
109
|
if (status === "pending") return "Runtime choice remains with you";
|
|
108
110
|
if (status === "declined") return "Runtime proposal declined by user";
|
|
111
|
+
if (status === "cancelled") return "Runtime proposal cancelled by Driver";
|
|
112
|
+
if (status === "superseded") return "Replaced by a newer runtime proposal";
|
|
109
113
|
return "Runtime configuration accepted by user";
|
|
110
114
|
}
|
|
111
115
|
|
package/lib/sdk-bridge.js
CHANGED
|
@@ -627,8 +627,18 @@ function createSDKBridge(opts) {
|
|
|
627
627
|
var PAIR_MCP_PREFIX = "mcp__clay-sessions__";
|
|
628
628
|
var pairMcpTools = {
|
|
629
629
|
propose_worker: true,
|
|
630
|
+
inspect_worker_proposal: true,
|
|
631
|
+
cancel_worker_proposal: true,
|
|
632
|
+
worker_runtime_catalog: true,
|
|
630
633
|
send_to_partner: true,
|
|
631
634
|
read_partner: true,
|
|
635
|
+
message_partner: true,
|
|
636
|
+
queue_partner_followup: true,
|
|
637
|
+
inspect_partner_followups: true,
|
|
638
|
+
cancel_partner_followup: true,
|
|
639
|
+
replace_partner_task: true,
|
|
640
|
+
resume_partner_task: true,
|
|
641
|
+
report_partner_outcome: true,
|
|
632
642
|
partner_status: true,
|
|
633
643
|
replace_partner: true,
|
|
634
644
|
interrupt_partner: true,
|
|
@@ -638,6 +648,16 @@ function createSDKBridge(opts) {
|
|
|
638
648
|
};
|
|
639
649
|
var pairDynamicTools = {
|
|
640
650
|
propose_worker: true,
|
|
651
|
+
inspect_worker_proposal: true,
|
|
652
|
+
cancel_worker_proposal: true,
|
|
653
|
+
worker_runtime_catalog: true,
|
|
654
|
+
message_partner: true,
|
|
655
|
+
queue_partner_followup: true,
|
|
656
|
+
inspect_partner_followups: true,
|
|
657
|
+
cancel_partner_followup: true,
|
|
658
|
+
replace_partner_task: true,
|
|
659
|
+
resume_partner_task: true,
|
|
660
|
+
report_partner_outcome: true,
|
|
641
661
|
partner_status: true,
|
|
642
662
|
replace_partner: true,
|
|
643
663
|
interrupt_partner: true,
|
package/lib/server-admin.js
CHANGED
|
@@ -632,9 +632,9 @@ function attachAdmin(ctx) {
|
|
|
632
632
|
return true;
|
|
633
633
|
}
|
|
634
634
|
var projSlug = fullUrl.split("/")[4];
|
|
635
|
-
if (
|
|
636
|
-
res.writeHead(
|
|
637
|
-
res.end('{"error":"
|
|
635
|
+
if (!projects.get(projSlug)) {
|
|
636
|
+
res.writeHead(404, { "Content-Type": "application/json" });
|
|
637
|
+
res.end('{"error":"Project not found"}');
|
|
638
638
|
return true;
|
|
639
639
|
}
|
|
640
640
|
var body = "";
|
package/lib/server-global-ws.js
CHANGED
|
@@ -40,6 +40,8 @@ function attachGlobalWs(opts) {
|
|
|
40
40
|
var onCloneProject = opts.onCloneProject;
|
|
41
41
|
var onHomePreferenceMessage = opts.onHomePreferenceMessage;
|
|
42
42
|
var onAppMessage = opts.onAppMessage;
|
|
43
|
+
var onConnection = opts.onConnection;
|
|
44
|
+
var clients = new Set();
|
|
43
45
|
|
|
44
46
|
function handleMessage(ws, msg) {
|
|
45
47
|
if (!msg || typeof msg !== "object") return;
|
|
@@ -184,16 +186,24 @@ function attachGlobalWs(opts) {
|
|
|
184
186
|
|
|
185
187
|
function handleConnection(ws, wsUser) {
|
|
186
188
|
ws._clayUser = wsUser || null;
|
|
189
|
+
clients.add(ws);
|
|
190
|
+
ws.on("close", function () { clients.delete(ws); });
|
|
187
191
|
ws.on("message", function (data) {
|
|
188
192
|
var msg;
|
|
189
193
|
try { msg = JSON.parse(data); } catch (e) { return; }
|
|
190
194
|
handleMessage(ws, msg);
|
|
191
195
|
});
|
|
196
|
+
if (typeof onConnection === "function") onConnection(ws);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function forEachClient(visitor) {
|
|
200
|
+
clients.forEach(function (ws) { visitor(ws); });
|
|
192
201
|
}
|
|
193
202
|
|
|
194
203
|
return {
|
|
195
204
|
handleConnection: handleConnection,
|
|
196
205
|
handleMessage: handleMessage,
|
|
206
|
+
forEachClient: forEachClient,
|
|
197
207
|
};
|
|
198
208
|
}
|
|
199
209
|
|
package/lib/server-mates.js
CHANGED
|
@@ -20,11 +20,12 @@ function attachMates(ctx) {
|
|
|
20
20
|
var projList = [];
|
|
21
21
|
projects.forEach(function (pCtx, pSlug) {
|
|
22
22
|
var st = pCtx.getStatus();
|
|
23
|
-
if (st.isMate
|
|
23
|
+
if (st.isMate) return;
|
|
24
24
|
// Filter by user access in multi-user mode
|
|
25
|
-
if (
|
|
25
|
+
if (users.isMultiUser() && onGetProjectAccess) {
|
|
26
|
+
if (!userId) return;
|
|
26
27
|
var access = onGetProjectAccess(pSlug);
|
|
27
|
-
if (access
|
|
28
|
+
if (!access || access.error || !users.canAccessProject(userId, access)) return;
|
|
28
29
|
}
|
|
29
30
|
projList.push(st);
|
|
30
31
|
});
|
package/lib/server-palette.js
CHANGED
|
@@ -5,6 +5,17 @@ function attachPalette(ctx) {
|
|
|
5
5
|
var projects = ctx.projects;
|
|
6
6
|
var getMultiUserFromReq = ctx.getMultiUserFromReq;
|
|
7
7
|
var onGetProjectAccess = ctx.onGetProjectAccess;
|
|
8
|
+
var canUserAccessSlug = ctx.canUserAccessSlug;
|
|
9
|
+
|
|
10
|
+
function accessFor(user, slug, status) {
|
|
11
|
+
if (!user) return { visibility: "public" };
|
|
12
|
+
if (typeof canUserAccessSlug !== "function" || !canUserAccessSlug(user.id, slug)) return null;
|
|
13
|
+
if (status && status.isMate) {
|
|
14
|
+
return { visibility: "private", ownerId: status.projectOwnerId || null, allowedUsers: [] };
|
|
15
|
+
}
|
|
16
|
+
var access = onGetProjectAccess ? onGetProjectAccess(slug) : null;
|
|
17
|
+
return access && !access.error ? access : null;
|
|
18
|
+
}
|
|
8
19
|
|
|
9
20
|
function handleRequest(req, res, fullUrl) {
|
|
10
21
|
if (req.method !== "GET" || fullUrl !== "/api/palette/search") return false;
|
|
@@ -26,17 +37,13 @@ function attachPalette(ctx) {
|
|
|
26
37
|
// Recent mode: return all sessions sorted by lastActivity
|
|
27
38
|
projects.forEach(function (pCtx, pSlug) {
|
|
28
39
|
var status = pCtx.getStatus();
|
|
29
|
-
|
|
30
|
-
if (paletteUser &&
|
|
31
|
-
var pAccess = onGetProjectAccess(pSlug);
|
|
32
|
-
if (pAccess && !pAccess.error && !users.canAccessProject(paletteUser.id, pAccess)) return;
|
|
33
|
-
}
|
|
40
|
+
var pAccess = accessFor(paletteUser, pSlug, status);
|
|
41
|
+
if (paletteUser && !pAccess) return;
|
|
34
42
|
pCtx.sm.sessions.forEach(function (session) {
|
|
35
43
|
if (session.hidden) return;
|
|
36
44
|
if (paletteUser) {
|
|
37
45
|
if (users.isMultiUser()) {
|
|
38
|
-
|
|
39
|
-
if (!users.canAccessSession(paletteUser.id, session, sAccess)) return;
|
|
46
|
+
if (!users.canAccessSession(paletteUser.id, session, pAccess)) return;
|
|
40
47
|
}
|
|
41
48
|
} else {
|
|
42
49
|
if (session.ownerId) return;
|
|
@@ -65,18 +72,14 @@ function attachPalette(ctx) {
|
|
|
65
72
|
var projectSessions = [];
|
|
66
73
|
projects.forEach(function (pCtx, pSlug) {
|
|
67
74
|
var status = pCtx.getStatus();
|
|
68
|
-
|
|
69
|
-
if (paletteUser &&
|
|
70
|
-
var pAccess = onGetProjectAccess(pSlug);
|
|
71
|
-
if (pAccess && !pAccess.error && !users.canAccessProject(paletteUser.id, pAccess)) return;
|
|
72
|
-
}
|
|
75
|
+
var pAccess = accessFor(paletteUser, pSlug, status);
|
|
76
|
+
if (paletteUser && !pAccess) return;
|
|
73
77
|
var accessibleSessions = [];
|
|
74
78
|
pCtx.sm.sessions.forEach(function (session) {
|
|
75
79
|
if (session.hidden) return;
|
|
76
80
|
if (paletteUser) {
|
|
77
81
|
if (users.isMultiUser()) {
|
|
78
|
-
|
|
79
|
-
if (!users.canAccessSession(paletteUser.id, session, sAccess)) return;
|
|
82
|
+
if (!users.canAccessSession(paletteUser.id, session, pAccess)) return;
|
|
80
83
|
}
|
|
81
84
|
} else {
|
|
82
85
|
if (session.ownerId) return;
|