From 3b7258ed3e71837aa1bf207cfe9d90cd09478e7f Mon Sep 17 00:00:00 2001 From: mirivlad Date: Sun, 28 Jun 2026 16:14:59 +0800 Subject: [PATCH] fix: make activity view passive --- plugins/activity/frontend/src/index.js | 85 +------------------------- scripts/smoke-activity-plugin.js | 43 ++++++++++--- 2 files changed, 36 insertions(+), 92 deletions(-) diff --git a/plugins/activity/frontend/src/index.js b/plugins/activity/frontend/src/index.js index 70781b4..3d685f1 100644 --- a/plugins/activity/frontend/src/index.js +++ b/plugins/activity/frontend/src/index.js @@ -115,76 +115,10 @@ }; } - function activityId() { - return 'activity-' + Date.now() + '-' + Math.random().toString(36).slice(2); - } - function eventPayload(event) { return event && event.payload && typeof event.payload === 'object' ? event.payload : {}; } - function firstText(values) { - for (var i = 0; i < values.length; i += 1) { - var value = text(values[i]).trim(); - if (value) return value; - } - return ''; - } - - function titleFromEvent(event, payload) { - return firstText([ - payload.title, - payload.name, - payload.path, - payload.url, - payload.captureId, - event.name, - 'Activity event' - ]); - } - - function summaryFromEvent(event, payload) { - if (payload.text) return text(payload.text).trim(); - return firstText([ - payload.summary, - payload.description, - payload.path, - payload.url, - payload.domain, - event.name - ]); - } - - function eventToActivity(event, scope) { - var payload = eventPayload(event); - var workspaceRoot = workspaceFromPayload(payload) || (scope && scope.workspaceRoot) || ''; - return { - activityId: activityId(), - type: text(event && event.name).trim() || 'activity.event', - title: titleFromEvent(event || {}, payload), - summary: summaryFromEvent(event || {}, payload), - occurredAt: text(payload.occurredAt || payload.capturedAt || (event && event.timestamp) || new Date().toISOString()), - receivedAt: new Date().toISOString(), - sourcePluginId: text((event && event.pluginId) || payload.pluginId || payload.sourcePluginId), - workspaceRootPath: workspaceRoot, - payload: payload - }; - } - - function manualActivity(scope) { - return { - activityId: activityId(), - type: 'activity.manual', - title: 'Manual activity', - summary: 'Manually recorded activity event', - occurredAt: new Date().toISOString(), - receivedAt: new Date().toISOString(), - sourcePluginId: PLUGIN_ID, - workspaceRootPath: (scope && scope.workspaceRoot) || '', - payload: {} - }; - } - function normalizeStoredEvents(value, storageKey) { if (!Array.isArray(value)) return []; return value.filter(function (item) { @@ -268,14 +202,6 @@ var titleEl = el('span', { className: 'activity-title', textContent: scope.mode === 'global' ? 'Activity' : 'Activity ยท ' + scope.label }); var countEl = el('span', { className: 'activity-count' }); var statusEl = el('span', { className: 'activity-status' }); - var manualBtn = el('button', { - className: 'activity-btn', - 'data-activity-action': 'manual', - textContent: 'Record', - onClick: function () { - addActivity(manualActivity(scope)); - } - }); var clearBtn = el('button', { className: 'activity-btn danger', 'data-activity-action': 'clear', @@ -293,7 +219,6 @@ toolbar.appendChild(countEl); toolbar.appendChild(el('span', { className: 'activity-spacer' })); toolbar.appendChild(statusEl); - toolbar.appendChild(manualBtn); toolbar.appendChild(clearBtn); var listEl = el('div', { className: 'activity-list' }); @@ -331,14 +256,6 @@ }); } - function addActivity(activity) { - activity._storageKey = scope.key; - events = sortEvents([activity].concat(events)); - statusText = 'Activity recorded'; - statusClass = ''; - return persist().then(render); - } - function renderList() { listEl.innerHTML = ''; if (events.length === 0) { @@ -406,7 +323,7 @@ return api.events.subscribe(eventName, function (event) { var eventWorkspace = workspaceFromPayload(eventPayload(event)); if (scope.mode === 'workspace' && eventWorkspace && eventWorkspace !== scope.workspaceRoot) return Promise.resolve(); - return addActivity(eventToActivity(event, scope)); + return loadStored().then(render); }).then(function (unsubscribe) { if (typeof unsubscribe === 'function') unsubscribers.push(unsubscribe); }); diff --git a/scripts/smoke-activity-plugin.js b/scripts/smoke-activity-plugin.js index f0d1f99..01f446b 100644 --- a/scripts/smoke-activity-plugin.js +++ b/scripts/smoke-activity-plugin.js @@ -157,11 +157,31 @@ async function mountWithApi(api, props = { workspaceNode: { name: 'Project' }, w (async () => { const api = makeApi(); const { component, container } = await mountWithApi(api); + const projectKey = 'events:workspace:Project'; + const clientKey = 'events:workspace:ClientA'; + const globalKey = 'events:global'; for (const name of ['file.opened', 'file.changed', 'note.saved', 'action.started', 'browser.capture.received', 'case.selected', 'browser.capture.selection']) { if (typeof api.handlers[name] !== 'function') throw new Error(`${name} subscription missing`); } + await api.settings.write(projectKey, [{ + activityId: 'capture-1', + type: 'browser.capture.selection', + title: 'Example Article', + summary: 'Selected text', + occurredAt: '2026-06-27T00:00:00Z', + sourcePluginId: 'verstak.browser-inbox', + workspaceRootPath: 'Project', + payload: { + captureId: 'capture-1', + kind: 'selection', + title: 'Example Article', + url: 'https://example.com/article', + text: 'Selected text', + workspaceRootPath: 'Project', + }, + }]); await api.handlers['browser.capture.selection']({ name: 'browser.capture.selection', pluginId: 'verstak.browser-inbox', @@ -176,9 +196,6 @@ async function mountWithApi(api, props = { workspaceNode: { name: 'Project' }, w }); await flush(); - const projectKey = 'events:workspace:Project'; - const clientKey = 'events:workspace:ClientA'; - const globalKey = 'events:global'; const stored = api.storedEvents(projectKey); if (stored.length !== 1) throw new Error(`expected one stored activity event, got ${stored.length}`); if (stored[0].type !== 'browser.capture.selection') throw new Error('stored event type mismatch'); @@ -189,6 +206,20 @@ async function mountWithApi(api, props = { workspaceNode: { name: 'Project' }, w const clientView = await mountWithApi(api, { workspaceNode: { name: 'ClientA' }, workspaceRootPath: 'ClientA' }); if (clientView.container.textContent.includes('Example Article')) throw new Error('Project activity leaked into ClientA workspace view'); + await api.settings.write(clientKey, [{ + activityId: 'client-note', + type: 'note.saved', + title: 'Client note', + summary: 'ClientA/Notes/Client.md', + occurredAt: '2026-06-27T00:10:00Z', + sourcePluginId: 'verstak.notes', + workspaceRootPath: 'ClientA', + payload: { + title: 'Client note', + path: 'ClientA/Notes/Client.md', + workspaceRootPath: 'ClientA', + }, + }]); await api.handlers['note.saved']({ name: 'note.saved', pluginId: 'verstak.notes', @@ -210,11 +241,7 @@ async function mountWithApi(api, props = { workspaceNode: { name: 'Project' }, w component.unmount && component.unmount(globalView.container); const manualButton = walk(container, (node) => node.getAttribute && node.getAttribute('data-activity-action') === 'manual'); - if (!manualButton) throw new Error('manual activity button not found'); - manualButton.click(); - await flush(); - if (api.storedEvents(projectKey).length !== 2) throw new Error('manual activity was not stored'); - if (!container.textContent.includes('Manual activity')) throw new Error('manual activity was not rendered'); + if (manualButton) throw new Error('manual activity button should not be rendered'); const clearButton = walk(container, (node) => node.getAttribute && node.getAttribute('data-activity-action') === 'clear'); if (!clearButton) throw new Error('clear activity button not found');