@unbrained/pm-web 1.0.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.
Files changed (150) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/README.md +107 -0
  3. package/dist/auth.js +20 -0
  4. package/dist/auth.js.map +1 -0
  5. package/dist/crypto.js +42 -0
  6. package/dist/crypto.js.map +1 -0
  7. package/dist/db.js +111 -0
  8. package/dist/db.js.map +1 -0
  9. package/dist/index.js +88 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/middleware/auth.js +16 -0
  12. package/dist/middleware/auth.js.map +1 -0
  13. package/dist/routes/admin.js +207 -0
  14. package/dist/routes/admin.js.map +1 -0
  15. package/dist/routes/auth.js +163 -0
  16. package/dist/routes/auth.js.map +1 -0
  17. package/dist/routes/github.js +354 -0
  18. package/dist/routes/github.js.map +1 -0
  19. package/dist/routes/groups.js +180 -0
  20. package/dist/routes/groups.js.map +1 -0
  21. package/dist/routes/pm.js +2446 -0
  22. package/dist/routes/pm.js.map +1 -0
  23. package/dist/routes/projects.js +151 -0
  24. package/dist/routes/projects.js.map +1 -0
  25. package/dist/routes/sharing.js +155 -0
  26. package/dist/routes/sharing.js.map +1 -0
  27. package/dist/server.js +64 -0
  28. package/dist/server.js.map +1 -0
  29. package/dist/services/pm-runner.js +190 -0
  30. package/dist/services/pm-runner.js.map +1 -0
  31. package/dist/services/sse.js +111 -0
  32. package/dist/services/sse.js.map +1 -0
  33. package/manifest.json +15 -0
  34. package/package.json +111 -0
  35. package/public/icons/icon-192.png +0 -0
  36. package/public/icons/icon-512.png +0 -0
  37. package/public/index.html +265 -0
  38. package/public/manifest.json +66 -0
  39. package/public/src/api.js +28 -0
  40. package/public/src/api.js.map +1 -0
  41. package/public/src/api.ts +29 -0
  42. package/public/src/app.js +926 -0
  43. package/public/src/app.js.map +1 -0
  44. package/public/src/app.ts +929 -0
  45. package/public/src/components/modals.js +62 -0
  46. package/public/src/components/modals.js.map +1 -0
  47. package/public/src/components/modals.ts +73 -0
  48. package/public/src/components/toast.js +10 -0
  49. package/public/src/components/toast.js.map +1 -0
  50. package/public/src/components/toast.ts +13 -0
  51. package/public/src/constants.js +30 -0
  52. package/public/src/constants.js.map +1 -0
  53. package/public/src/constants.ts +41 -0
  54. package/public/src/state.js +15 -0
  55. package/public/src/state.js.map +1 -0
  56. package/public/src/state.ts +19 -0
  57. package/public/src/types.js +5 -0
  58. package/public/src/types.js.map +1 -0
  59. package/public/src/types.ts +253 -0
  60. package/public/src/utils.js +57 -0
  61. package/public/src/utils.js.map +1 -0
  62. package/public/src/utils.ts +56 -0
  63. package/public/src/views/activity.js +47 -0
  64. package/public/src/views/activity.js.map +1 -0
  65. package/public/src/views/activity.ts +41 -0
  66. package/public/src/views/admin.js +435 -0
  67. package/public/src/views/admin.js.map +1 -0
  68. package/public/src/views/admin.ts +504 -0
  69. package/public/src/views/auth.js +81 -0
  70. package/public/src/views/auth.js.map +1 -0
  71. package/public/src/views/auth.ts +74 -0
  72. package/public/src/views/calendar.js +133 -0
  73. package/public/src/views/calendar.js.map +1 -0
  74. package/public/src/views/calendar.ts +129 -0
  75. package/public/src/views/comments-audit.js +109 -0
  76. package/public/src/views/comments-audit.js.map +1 -0
  77. package/public/src/views/comments-audit.ts +108 -0
  78. package/public/src/views/config.js +322 -0
  79. package/public/src/views/config.js.map +1 -0
  80. package/public/src/views/config.ts +344 -0
  81. package/public/src/views/context.js +98 -0
  82. package/public/src/views/context.js.map +1 -0
  83. package/public/src/views/context.ts +100 -0
  84. package/public/src/views/create.js +293 -0
  85. package/public/src/views/create.js.map +1 -0
  86. package/public/src/views/create.ts +246 -0
  87. package/public/src/views/dedupe.js +51 -0
  88. package/public/src/views/dedupe.js.map +1 -0
  89. package/public/src/views/dedupe.ts +43 -0
  90. package/public/src/views/export.js +300 -0
  91. package/public/src/views/export.js.map +1 -0
  92. package/public/src/views/export.ts +274 -0
  93. package/public/src/views/github.js +360 -0
  94. package/public/src/views/github.js.map +1 -0
  95. package/public/src/views/github.ts +308 -0
  96. package/public/src/views/graph-canvas.js +1986 -0
  97. package/public/src/views/graph-canvas.js.map +1 -0
  98. package/public/src/views/graph-canvas.ts +2218 -0
  99. package/public/src/views/graph.js +1824 -0
  100. package/public/src/views/graph.js.map +1 -0
  101. package/public/src/views/graph.ts +1891 -0
  102. package/public/src/views/groups.js +186 -0
  103. package/public/src/views/groups.js.map +1 -0
  104. package/public/src/views/groups.ts +172 -0
  105. package/public/src/views/guide.js +151 -0
  106. package/public/src/views/guide.js.map +1 -0
  107. package/public/src/views/guide.ts +162 -0
  108. package/public/src/views/health.js +105 -0
  109. package/public/src/views/health.js.map +1 -0
  110. package/public/src/views/health.ts +102 -0
  111. package/public/src/views/items.js +1306 -0
  112. package/public/src/views/items.js.map +1 -0
  113. package/public/src/views/items.ts +1196 -0
  114. package/public/src/views/normalize.js +67 -0
  115. package/public/src/views/normalize.js.map +1 -0
  116. package/public/src/views/normalize.ts +58 -0
  117. package/public/src/views/plan.js +454 -0
  118. package/public/src/views/plan.js.map +1 -0
  119. package/public/src/views/plan.ts +496 -0
  120. package/public/src/views/projects.js +204 -0
  121. package/public/src/views/projects.js.map +1 -0
  122. package/public/src/views/projects.ts +196 -0
  123. package/public/src/views/router.js +227 -0
  124. package/public/src/views/router.js.map +1 -0
  125. package/public/src/views/router.ts +188 -0
  126. package/public/src/views/search.js +103 -0
  127. package/public/src/views/search.js.map +1 -0
  128. package/public/src/views/search.ts +94 -0
  129. package/public/src/views/settings.js +272 -0
  130. package/public/src/views/settings.js.map +1 -0
  131. package/public/src/views/settings.ts +190 -0
  132. package/public/src/views/shared.js +49 -0
  133. package/public/src/views/shared.js.map +1 -0
  134. package/public/src/views/shared.ts +49 -0
  135. package/public/src/views/sharing.js +152 -0
  136. package/public/src/views/sharing.js.map +1 -0
  137. package/public/src/views/sharing.ts +139 -0
  138. package/public/src/views/stats.js +92 -0
  139. package/public/src/views/stats.js.map +1 -0
  140. package/public/src/views/stats.ts +88 -0
  141. package/public/src/views/templates.js +117 -0
  142. package/public/src/views/templates.js.map +1 -0
  143. package/public/src/views/templates.ts +113 -0
  144. package/public/src/views/validate.js +54 -0
  145. package/public/src/views/validate.js.map +1 -0
  146. package/public/src/views/validate.ts +48 -0
  147. package/public/styles.css +2231 -0
  148. package/public/sw.js +318 -0
  149. package/public/tsconfig.json +20 -0
  150. package/sql/schema.sql +105 -0
@@ -0,0 +1,186 @@
1
+ import { api } from '../api.js';
2
+ import { escHtml } from '../utils.js';
3
+ import { showModal, hideModal, createModal, confirmDialog } from '../components/modals.js';
4
+ import { toast } from '../components/toast.js';
5
+ export async function renderGroupsView() {
6
+ const el = document.getElementById('content-groups');
7
+ if (!el)
8
+ return;
9
+ el.innerHTML = `
10
+ <div class="page-header">
11
+ <div><div class="page-title">Groups</div><div class="page-subtitle">Manage your teams</div></div>
12
+ <div class="page-actions">
13
+ <button class="btn btn-secondary btn-sm" onclick="window.__app.renderGroupsView()">↺ Refresh</button>
14
+ <button class="btn btn-primary" onclick="window.__app.openCreateGroupModal()">+ New Group</button>
15
+ </div>
16
+ </div>
17
+ <div id="groups-list"><div class="loading-state"><div class="loading-spinner"></div></div></div>`;
18
+ await loadGroups();
19
+ }
20
+ async function loadGroups() {
21
+ const el = document.getElementById('groups-list');
22
+ if (!el)
23
+ return;
24
+ try {
25
+ const data = await api('GET', '/groups');
26
+ const groups = data.groups || [];
27
+ if (groups.length === 0) {
28
+ el.innerHTML = `
29
+ <div class="empty-state">
30
+ <div class="empty-state-icon">◉</div>
31
+ <div class="empty-state-text">No groups yet</div>
32
+ <div class="empty-state-sub">Create a group to share projects with multiple teammates at once</div>
33
+ </div>`;
34
+ return;
35
+ }
36
+ el.innerHTML = `<div style="display:flex;flex-direction:column;gap:8px">
37
+ ${groups.map((g) => `
38
+ <div class="group-row" onclick="window.__app.openGroupDetail('${escHtml(g.id)}','${escHtml(g.name)}')">
39
+ <div style="width:36px;height:36px;border-radius:50%;background:var(--accent-dim);display:flex;align-items:center;justify-content:center;font-size:13px;font-weight:600;color:var(--accent);flex-shrink:0">
40
+ ${escHtml((g.name || '?').slice(0, 2).toUpperCase())}
41
+ </div>
42
+ <div style="flex:1">
43
+ <div class="group-name">${escHtml(g.name)}</div>
44
+ ${g.description ? `<div class="group-desc">${escHtml(g.description)}</div>` : ''}
45
+ </div>
46
+ <span class="sidebar-badge">${g.memberCount || g.members?.length || 0} members</span>
47
+ <button class="btn btn-danger btn-sm" onclick="event.stopPropagation();window.__app.deleteGroup('${escHtml(g.id)}','${escHtml(g.name)}')">Delete</button>
48
+ </div>`).join('')}
49
+ </div>`;
50
+ }
51
+ catch (err) {
52
+ if (el)
53
+ el.innerHTML = `<div class="empty-state"><div class="empty-state-text">Error: ${escHtml(err instanceof Error ? err.message : String(err))}</div></div>`;
54
+ }
55
+ }
56
+ export function openCreateGroupModal() {
57
+ createModal('create-group-modal', 'New Group', `
58
+ <div class="form-group">
59
+ <label class="form-label">Group Name *</label>
60
+ <input class="form-input" id="cg-name" type="text" placeholder="Engineering Team" required>
61
+ </div>
62
+ <div class="form-group">
63
+ <label class="form-label">Description</label>
64
+ <input class="form-input" id="cg-desc" type="text" placeholder="What is this group for?">
65
+ </div>
66
+ <div class="form-error" id="cg-error" style="display:none"></div>`, `<button class="btn btn-ghost" onclick="window.__app.hideModal('create-group-modal')">Cancel</button>
67
+ <button class="btn btn-primary" onclick="window.__app.submitCreateGroup()"><span>Create Group</span></button>`);
68
+ showModal('create-group-modal');
69
+ }
70
+ export async function submitCreateGroup() {
71
+ const name = document.getElementById('cg-name')?.value?.trim() || '';
72
+ const description = document.getElementById('cg-desc')?.value?.trim() || '';
73
+ const errEl = document.getElementById('cg-error');
74
+ if (errEl)
75
+ errEl.style.display = 'none';
76
+ if (!name) {
77
+ if (errEl) {
78
+ errEl.textContent = 'Group name is required';
79
+ errEl.style.display = 'block';
80
+ }
81
+ return;
82
+ }
83
+ try {
84
+ await api('POST', '/groups', { name, description });
85
+ toast('Group created', 'success');
86
+ hideModal('create-group-modal');
87
+ await loadGroups();
88
+ }
89
+ catch (err) {
90
+ if (errEl) {
91
+ errEl.textContent = err instanceof Error ? err.message : String(err);
92
+ errEl.style.display = 'block';
93
+ }
94
+ }
95
+ }
96
+ export function deleteGroup(groupId, name) {
97
+ confirmDialog('Delete Group?', `Delete group "${name}"? This cannot be undone.`, async () => {
98
+ try {
99
+ await api('DELETE', `/groups/${groupId}`);
100
+ toast('Group deleted', 'success');
101
+ await loadGroups();
102
+ }
103
+ catch (err) {
104
+ toast(err instanceof Error ? err.message : String(err), 'error');
105
+ }
106
+ }, true);
107
+ }
108
+ export async function openGroupDetail(groupId, _groupName) {
109
+ createModal('group-detail-modal', _groupName, `<div class="loading-state"><div class="loading-spinner"></div></div>`, '', true);
110
+ showModal('group-detail-modal');
111
+ try {
112
+ const data = await api('GET', `/groups/${groupId}`);
113
+ const group = data.group || { id: groupId, name: _groupName, members: [] };
114
+ const members = group.members || [];
115
+ const groupName = group.name || _groupName || 'Group';
116
+ const membersHtml = members.length === 0
117
+ ? `<div style="color:var(--text-muted);font-size:13px">No members yet</div>`
118
+ : members.map((m) => `
119
+ <div class="member-row">
120
+ <div class="member-avatar">${escHtml((m.display_name || m.displayName || m.email || '?').slice(0, 2).toUpperCase())}</div>
121
+ <div style="flex:1">
122
+ <div style="font-size:13px;font-weight:500">${escHtml(m.display_name || m.displayName || m.email || m.user_id || m.userId || 'Unknown')}</div>
123
+ ${m.email && (m.display_name || m.displayName) ? `<div class="group-desc">${escHtml(m.email)}</div>` : ''}
124
+ </div>
125
+ <span class="share-perm">${escHtml(m.role || 'member')}</span>
126
+ <button class="btn btn-danger btn-sm" onclick="window.__app.removeMember('${escHtml(groupId)}','${escHtml(m.user_id || m.userId || '')}')">Remove</button>
127
+ </div>`).join('');
128
+ const bodyEl = document.getElementById('group-detail-modal')?.querySelector('.modal-body');
129
+ const titleEl = document.getElementById('group-detail-modal')?.querySelector('.modal-title');
130
+ if (titleEl)
131
+ titleEl.textContent = groupName;
132
+ if (bodyEl) {
133
+ bodyEl.innerHTML = `
134
+ <div style="margin-bottom:20px">
135
+ <div style="font-size:11px;font-weight:600;color:var(--text-muted);text-transform:uppercase;letter-spacing:1px;margin-bottom:12px">
136
+ Members (${members.length})
137
+ </div>
138
+ ${membersHtml}
139
+ </div>
140
+ <hr class="section-divider">
141
+ <div style="font-size:11px;font-weight:600;color:var(--text-muted);text-transform:uppercase;letter-spacing:1px;margin-bottom:10px">
142
+ Invite Member
143
+ </div>
144
+ <div class="row">
145
+ <input class="form-input flex-1" id="invite-email-${escHtml(groupId)}" type="email" placeholder="colleague@example.com">
146
+ <button class="btn btn-primary btn-sm" onclick="window.__app.inviteMember('${escHtml(groupId)}')">Invite</button>
147
+ </div>`;
148
+ }
149
+ }
150
+ catch (err) {
151
+ const bodyEl = document.getElementById('group-detail-modal')?.querySelector('.modal-body');
152
+ if (bodyEl)
153
+ bodyEl.innerHTML = `<div class="empty-state"><div class="empty-state-text">Error: ${escHtml(err instanceof Error ? err.message : String(err))}</div></div>`;
154
+ }
155
+ }
156
+ export async function inviteMember(groupId) {
157
+ const emailEl = document.getElementById(`invite-email-${groupId}`);
158
+ const email = emailEl?.value?.trim() || '';
159
+ if (!email) {
160
+ toast('Email is required', 'error');
161
+ return;
162
+ }
163
+ try {
164
+ await api('POST', `/groups/${groupId}/members`, { email });
165
+ toast('Member invited', 'success');
166
+ if (emailEl)
167
+ emailEl.value = '';
168
+ await openGroupDetail(groupId, '');
169
+ }
170
+ catch (err) {
171
+ toast(err instanceof Error ? err.message : String(err), 'error');
172
+ }
173
+ }
174
+ export function removeMember(groupId, userId) {
175
+ confirmDialog('Remove Member?', 'Remove this member from the group?', async () => {
176
+ try {
177
+ await api('DELETE', `/groups/${groupId}/members/${userId}`);
178
+ toast('Member removed', 'success');
179
+ await openGroupDetail(groupId, '');
180
+ }
181
+ catch (err) {
182
+ toast(err instanceof Error ? err.message : String(err), 'error');
183
+ }
184
+ });
185
+ }
186
+ //# sourceMappingURL=groups.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"groups.js","sourceRoot":"","sources":["groups.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,172 @@
1
+ // ═══════════════════════════════════════════════════════════════
2
+ // GROUPS VIEW
3
+ // ═══════════════════════════════════════════════════════════════
4
+ import { state } from '../state.js';
5
+ import { api } from '../api.js';
6
+ import { escHtml } from '../utils.js';
7
+ import { showModal, hideModal, createModal, confirmDialog } from '../components/modals.js';
8
+ import { toast } from '../components/toast.js';
9
+
10
+ export async function renderGroupsView(): Promise<void> {
11
+ const el = document.getElementById('content-groups');
12
+ if (!el) return;
13
+ el.innerHTML = `
14
+ <div class="page-header">
15
+ <div><div class="page-title">Groups</div><div class="page-subtitle">Manage your teams</div></div>
16
+ <div class="page-actions">
17
+ <button class="btn btn-secondary btn-sm" onclick="window.__app.renderGroupsView()">↺ Refresh</button>
18
+ <button class="btn btn-primary" onclick="window.__app.openCreateGroupModal()">+ New Group</button>
19
+ </div>
20
+ </div>
21
+ <div id="groups-list"><div class="loading-state"><div class="loading-spinner"></div></div></div>`;
22
+ await loadGroups();
23
+ }
24
+
25
+ async function loadGroups(): Promise<void> {
26
+ const el = document.getElementById('groups-list');
27
+ if (!el) return;
28
+ try {
29
+ const data = await api('GET','/groups');
30
+ const groups = (data as any).groups || [];
31
+ if (groups.length === 0) {
32
+ el.innerHTML = `
33
+ <div class="empty-state">
34
+ <div class="empty-state-icon">◉</div>
35
+ <div class="empty-state-text">No groups yet</div>
36
+ <div class="empty-state-sub">Create a group to share projects with multiple teammates at once</div>
37
+ </div>`;
38
+ return;
39
+ }
40
+ el.innerHTML = `<div style="display:flex;flex-direction:column;gap:8px">
41
+ ${groups.map((g: any)=>`
42
+ <div class="group-row" onclick="window.__app.openGroupDetail('${escHtml(g.id)}','${escHtml(g.name)}')">
43
+ <div style="width:36px;height:36px;border-radius:50%;background:var(--accent-dim);display:flex;align-items:center;justify-content:center;font-size:13px;font-weight:600;color:var(--accent);flex-shrink:0">
44
+ ${escHtml((g.name||'?').slice(0,2).toUpperCase())}
45
+ </div>
46
+ <div style="flex:1">
47
+ <div class="group-name">${escHtml(g.name)}</div>
48
+ ${g.description ? `<div class="group-desc">${escHtml(g.description)}</div>` : ''}
49
+ </div>
50
+ <span class="sidebar-badge">${g.memberCount||g.members?.length||0} members</span>
51
+ <button class="btn btn-danger btn-sm" onclick="event.stopPropagation();window.__app.deleteGroup('${escHtml(g.id)}','${escHtml(g.name)}')">Delete</button>
52
+ </div>`).join('')}
53
+ </div>`;
54
+ } catch(err: unknown) {
55
+ if (el) el.innerHTML = `<div class="empty-state"><div class="empty-state-text">Error: ${escHtml(err instanceof Error ? err.message : String(err))}</div></div>`;
56
+ }
57
+ }
58
+
59
+ export function openCreateGroupModal(): void {
60
+ createModal('create-group-modal','New Group',`
61
+ <div class="form-group">
62
+ <label class="form-label">Group Name *</label>
63
+ <input class="form-input" id="cg-name" type="text" placeholder="Engineering Team" required>
64
+ </div>
65
+ <div class="form-group">
66
+ <label class="form-label">Description</label>
67
+ <input class="form-input" id="cg-desc" type="text" placeholder="What is this group for?">
68
+ </div>
69
+ <div class="form-error" id="cg-error" style="display:none"></div>`,
70
+ `<button class="btn btn-ghost" onclick="window.__app.hideModal('create-group-modal')">Cancel</button>
71
+ <button class="btn btn-primary" onclick="window.__app.submitCreateGroup()"><span>Create Group</span></button>`
72
+ );
73
+ showModal('create-group-modal');
74
+ }
75
+
76
+ export async function submitCreateGroup(): Promise<void> {
77
+ const name = (document.getElementById('cg-name') as HTMLInputElement | null)?.value?.trim() || '';
78
+ const description = (document.getElementById('cg-desc') as HTMLInputElement | null)?.value?.trim() || '';
79
+ const errEl = document.getElementById('cg-error') as HTMLElement | null;
80
+ if (errEl) errEl.style.display = 'none';
81
+ if (!name) { if (errEl) { errEl.textContent = 'Group name is required'; errEl.style.display = 'block'; } return; }
82
+ try {
83
+ await api('POST','/groups',{name,description});
84
+ toast('Group created','success');
85
+ hideModal('create-group-modal');
86
+ await loadGroups();
87
+ } catch(err: unknown) {
88
+ if (errEl) { errEl.textContent = err instanceof Error ? err.message : String(err); errEl.style.display = 'block'; }
89
+ }
90
+ }
91
+
92
+ export function deleteGroup(groupId: string, name: string): void {
93
+ confirmDialog('Delete Group?', `Delete group "${name}"? This cannot be undone.`, async () => {
94
+ try {
95
+ await api('DELETE',`/groups/${groupId}`);
96
+ toast('Group deleted','success');
97
+ await loadGroups();
98
+ } catch(err: unknown) { toast(err instanceof Error ? err.message : String(err),'error'); }
99
+ }, true);
100
+ }
101
+
102
+ export async function openGroupDetail(groupId: string, _groupName: string): Promise<void> {
103
+ createModal('group-detail-modal', _groupName,
104
+ `<div class="loading-state"><div class="loading-spinner"></div></div>`, '', true);
105
+ showModal('group-detail-modal');
106
+
107
+ try {
108
+ const data = await api('GET',`/groups/${groupId}`);
109
+ const group = (data as any).group || {id:groupId,name:_groupName,members:[]};
110
+ const members = group.members || [];
111
+ const groupName = group.name || _groupName || 'Group';
112
+
113
+ const membersHtml = members.length === 0
114
+ ? `<div style="color:var(--text-muted);font-size:13px">No members yet</div>`
115
+ : members.map((m: any)=>`
116
+ <div class="member-row">
117
+ <div class="member-avatar">${escHtml((m.display_name||m.displayName||m.email||'?').slice(0,2).toUpperCase())}</div>
118
+ <div style="flex:1">
119
+ <div style="font-size:13px;font-weight:500">${escHtml(m.display_name||m.displayName||m.email||m.user_id||m.userId||'Unknown')}</div>
120
+ ${m.email&&(m.display_name||m.displayName)?`<div class="group-desc">${escHtml(m.email)}</div>`:''}
121
+ </div>
122
+ <span class="share-perm">${escHtml(m.role||'member')}</span>
123
+ <button class="btn btn-danger btn-sm" onclick="window.__app.removeMember('${escHtml(groupId)}','${escHtml(m.user_id||m.userId||'')}')">Remove</button>
124
+ </div>`).join('');
125
+
126
+ const bodyEl = document.getElementById('group-detail-modal')?.querySelector('.modal-body');
127
+ const titleEl = document.getElementById('group-detail-modal')?.querySelector('.modal-title');
128
+ if (titleEl) titleEl.textContent = groupName;
129
+ if (bodyEl) {
130
+ bodyEl.innerHTML = `
131
+ <div style="margin-bottom:20px">
132
+ <div style="font-size:11px;font-weight:600;color:var(--text-muted);text-transform:uppercase;letter-spacing:1px;margin-bottom:12px">
133
+ Members (${members.length})
134
+ </div>
135
+ ${membersHtml}
136
+ </div>
137
+ <hr class="section-divider">
138
+ <div style="font-size:11px;font-weight:600;color:var(--text-muted);text-transform:uppercase;letter-spacing:1px;margin-bottom:10px">
139
+ Invite Member
140
+ </div>
141
+ <div class="row">
142
+ <input class="form-input flex-1" id="invite-email-${escHtml(groupId)}" type="email" placeholder="colleague@example.com">
143
+ <button class="btn btn-primary btn-sm" onclick="window.__app.inviteMember('${escHtml(groupId)}')">Invite</button>
144
+ </div>`;
145
+ }
146
+ } catch(err: unknown) {
147
+ const bodyEl = document.getElementById('group-detail-modal')?.querySelector('.modal-body');
148
+ if (bodyEl) bodyEl.innerHTML = `<div class="empty-state"><div class="empty-state-text">Error: ${escHtml(err instanceof Error ? err.message : String(err))}</div></div>`;
149
+ }
150
+ }
151
+
152
+ export async function inviteMember(groupId: string): Promise<void> {
153
+ const emailEl = document.getElementById(`invite-email-${groupId}`) as HTMLInputElement | null;
154
+ const email = emailEl?.value?.trim() || '';
155
+ if (!email) { toast('Email is required','error'); return; }
156
+ try {
157
+ await api('POST',`/groups/${groupId}/members`,{email});
158
+ toast('Member invited','success');
159
+ if (emailEl) emailEl.value = '';
160
+ await openGroupDetail(groupId, '');
161
+ } catch(err: unknown) { toast(err instanceof Error ? err.message : String(err),'error'); }
162
+ }
163
+
164
+ export function removeMember(groupId: string, userId: string): void {
165
+ confirmDialog('Remove Member?', 'Remove this member from the group?', async () => {
166
+ try {
167
+ await api('DELETE',`/groups/${groupId}/members/${userId}`);
168
+ toast('Member removed','success');
169
+ await openGroupDetail(groupId, '');
170
+ } catch(err: unknown) { toast(err instanceof Error ? err.message : String(err),'error'); }
171
+ });
172
+ }
@@ -0,0 +1,151 @@
1
+ // ═══════════════════════════════════════════════════════════════
2
+ // GUIDE VIEW
3
+ // ═══════════════════════════════════════════════════════════════
4
+ import { state } from '../state.js';
5
+ import { getGuide, getGuideTopic } from '../api.js';
6
+ import { escHtml } from '../utils.js';
7
+ import { toast } from '../components/toast.js';
8
+ const TOPIC_ICONS = {
9
+ quickstart: '🚀',
10
+ commands: '⌨️',
11
+ workflows: '🔄',
12
+ sdk: '🛠️',
13
+ extensions: '🧩',
14
+ skills: '🤖',
15
+ harnesses: '⚙️',
16
+ release: '📦',
17
+ };
18
+ function topicIcon(id) {
19
+ return TOPIC_ICONS[id] ?? '📖';
20
+ }
21
+ function renderTopicCards(topics) {
22
+ if (topics.length === 0) {
23
+ return '<div class="empty-state"><div class="empty-state-text">No guide topics found.</div></div>';
24
+ }
25
+ return `<div class="guide-topic-grid">${topics.map(t => `
26
+ <div class="card guide-topic-card" style="cursor:pointer;margin-bottom:0" onclick="window.__app.renderGuideView('${escHtml(t.id)}')">
27
+ <div class="guide-topic-icon">${topicIcon(t.id)}</div>
28
+ <div class="guide-topic-body">
29
+ <div class="guide-topic-title">${escHtml(t.title)}</div>
30
+ <div class="guide-topic-summary">${escHtml(t.summary || t.intent || '')}</div>
31
+ </div>
32
+ </div>`).join('')}</div>`;
33
+ }
34
+ function renderTopicDetail(topic) {
35
+ const commands = topic.commands ?? topic.quick_commands ?? [];
36
+ const related = topic.related ?? [];
37
+ return `
38
+ <div style="margin-bottom:16px">
39
+ <a href="#" class="guide-back-link" onclick="event.preventDefault();window.__app.renderGuideView()"
40
+ style="font-size:13px;color:var(--accent);text-decoration:none">← Back to topics</a>
41
+ </div>
42
+ <div class="page-header">
43
+ <div>
44
+ <div class="page-title">${topicIcon(topic.id)} ${escHtml(topic.title)}</div>
45
+ ${topic.intent ? `<div class="page-subtitle">${escHtml(topic.intent)}</div>` : ''}
46
+ </div>
47
+ </div>
48
+ ${topic.summary ? `
49
+ <div class="card" style="margin-bottom:16px">
50
+ <div class="card-body">
51
+ <div class="item-detail-desc">${escHtml(topic.summary)}</div>
52
+ </div>
53
+ </div>` : ''}
54
+ ${commands.length > 0 ? `
55
+ <div class="card" style="margin-bottom:16px">
56
+ <div class="card-header"><div class="card-title">Quick Commands</div></div>
57
+ <div class="card-body">
58
+ ${commands.map(cmd => `
59
+ <div class="guide-cmd-row">
60
+ <code class="guide-cmd-code">${escHtml(cmd)}</code>
61
+ <button class="btn btn-ghost btn-sm guide-copy-btn"
62
+ onclick="navigator.clipboard.writeText('${escHtml(cmd.replace(/'/g, "\\'"))}').then(()=>window.__app.toast('Copied!','success')).catch(()=>{})"
63
+ title="Copy to clipboard">⎘</button>
64
+ </div>`).join('')}
65
+ </div>
66
+ </div>` : ''}
67
+ ${topic.workflows && topic.workflows.length > 0 ? `
68
+ <div class="card" style="margin-bottom:16px">
69
+ <div class="card-header"><div class="card-title">Workflows</div></div>
70
+ <div class="card-body">
71
+ ${topic.workflows.map(wf => `
72
+ <div style="margin-bottom:16px">
73
+ <div style="font-weight:600;font-size:14px;margin-bottom:4px">${escHtml(wf.name)}</div>
74
+ ${wf.goal ? `<div style="font-size:13px;color:var(--text-muted);margin-bottom:8px">${escHtml(wf.goal)}</div>` : ''}
75
+ ${wf.commands && wf.commands.length > 0 ? wf.commands.map(cmd => `
76
+ <div class="guide-cmd-row">
77
+ <code class="guide-cmd-code">${escHtml(cmd)}</code>
78
+ <button class="btn btn-ghost btn-sm guide-copy-btn"
79
+ onclick="navigator.clipboard.writeText('${escHtml(cmd.replace(/'/g, "\\'"))}').then(()=>window.__app.toast('Copied!','success')).catch(()=>{})"
80
+ title="Copy to clipboard">⎘</button>
81
+ </div>`).join('') : ''}
82
+ </div>`).join('')}
83
+ </div>
84
+ </div>` : ''}
85
+ ${related.length > 0 ? `
86
+ <div class="card">
87
+ <div class="card-header"><div class="card-title">Related Topics</div></div>
88
+ <div class="card-body" style="display:flex;flex-wrap:wrap;gap:8px">
89
+ ${related.map(r => `
90
+ <a href="#" class="badge badge-secondary"
91
+ onclick="event.preventDefault();window.__app.renderGuideView('${escHtml(r)}')"
92
+ style="cursor:pointer;text-decoration:none">${escHtml(r)}</a>`).join('')}
93
+ </div>
94
+ </div>` : ''}`;
95
+ }
96
+ export async function renderGuideView(topicId) {
97
+ const el = document.getElementById('content-guide');
98
+ if (!el)
99
+ return;
100
+ if (!state.currentProject) {
101
+ el.innerHTML = '<div class="empty-state"><div class="empty-state-text">No project selected</div></div>';
102
+ return;
103
+ }
104
+ if (topicId) {
105
+ // Show single topic detail
106
+ el.innerHTML = `
107
+ <div style="margin-bottom:16px">
108
+ <a href="#" onclick="event.preventDefault();window.__app.renderGuideView()"
109
+ style="font-size:13px;color:var(--accent);text-decoration:none">← Back to topics</a>
110
+ </div>
111
+ <div id="guide-content"><div class="loading-state"><div class="loading-spinner"></div></div></div>`;
112
+ try {
113
+ const data = await getGuideTopic(state.currentProject.id, topicId);
114
+ const topic = data.topic || data;
115
+ const contentEl = document.getElementById('guide-content');
116
+ if (contentEl)
117
+ contentEl.innerHTML = renderTopicDetail(topic);
118
+ }
119
+ catch (err) {
120
+ const contentEl = document.getElementById('guide-content');
121
+ if (contentEl) {
122
+ contentEl.innerHTML = `<div class="empty-state"><div class="empty-state-text">Error: ${escHtml(err instanceof Error ? err.message : String(err))}</div></div>`;
123
+ }
124
+ toast(err instanceof Error ? err.message : 'Failed to load topic', 'error');
125
+ }
126
+ }
127
+ else {
128
+ // Show topic list
129
+ el.innerHTML = `
130
+ <div class="page-header">
131
+ <div><div class="page-title">Guide</div><div class="page-subtitle">${escHtml(state.currentProject.name)}</div></div>
132
+ <div class="page-actions"><button class="btn btn-secondary btn-sm" onclick="window.__app.renderGuideView()">↺ Refresh</button></div>
133
+ </div>
134
+ <div id="guide-content"><div class="loading-state"><div class="loading-spinner"></div></div></div>`;
135
+ try {
136
+ const data = await getGuide(state.currentProject.id);
137
+ const topics = data.topics || [];
138
+ const contentEl = document.getElementById('guide-content');
139
+ if (contentEl)
140
+ contentEl.innerHTML = renderTopicCards(topics);
141
+ }
142
+ catch (err) {
143
+ const contentEl = document.getElementById('guide-content');
144
+ if (contentEl) {
145
+ contentEl.innerHTML = `<div class="empty-state"><div class="empty-state-text">Error: ${escHtml(err instanceof Error ? err.message : String(err))}</div></div>`;
146
+ }
147
+ toast(err instanceof Error ? err.message : 'Failed to load guide', 'error');
148
+ }
149
+ }
150
+ }
151
+ //# sourceMappingURL=guide.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guide.js","sourceRoot":"","sources":["guide.ts"],"names":[],"mappings":"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"}