| 1 |
|
| 2 |
* GoingsOn - Groups (shared-workspace) client cache + badge helpers. |
| 3 |
* |
| 4 |
* A thin, lazily-populated cache of the groups you belong to, keyed by id, so |
| 5 |
* the UI can resolve a project's `groupId` to a human name without a round-trip |
| 6 |
* per render. Sharing is whole-project, so a task's share state is its project's |
| 7 |
* share state; the badge helpers reflect that. |
| 8 |
* |
| 9 |
* The admin/list commands themselves live on `GoingsOn.api.groups`; this module |
| 10 |
* is only the render-side cache. Invalidate it whenever group membership changes |
| 11 |
* (a group is created, joined, or renamed). |
| 12 |
|
| 13 |
|
| 14 |
(function() { |
| 15 |
'use strict'; |
| 16 |
const esc = GoingsOn.utils.escapeHtml; |
| 17 |
const escAttr = GoingsOn.utils.escapeAttrValue; |
| 18 |
|
| 19 |
let cache = null; |
| 20 |
let byId = {}; |
| 21 |
|
| 22 |
|
| 23 |
* Load the group list into the cache if it is not already loaded. Non-fatal: |
| 24 |
* if sync is not configured the cache stays null and names do not |
| 25 |
* resolve (badges still render as a bare "Shared"). |
| 26 |
* @returns {Promise<Array>} the cached groups (possibly empty) |
| 27 |
|
| 28 |
async function ensureLoaded() { |
| 29 |
if (cache) return cache; |
| 30 |
try { |
| 31 |
const list = await GoingsOn.api.groups.list(); |
| 32 |
cache = list; |
| 33 |
byId = {}; |
| 34 |
list.forEach(g => { byId[g.id] = g; }); |
| 35 |
} catch (_) { |
| 36 |
|
| 37 |
} |
| 38 |
return cache || []; |
| 39 |
} |
| 40 |
|
| 41 |
|
| 42 |
function nameFor(groupId) { |
| 43 |
if (!groupId) return null; |
| 44 |
const g = byId[groupId]; |
| 45 |
return g ? g.name : null; |
| 46 |
} |
| 47 |
|
| 48 |
|
| 49 |
function invalidate() { |
| 50 |
cache = null; |
| 51 |
byId = {}; |
| 52 |
} |
| 53 |
|
| 54 |
|
| 55 |
* Badge HTML for a project's card meta, or '' when the project is personal. |
| 56 |
* Shows the group name when known, otherwise a bare "Shared". |
| 57 |
|
| 58 |
function projectCardBadge(project) { |
| 59 |
if (!project || !project.groupId) return ''; |
| 60 |
const name = nameFor(project.groupId); |
| 61 |
const label = name ? `Shared · ${name}` : 'Shared'; |
| 62 |
return `<span class="tag tag-shared" title="${escAttr(label)}">${esc(label)}</span>`; |
| 63 |
} |
| 64 |
|
| 65 |
|
| 66 |
* Small inline marker for a task row whose project is shared, resolved from |
| 67 |
* the projects cache (best-effort; no badge if projects are not loaded). |
| 68 |
|
| 69 |
function taskSharedBadge(projectId) { |
| 70 |
if (!projectId) return ''; |
| 71 |
const project = GoingsOn.getProjectsCache().find(p => p.id === projectId); |
| 72 |
if (!project || !project.groupId) return ''; |
| 73 |
const name = nameFor(project.groupId); |
| 74 |
const label = name ? `Shared · ${name}` : 'Shared'; |
| 75 |
return `<span class="shared-badge" title="${escAttr(label)}">Shared</span>`; |
| 76 |
} |
| 77 |
|
| 78 |
GoingsOn.groups = { |
| 79 |
ensureLoaded, |
| 80 |
nameFor, |
| 81 |
invalidate, |
| 82 |
projectCardBadge, |
| 83 |
taskSharedBadge, |
| 84 |
list: () => cache || [], |
| 85 |
}; |
| 86 |
|
| 87 |
})(); |
| 88 |
|