@unbrained/pm-web 2026.7.26 → 2026.7.28

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.
@@ -0,0 +1,238 @@
1
+ // ═══════════════════════════════════════════════════════════════
2
+ // PACKAGES VIEW — per-project pm package catalog
3
+ // ═══════════════════════════════════════════════════════════════
4
+ //
5
+ // Lists every pm package from the server-side catalog
6
+ // (src/services/package-catalog.ts, surfaced via
7
+ // GET /api/projects/:projectId/extensions) with install/enable/disable
8
+ // controls, the currently installed version, and an honest explanation for
9
+ // packages that need credentials or a backing service. Mutations go through
10
+ // the extensions routes, which validate the package name against the catalog
11
+ // before any pm command is spawned, and broadcast on the existing realtime bus
12
+ // so every collaborator on the project sees the change live.
13
+ //
14
+ // User-facing strings are wired into the i18n system (public/src/i18n.ts):
15
+ // the `packages.*` keys live in every shipped locale catalog, and the view
16
+ // re-renders translations on locale change via applyTranslations().
17
+
18
+ import { state } from '../state.js';
19
+ import { api } from '../api.js';
20
+ import { escHtml } from '../utils.js';
21
+ import { toast } from '../components/toast.js';
22
+ import { t, applyTranslations } from '../i18n.js';
23
+
24
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
25
+ interface PackageRow {
26
+ name: string;
27
+ npmSpec: string;
28
+ title: string;
29
+ description: string;
30
+ capabilities: string[];
31
+ requiresService?: { name: string; optional?: boolean };
32
+ requiresCredentials?: Array<{ label: string; envVars: string[]; optional?: boolean }>;
33
+ installed: boolean;
34
+ version: string | null;
35
+ active: boolean;
36
+ enabled: boolean;
37
+ runtimeActive: boolean;
38
+ activationStatus: string | null;
39
+ managed: boolean;
40
+ sourceKind: string | null;
41
+ }
42
+
43
+ let currentPackages: PackageRow[] = [];
44
+
45
+ /**
46
+ * Monotonic token for in-flight package fetches.
47
+ *
48
+ * A fetch started for one project can resolve *after* the user switches
49
+ * project or after a newer refresh, and would then paint stale cards into the
50
+ * new container — cards whose action buttons submit against the *current*
51
+ * project id. Each fetch captures the token it started with and discards its
52
+ * own response if a newer fetch has begun since.
53
+ */
54
+ let packagesFetchToken = 0;
55
+
56
+ export async function renderPackagesView(): Promise<void> {
57
+ ensureActionsWired();
58
+ const el = document.getElementById('content-packages');
59
+ if (!el) return;
60
+ if (!state.currentProject) {
61
+ el.innerHTML = `<div class="empty-state"><div class="empty-state-text">${escHtml(t('packages.noProject'))}</div></div>`;
62
+ return;
63
+ }
64
+ el.innerHTML = `
65
+ <div class="page-header">
66
+ <div>
67
+ <div class="page-title" data-i18n="packages.title">Packages</div>
68
+ <div class="page-subtitle">${escHtml(t('packages.subtitle', { project: state.currentProject.name }))}</div>
69
+ </div>
70
+ <div class="page-actions">
71
+ <button class="btn btn-secondary btn-sm" id="packages-refresh" onclick="window.__app.renderPackagesView()">${escHtml(t('packages.refresh'))}</button>
72
+ </div>
73
+ </div>
74
+ <div id="packages-content"><div class="loading-state"><div class="loading-spinner"></div></div></div>`;
75
+ await fetchAndRenderPackages();
76
+ }
77
+
78
+ async function fetchAndRenderPackages(): Promise<void> {
79
+ const pid = state.currentProject?.id;
80
+ if (!pid) return;
81
+ const target = document.getElementById('packages-content');
82
+ if (!target) return;
83
+ const token = ++packagesFetchToken;
84
+ /** True when a newer fetch started, or the project changed, while awaiting. */
85
+ const superseded = (): boolean => token !== packagesFetchToken || state.currentProject?.id !== pid;
86
+ try {
87
+ const data = await api('GET', `/projects/${pid}/extensions`);
88
+ if (superseded()) return;
89
+ const rows: PackageRow[] = (data as { packages?: PackageRow[] }).packages ?? [];
90
+ currentPackages = rows;
91
+ if (rows.length === 0) {
92
+ target.innerHTML = `<div class="empty-state"><div class="empty-state-text">${escHtml(t('packages.empty'))}</div></div>`;
93
+ return;
94
+ }
95
+ target.innerHTML = `
96
+ <div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(320px,1fr));gap:12px">
97
+ ${rows.map((row) => renderPackageCard(row)).join('')}
98
+ </div>`;
99
+ applyTranslations(target);
100
+ } catch (err: unknown) {
101
+ if (superseded()) return;
102
+ const msg = err instanceof Error ? err.message : String(err);
103
+ target.innerHTML = `<div class="empty-state"><div class="empty-state-text">${escHtml(t('packages.loadError', { error: msg }))}</div></div>`;
104
+ }
105
+ }
106
+
107
+ function renderPackageCard(row: PackageRow): string {
108
+ const statusChip = row.installed
109
+ ? `<span style="font-size:11px;color:var(--text-muted);background:var(--bg-input);padding:2px 8px;border-radius:4px">${escHtml(t('packages.installed'))}${row.version ? ' · ' + escHtml(t('packages.version', { version: row.version })) : ''}</span>`
110
+ : `<span style="font-size:11px;color:var(--text-muted);background:var(--bg-input);padding:2px 8px;border-radius:4px">${escHtml(t('packages.notInstalled'))}</span>`;
111
+
112
+ // Honest gating explanations — the UI must not promise a one-click install
113
+ // for a package that needs a Neo4j instance or an API token.
114
+ const serviceNote = row.requiresService
115
+ ? row.requiresService.optional
116
+ ? `<div class="pkg-req" style="font-size:12px;color:var(--text-secondary);margin-top:6px">⚠ ${escHtml(t('packages.requiresServiceOptional', { name: row.requiresService.name }))}</div>`
117
+ : `<div class="pkg-req" style="font-size:12px;color:var(--text-secondary);margin-top:6px">⚠ ${escHtml(t('packages.requiresService', { name: row.requiresService.name }))}</div>`
118
+ : '';
119
+ const credNotes = (row.requiresCredentials ?? []).map((c) => {
120
+ const label = c.optional ? t('packages.requiresCredentialsOptional') : t('packages.requiresCredentials');
121
+ const envs = c.envVars.map((e) => `<code style="font-family:var(--font-mono);background:var(--bg-input);padding:1px 4px;border-radius:3px">${escHtml(e)}</code>`).join(' ');
122
+ return `<div class="pkg-req" style="font-size:12px;color:var(--text-secondary);margin-top:4px">🔑 ${escHtml(label)} — ${escHtml(c.label)}<br><span style="color:var(--text-muted)">${escHtml(t('packages.envVars'))}: ${envs}</span></div>`;
123
+ }).join('');
124
+
125
+ const caps = row.capabilities.length
126
+ ? `<div style="font-size:11px;color:var(--text-muted);margin-top:6px">${escHtml(t('packages.capabilities'))}: ${row.capabilities.map((c) => escHtml(c)).join(', ')}</div>`
127
+ : '';
128
+
129
+ // Action buttons. The name is read from the row's catalog `name`, never from
130
+ // a raw DOM string — and the server validates it against the catalog again
131
+ // before any pm command is spawned.
132
+ let actions = '';
133
+ if (!row.installed) {
134
+ actions = `<button class="btn btn-primary btn-sm" style="width:100%" data-pkg-action="install" data-pkg-name="${escHtml(row.name)}">${escHtml(t('packages.install'))}</button>`;
135
+ } else if (row.active && row.enabled) {
136
+ actions = `
137
+ <div style="display:flex;gap:6px">
138
+ <button class="btn btn-secondary btn-sm" style="flex:1" data-pkg-action="deactivate" data-pkg-name="${escHtml(row.name)}">${escHtml(t('packages.deactivate'))}</button>
139
+ <button class="btn btn-ghost btn-sm" style="flex:1" data-pkg-action="uninstall" data-pkg-name="${escHtml(row.name)}">${escHtml(t('packages.uninstall'))}</button>
140
+ </div>`;
141
+ } else {
142
+ actions = `
143
+ <div style="display:flex;gap:6px">
144
+ <button class="btn btn-primary btn-sm" style="flex:1" data-pkg-action="activate" data-pkg-name="${escHtml(row.name)}">${escHtml(t('packages.activate'))}</button>
145
+ <button class="btn btn-ghost btn-sm" style="flex:1" data-pkg-action="uninstall" data-pkg-name="${escHtml(row.name)}">${escHtml(t('packages.uninstall'))}</button>
146
+ </div>`;
147
+ }
148
+
149
+ return `
150
+ <div class="card" style="cursor:default">
151
+ <div class="card-header" style="display:flex;align-items:center;justify-content:space-between;gap:8px">
152
+ <div class="card-title">${escHtml(row.title)}</div>
153
+ ${statusChip}
154
+ </div>
155
+ <div class="card-body" style="padding-top:0">
156
+ <div style="font-size:12px;color:var(--text-muted);margin-bottom:8px;line-height:1.4">${escHtml(row.description)}</div>
157
+ ${serviceNote}${credNotes}${caps}
158
+ <div style="margin-top:12px">${actions}</div>
159
+ </div>
160
+ </div>`;
161
+ }
162
+
163
+ // Delegate clicks on package action buttons so each card stays simple and the
164
+ // handler resolves the action + name from data attributes, then calls the
165
+ // server-validated extensions route.
166
+ function wirePackageActions(root: HTMLElement): void {
167
+ root.addEventListener('click', (ev: MouseEvent) => {
168
+ const btn = (ev.target as HTMLElement).closest<HTMLButtonElement>('[data-pkg-action]');
169
+ if (!btn) return;
170
+ const action = btn.dataset['pkgAction'];
171
+ const name = btn.dataset['pkgName'];
172
+ if (!action || !name) return;
173
+ void handlePackageAction(name, action, btn);
174
+ });
175
+ }
176
+
177
+ async function handlePackageAction(name: string, action: string, btn: HTMLButtonElement): Promise<void> {
178
+ const pid = state.currentProject?.id;
179
+ if (!pid) return;
180
+ const actionLabel: Record<string, string> = {
181
+ install: t('packages.install'),
182
+ activate: t('packages.activate'),
183
+ deactivate: t('packages.deactivate'),
184
+ uninstall: t('packages.uninstall'),
185
+ };
186
+ const original = btn.textContent ?? '';
187
+ btn.disabled = true;
188
+ btn.textContent = '…';
189
+ try {
190
+ if (action === 'uninstall') {
191
+ if (!window.confirm(t('packages.confirmUninstall', { name }))) {
192
+ btn.disabled = false;
193
+ btn.textContent = original;
194
+ return;
195
+ }
196
+ }
197
+ const method = action === 'uninstall' ? 'DELETE' : 'POST';
198
+ const suffix = action === 'uninstall' ? '' : `/${action}`;
199
+ await api(method, `/projects/${pid}/extensions/${encodeURIComponent(name)}${suffix}`);
200
+ toast(`${actionLabel[action] ?? action}: ${name}`, 'success');
201
+ await fetchAndRenderPackages();
202
+ } catch (err: unknown) {
203
+ const msg = err instanceof Error ? err.message : String(err);
204
+ toast(t('packages.actionFailed', { action: actionLabel[action] ?? action, error: msg }), 'error');
205
+ btn.disabled = false;
206
+ btn.textContent = original;
207
+ }
208
+ }
209
+
210
+ // Wire the delegated action handler once the view container exists.
211
+ let actionsWired = false;
212
+ function ensureActionsWired(): void {
213
+ if (actionsWired) return;
214
+ const root = document.getElementById('content-packages');
215
+ if (root) {
216
+ wirePackageActions(root);
217
+ actionsWired = true;
218
+ }
219
+ }
220
+
221
+ /**
222
+ * Called from the SSE handler in app.ts when an `extensions-changed` event
223
+ * arrives, so every collaborator on the project sees package installs /
224
+ * activates / deactivates / uninstalls live. Only re-renders when the Packages
225
+ * view is active, matching how the graph view gates its live refresh.
226
+ */
227
+ export function refreshPackagesOnSSE(evt: MessageEvent): void {
228
+ if (state.currentView !== 'packages') return;
229
+ try {
230
+ const payload = JSON.parse(evt.data) as { userId?: string; name?: string; operation?: string };
231
+ const myUserId = state.user?.id;
232
+ if (payload.userId && payload.userId !== myUserId) {
233
+ const op = payload.operation ?? 'updated';
234
+ toast(t('packages.changedByOther', { name: payload.name ?? '', operation: op }), 'info');
235
+ }
236
+ } catch { /* ignore parse errors */ }
237
+ void fetchAndRenderPackages();
238
+ }
@@ -23,6 +23,7 @@ import { renderExportView } from './export.js';
23
23
  import { renderNormalizeView } from './normalize.js';
24
24
  import { renderSharedView } from './shared.js';
25
25
  import { renderTemplatesView } from './templates.js';
26
+ import { renderPackagesView } from './packages.js';
26
27
  import { renderCommentsAuditView } from './comments-audit.js';
27
28
  import { renderConfigView } from './config.js';
28
29
  import { renderGuideView } from './guide.js';
@@ -50,6 +51,7 @@ const VIEW_TO_PATH = {
50
51
  'normalize': '/normalize',
51
52
  'shared': '/shared',
52
53
  'templates': '/templates',
54
+ 'packages': '/packages',
53
55
  'comments-audit': '/comments-audit',
54
56
  'config': '/config',
55
57
  'guide': '/guide',
@@ -171,6 +173,9 @@ export function showView(view, pushState = true) {
171
173
  case 'templates':
172
174
  renderTemplatesView();
173
175
  break;
176
+ case 'packages':
177
+ renderPackagesView();
178
+ break;
174
179
  case 'comments-audit':
175
180
  renderCommentsAuditView();
176
181
  break;
@@ -1 +1 @@
1
- {"version":3,"file":"router.js","sourceRoot":"","sources":["router.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"router.js","sourceRoot":"","sources":["router.ts"],"names":[],"mappings":"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"}
@@ -23,6 +23,7 @@ import { renderExportView } from './export.js';
23
23
  import { renderNormalizeView } from './normalize.js';
24
24
  import { renderSharedView } from './shared.js';
25
25
  import { renderTemplatesView } from './templates.js';
26
+ import { renderPackagesView } from './packages.js';
26
27
  import { renderCommentsAuditView } from './comments-audit.js';
27
28
  import { renderConfigView } from './config.js';
28
29
  import { renderGuideView } from './guide.js';
@@ -51,6 +52,7 @@ const VIEW_TO_PATH: Record<string, string> = {
51
52
  'normalize': '/normalize',
52
53
  'shared': '/shared',
53
54
  'templates': '/templates',
55
+ 'packages': '/packages',
54
56
  'comments-audit': '/comments-audit',
55
57
  'config': '/config',
56
58
  'guide': '/guide',
@@ -138,6 +140,7 @@ export function showView(view: string, pushState = true): void {
138
140
  case 'normalize': renderNormalizeView(); break;
139
141
  case 'shared': renderSharedView(); break;
140
142
  case 'templates': renderTemplatesView(); break;
143
+ case 'packages': renderPackagesView(); break;
141
144
  case 'comments-audit': renderCommentsAuditView(); break;
142
145
  case 'config': renderConfigView(); break;
143
146
  case 'guide': renderGuideView(); break;
package/public/sw.js CHANGED
@@ -60,6 +60,7 @@ const STATIC_ASSETS = [
60
60
  '/src/views/health.js',
61
61
  '/src/views/items.js',
62
62
  '/src/views/normalize.js',
63
+ '/src/views/packages.js',
63
64
  '/src/views/plan.js',
64
65
  '/src/views/plan-execution.js',
65
66
  '/src/views/projects.js',