aimeat 1.16.2 → 1.18.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.
- package/dist/.env.example +6 -1
- package/dist/locales/en.json +166 -4
- package/dist/locales/fi.json +166 -4
- package/dist/public/components/Card.js +17 -3
- package/dist/public/components/Collapsible.js +39 -0
- package/dist/public/components/CopyButton.js +55 -24
- package/dist/public/components/DataTable.js +57 -0
- package/dist/public/components/EmptyState.js +28 -0
- package/dist/public/components/KeyValueRow.js +37 -0
- package/dist/public/components/Modal.js +22 -5
- package/dist/public/components/Pagination.js +70 -0
- package/dist/public/components/SearchBar.js +44 -0
- package/dist/public/components/StatusDot.js +29 -0
- package/dist/public/components/TagList.js +53 -0
- package/dist/public/components/ToggleSwitch.js +28 -0
- package/dist/public/components/index.js +41 -1
- package/dist/public/css/components/tags.css +24 -0
- package/dist/public/css/style-testbed.css +135 -0
- package/dist/public/css/theme.css +556 -34
- package/dist/public/css/views/admin-agent-integration.css +2 -33
- package/dist/public/css/views/admin.css +730 -686
- package/dist/public/css/views/agents-detail.css +402 -14
- package/dist/public/css/views/help.css +2 -1
- package/dist/public/css/views/hobbies.css +53 -33
- package/dist/public/css/views/marketplace.css +73 -60
- package/dist/public/css/views/openclaw.css +12 -6
- package/dist/public/css/views/portal-classic.css +34 -26
- package/dist/public/css/views/portal-dev.css +41 -32
- package/dist/public/css/views/portal.css +14 -18
- package/dist/public/css/views/profile.css +252 -164
- package/dist/public/css/views/public-knowledge-viewer.css +18 -6
- package/dist/public/css/views/scheduler.css +100 -0
- package/dist/public/js/format.js +41 -0
- package/dist/public/js/services/agent-tasks.js +14 -1
- package/dist/public/js/services/generator-spec-validate.js +5 -1
- package/dist/public/js/services/schedules.js +53 -0
- package/dist/public/js/style-testbed.js +170 -0
- package/dist/public/js/theme.js +114 -0
- package/dist/public/spa.html +74 -16
- package/dist/public/style-testbed.html +420 -0
- package/dist/public/views/admin/agent-integration-tab.js +23 -38
- package/dist/public/views/admin/agent-tasks-tab.js +14 -21
- package/dist/public/views/admin/chat-instances-tab.js +1 -1
- package/dist/public/views/admin/config-tab.js +7 -2
- package/dist/public/views/admin/cortex-tab.js +20 -14
- package/dist/public/views/admin/csm-tab.js +22 -18
- package/dist/public/views/admin/directory-tab.js +3 -3
- package/dist/public/views/admin/email-tab.js +23 -28
- package/dist/public/views/admin/federation-tab.js +15 -5
- package/dist/public/views/admin/generator-debug-tab.js +10 -8
- package/dist/public/views/admin/genesis-tab.js +4 -4
- package/dist/public/views/admin/ghii-tab.js +3 -3
- package/dist/public/views/admin/knowledge-tab.js +15 -5
- package/dist/public/views/admin/matching-tab.js +3 -3
- package/dist/public/views/admin/memory-tab.js +16 -20
- package/dist/public/views/admin/msm-tab.js +30 -17
- package/dist/public/views/admin/overview-tab.js +7 -7
- package/dist/public/views/admin/packages-tab.js +10 -9
- package/dist/public/views/admin/portal-tab.js +14 -4
- package/dist/public/views/admin/prompts-tab.js +5 -5
- package/dist/public/views/admin/push-tab.js +15 -4
- package/dist/public/views/admin/realtime-tab.js +3 -3
- package/dist/public/views/admin/services-tab.js +18 -27
- package/dist/public/views/admin/shared.js +48 -58
- package/dist/public/views/admin/sharing-groups-tab.js +5 -10
- package/dist/public/views/admin/stats-tab.js +3 -3
- package/dist/public/views/guides.js +9 -13
- package/dist/public/views/help.js +3 -24
- package/dist/public/views/hobbies.js +47 -41
- package/dist/public/views/marketplace.js +42 -34
- package/dist/public/views/openclaw.js +0 -1
- package/dist/public/views/portal-classic.js +4 -15
- package/dist/public/views/portal-dev.js +28 -30
- package/dist/public/views/portal.js +16 -21
- package/dist/public/views/portfolio.js +11 -12
- package/dist/public/views/profile/access-tab.js +250 -1
- package/dist/public/views/profile/agents/agent-card.js +75 -4
- package/dist/public/views/profile/agents/tab-activity.js +15 -13
- package/dist/public/views/profile/agents/tab-agent-config.js +60 -6
- package/dist/public/views/profile/agents/tab-integration.js +37 -60
- package/dist/public/views/profile/agents/tab-messages.js +10 -1
- package/dist/public/views/profile/agents/tab-quality.js +25 -19
- package/dist/public/views/profile/agents/tab-schedules.js +110 -0
- package/dist/public/views/profile/agents-activity-subtab.js +4 -4
- package/dist/public/views/profile/agents-services-subtab.js +5 -4
- package/dist/public/views/profile/agents-tab.js +141 -37
- package/dist/public/views/profile/agents-tasks-subtab.js +221 -26
- package/dist/public/views/profile/calibrator-batch.js +5 -11
- package/dist/public/views/profile/calibrator-tab.js +4 -9
- package/dist/public/views/profile/chat-sessions-tab.js +9 -5
- package/dist/public/views/profile/email-tab.js +2 -2
- package/dist/public/views/profile/extensions-tab.js +27 -22
- package/dist/public/views/profile/federation-tab.js +4 -1
- package/dist/public/views/profile/foundry-detail.js +22 -23
- package/dist/public/views/profile/foundry-tab.js +12 -13
- package/dist/public/views/profile/generator-dashboard/DebugPanel.js +4 -7
- package/dist/public/views/profile/generator-dashboard/use-dashboard-core.js +4 -1
- package/dist/public/views/profile/generator-dashboard/use-edit-mode.js +3 -2
- package/dist/public/views/profile/generator-detail.js +26 -30
- package/dist/public/views/profile/generator-tab.js +5 -5
- package/dist/public/views/profile/knowledge-tab.js +12 -12
- package/dist/public/views/profile/landing-page.js +100 -149
- package/dist/public/views/profile/memory-tab.js +15 -11
- package/dist/public/views/profile/node-stats-tab.js +3 -3
- package/dist/public/views/profile/nodes-tab.js +10 -3
- package/dist/public/views/profile/notifications-tab.js +3 -3
- package/dist/public/views/profile/packages-tab.js +14 -14
- package/dist/public/views/profile/scheduler-tab.js +340 -0
- package/dist/public/views/profile/services-tab.js +1 -1
- package/dist/public/views/profile/shared.js +16 -12
- package/dist/public/views/profile/wallet-tab.js +27 -50
- package/dist/public/views/profile/work-tab.js +29 -31
- package/dist/public/views/profile.js +24 -0
- package/dist/public/views/public-knowledge-viewer.js +9 -18
- package/dist/src/auth/middleware.d.ts +3 -2
- package/dist/src/auth/middleware.d.ts.map +1 -1
- package/dist/src/auth/middleware.js +78 -3
- package/dist/src/auth/middleware.js.map +1 -1
- package/dist/src/cli/init-wizard.d.ts.map +1 -1
- package/dist/src/cli/init-wizard.js +13 -1
- package/dist/src/cli/init-wizard.js.map +1 -1
- package/dist/src/config.d.ts +6 -0
- package/dist/src/config.d.ts.map +1 -1
- package/dist/src/config.js +12 -1
- package/dist/src/config.js.map +1 -1
- package/dist/src/generated/api-types.d.ts +708 -8
- package/dist/src/generated/api-types.d.ts.map +1 -1
- package/dist/src/mcp/agent-schedules.d.ts +23 -0
- package/dist/src/mcp/agent-schedules.d.ts.map +1 -0
- package/dist/src/mcp/agent-schedules.js +175 -0
- package/dist/src/mcp/agent-schedules.js.map +1 -0
- package/dist/src/mcp/annotations.d.ts.map +1 -1
- package/dist/src/mcp/annotations.js +6 -0
- package/dist/src/mcp/annotations.js.map +1 -1
- package/dist/src/mcp/catalog/definitions.d.ts.map +1 -1
- package/dist/src/mcp/catalog/definitions.js +55 -0
- package/dist/src/mcp/catalog/definitions.js.map +1 -1
- package/dist/src/mcp/catalog/scopes.d.ts.map +1 -1
- package/dist/src/mcp/catalog/scopes.js +12 -0
- package/dist/src/mcp/catalog/scopes.js.map +1 -1
- package/dist/src/mcp/catalog/surfaces.d.ts.map +1 -1
- package/dist/src/mcp/catalog/surfaces.js +2 -0
- package/dist/src/mcp/catalog/surfaces.js.map +1 -1
- package/dist/src/mcp/index.d.ts.map +1 -1
- package/dist/src/mcp/index.js +2 -0
- package/dist/src/mcp/index.js.map +1 -1
- package/dist/src/models/agent-task-schemas.d.ts +6 -0
- package/dist/src/models/agent-task-schemas.d.ts.map +1 -1
- package/dist/src/models/agent-task-schemas.js +6 -0
- package/dist/src/models/agent-task-schemas.js.map +1 -1
- package/dist/src/models/schemas.d.ts +1 -0
- package/dist/src/models/schemas.d.ts.map +1 -1
- package/dist/src/models/schemas.js +4 -0
- package/dist/src/models/schemas.js.map +1 -1
- package/dist/src/routes/access-tokens.d.ts +17 -0
- package/dist/src/routes/access-tokens.d.ts.map +1 -0
- package/dist/src/routes/access-tokens.js +164 -0
- package/dist/src/routes/access-tokens.js.map +1 -0
- package/dist/src/routes/agent-tasks.d.ts +2 -0
- package/dist/src/routes/agent-tasks.d.ts.map +1 -1
- package/dist/src/routes/agent-tasks.js +118 -23
- package/dist/src/routes/agent-tasks.js.map +1 -1
- package/dist/src/routes/agents.d.ts.map +1 -1
- package/dist/src/routes/agents.js +46 -0
- package/dist/src/routes/agents.js.map +1 -1
- package/dist/src/routes/ai.d.ts +6 -9
- package/dist/src/routes/ai.d.ts.map +1 -1
- package/dist/src/routes/ai.js +26 -175
- package/dist/src/routes/ai.js.map +1 -1
- package/dist/src/routes/apps.d.ts.map +1 -1
- package/dist/src/routes/apps.js +104 -34
- package/dist/src/routes/apps.js.map +1 -1
- package/dist/src/routes/auth.d.ts.map +1 -1
- package/dist/src/routes/auth.js +77 -4
- package/dist/src/routes/auth.js.map +1 -1
- package/dist/src/routes/cortex.d.ts +2 -1
- package/dist/src/routes/cortex.d.ts.map +1 -1
- package/dist/src/routes/cortex.js +13 -8
- package/dist/src/routes/cortex.js.map +1 -1
- package/dist/src/routes/extensions.d.ts.map +1 -1
- package/dist/src/routes/extensions.js +85 -51
- package/dist/src/routes/extensions.js.map +1 -1
- package/dist/src/routes/generator.d.ts.map +1 -1
- package/dist/src/routes/generator.js +109 -43
- package/dist/src/routes/generator.js.map +1 -1
- package/dist/src/routes/ghii.d.ts.map +1 -1
- package/dist/src/routes/ghii.js +34 -13
- package/dist/src/routes/ghii.js.map +1 -1
- package/dist/src/routes/libs.d.ts +15 -0
- package/dist/src/routes/libs.d.ts.map +1 -1
- package/dist/src/routes/libs.js +178 -55
- package/dist/src/routes/libs.js.map +1 -1
- package/dist/src/routes/portal.d.ts.map +1 -1
- package/dist/src/routes/portal.js +1 -0
- package/dist/src/routes/portal.js.map +1 -1
- package/dist/src/routes/schedules.d.ts +33 -0
- package/dist/src/routes/schedules.d.ts.map +1 -0
- package/dist/src/routes/schedules.js +380 -0
- package/dist/src/routes/schedules.js.map +1 -0
- package/dist/src/server-bootstrap/config-init.js +2 -2
- package/dist/src/server-bootstrap/config-init.js.map +1 -1
- package/dist/src/server-bootstrap/routes-loader.d.ts.map +1 -1
- package/dist/src/server-bootstrap/routes-loader.js +7 -0
- package/dist/src/server-bootstrap/routes-loader.js.map +1 -1
- package/dist/src/server-bootstrap/service-init.d.ts.map +1 -1
- package/dist/src/server-bootstrap/service-init.js +2 -1
- package/dist/src/server-bootstrap/service-init.js.map +1 -1
- package/dist/src/services/access-token.d.ts +28 -0
- package/dist/src/services/access-token.d.ts.map +1 -0
- package/dist/src/services/access-token.js +37 -0
- package/dist/src/services/access-token.js.map +1 -0
- package/dist/src/services/ai-completion.d.ts +83 -0
- package/dist/src/services/ai-completion.d.ts.map +1 -0
- package/dist/src/services/ai-completion.js +187 -0
- package/dist/src/services/ai-completion.js.map +1 -0
- package/dist/src/services/config-schema.d.ts.map +1 -1
- package/dist/src/services/config-schema.js +3 -0
- package/dist/src/services/config-schema.js.map +1 -1
- package/dist/src/services/generator-prompt-seeds.d.ts.map +1 -1
- package/dist/src/services/generator-prompt-seeds.js +6 -3
- package/dist/src/services/generator-prompt-seeds.js.map +1 -1
- package/dist/src/services/generator-prompts/spec-validate.d.ts.map +1 -1
- package/dist/src/services/generator-prompts/spec-validate.js +6 -2
- package/dist/src/services/generator-prompts/spec-validate.js.map +1 -1
- package/dist/src/services/generator-registration.d.ts +12 -4
- package/dist/src/services/generator-registration.d.ts.map +1 -1
- package/dist/src/services/generator-registration.js +71 -0
- package/dist/src/services/generator-registration.js.map +1 -1
- package/dist/src/services/generator-validate.d.ts +10 -0
- package/dist/src/services/generator-validate.d.ts.map +1 -1
- package/dist/src/services/generator-validate.js +180 -36
- package/dist/src/services/generator-validate.js.map +1 -1
- package/dist/src/services/owner-session.d.ts +43 -0
- package/dist/src/services/owner-session.d.ts.map +1 -0
- package/dist/src/services/owner-session.js +175 -0
- package/dist/src/services/owner-session.js.map +1 -0
- package/dist/src/services/schedule-constraints.d.ts +65 -0
- package/dist/src/services/schedule-constraints.d.ts.map +1 -0
- package/dist/src/services/schedule-constraints.js +106 -0
- package/dist/src/services/schedule-constraints.js.map +1 -0
- package/dist/src/services/scheduler.d.ts +34 -0
- package/dist/src/services/scheduler.d.ts.map +1 -1
- package/dist/src/services/scheduler.js +266 -22
- package/dist/src/services/scheduler.js.map +1 -1
- package/dist/src/services/skill-bundle/generator.js +19 -0
- package/dist/src/services/skill-bundle/generator.js.map +1 -1
- package/dist/src/storage/interface.d.ts +48 -4
- package/dist/src/storage/interface.d.ts.map +1 -1
- package/dist/src/storage/interface.js.map +1 -1
- package/dist/src/storage/providers/mongodb/index.d.ts +31 -0
- package/dist/src/storage/providers/mongodb/index.d.ts.map +1 -1
- package/dist/src/storage/providers/mongodb/index.js +187 -9
- package/dist/src/storage/providers/mongodb/index.js.map +1 -1
- package/dist/src/storage/providers/sqlite/index.d.ts +31 -0
- package/dist/src/storage/providers/sqlite/index.d.ts.map +1 -1
- package/dist/src/storage/providers/sqlite/index.js +131 -8
- package/dist/src/storage/providers/sqlite/index.js.map +1 -1
- package/dist/src/storage/providers/sqlite/repos/agent-task.d.ts.map +1 -1
- package/dist/src/storage/providers/sqlite/repos/agent-task.js +6 -4
- package/dist/src/storage/providers/sqlite/repos/agent-task.js.map +1 -1
- package/dist/src/storage/providers/sqlite/schema.d.ts.map +1 -1
- package/dist/src/storage/providers/sqlite/schema.js +79 -8
- package/dist/src/storage/providers/sqlite/schema.js.map +1 -1
- package/dist/src/storage/repositories/pat.repository.d.ts +40 -0
- package/dist/src/storage/repositories/pat.repository.d.ts.map +1 -0
- package/dist/src/storage/repositories/pat.repository.js +14 -0
- package/dist/src/storage/repositories/pat.repository.js.map +1 -0
- package/dist/src/storage/repositories/scheduler.repository.d.ts +2 -0
- package/dist/src/storage/repositories/scheduler.repository.d.ts.map +1 -1
- package/dist/src/storage/repositories/session.repository.d.ts +51 -0
- package/dist/src/storage/repositories/session.repository.d.ts.map +1 -1
- package/dist/src/storage/repositories/session.repository.js +12 -0
- package/dist/src/storage/repositories/session.repository.js.map +1 -1
- package/dist/src/utils/env-config.d.ts.map +1 -1
- package/dist/src/utils/env-config.js +25 -1
- package/dist/src/utils/env-config.js.map +1 -1
- package/dist/src/utils/env-validator.d.ts.map +1 -1
- package/dist/src/utils/env-validator.js +4 -0
- package/dist/src/utils/env-validator.js.map +1 -1
- package/package.json +1 -1
- package/prisma/schema.prisma +48 -0
|
@@ -24,7 +24,7 @@ import { useState, useEffect, useCallback, useRef } from 'preact/hooks';
|
|
|
24
24
|
import htm from 'htm';
|
|
25
25
|
const html = htm.bind(h);
|
|
26
26
|
import { t } from '/js/i18n.js';
|
|
27
|
-
import { escHtml } from '/js/utils.js';
|
|
27
|
+
import { escHtml, copyToClipboard } from '/js/utils.js';
|
|
28
28
|
import { apiGet, apiPost, apiDelete } from '/js/api.js';
|
|
29
29
|
import { listConsents, grantConsent, revokeConsent } from '/js/services/consent.js';
|
|
30
30
|
import { Spinner } from './shared.js';
|
|
@@ -63,9 +63,9 @@ export default function KnowledgeTab({ session, showToast, onStats }) {
|
|
|
63
63
|
const nodeUrl = window.location.origin;
|
|
64
64
|
const nodeId = session?.nodeId || '';
|
|
65
65
|
|
|
66
|
-
const loadPackages = useCallback(async () => {
|
|
66
|
+
const loadPackages = useCallback(async ({ showSpinner = true } = {}) => {
|
|
67
67
|
try {
|
|
68
|
-
setLoading(true);
|
|
68
|
+
if (showSpinner) setLoading(true);
|
|
69
69
|
const list = await knowledgeService.listMyPackages();
|
|
70
70
|
const hydrated = await Promise.all(list.map(async (pkg) => {
|
|
71
71
|
if (pkg.value) return pkg;
|
|
@@ -76,7 +76,7 @@ export default function KnowledgeTab({ session, showToast, onStats }) {
|
|
|
76
76
|
}));
|
|
77
77
|
setPackages(hydrated);
|
|
78
78
|
onStats?.({ knowledge: hydrated.length });
|
|
79
|
-
} catch { setPackages([]); }
|
|
79
|
+
} catch { if (showSpinner) setPackages([]); } // keep old list on a transient live-update refetch
|
|
80
80
|
finally { setLoading(false); }
|
|
81
81
|
}, [onStats]);
|
|
82
82
|
|
|
@@ -133,7 +133,7 @@ export default function KnowledgeTab({ session, showToast, onStats }) {
|
|
|
133
133
|
const loadRef = useRef(loadPackages);
|
|
134
134
|
loadRef.current = loadPackages;
|
|
135
135
|
useEffect(() => {
|
|
136
|
-
const handler = () => { loadRef.current(); loadFedConsents(); };
|
|
136
|
+
const handler = () => { loadRef.current({ showSpinner: false }); loadFedConsents(); }; // silent
|
|
137
137
|
window.addEventListener('aimeat-live-update', handler);
|
|
138
138
|
return () => window.removeEventListener('aimeat-live-update', handler);
|
|
139
139
|
}, []);
|
|
@@ -178,7 +178,7 @@ export default function KnowledgeTab({ session, showToast, onStats }) {
|
|
|
178
178
|
: await knowledgeService.getAgentPrompt();
|
|
179
179
|
const text = resp?.data?.prompt;
|
|
180
180
|
if (text) {
|
|
181
|
-
await
|
|
181
|
+
await copyToClipboard(text);
|
|
182
182
|
showToast(t('knowledge.actionBar.copy' + (type === 'human' ? 'HumanPrompt' : 'AgentPrompt')) + ' \u2713');
|
|
183
183
|
} else {
|
|
184
184
|
showToast('Prompt template not available yet');
|
|
@@ -276,12 +276,12 @@ export default function KnowledgeTab({ session, showToast, onStats }) {
|
|
|
276
276
|
try {
|
|
277
277
|
const resp = await knowledgeService.exportPackage(packageId);
|
|
278
278
|
const json = JSON.stringify(resp?.data || manifest, null, 2);
|
|
279
|
-
await
|
|
279
|
+
await copyToClipboard(json);
|
|
280
280
|
showToast(t('knowledge.myKnowledge.exportCopied') || 'Package JSON copied to clipboard');
|
|
281
281
|
} catch {
|
|
282
282
|
// Fallback: export the manifest we already have
|
|
283
283
|
try {
|
|
284
|
-
await
|
|
284
|
+
await copyToClipboard(JSON.stringify(manifest, null, 2));
|
|
285
285
|
showToast(t('knowledge.myKnowledge.exportCopied') || 'Package JSON copied to clipboard');
|
|
286
286
|
} catch {
|
|
287
287
|
showToast('Failed to export package');
|
|
@@ -481,7 +481,7 @@ export default function KnowledgeTab({ session, showToast, onStats }) {
|
|
|
481
481
|
<strong>${escHtml(label)}</strong>
|
|
482
482
|
${entry.key && entry.key !== label ? html`<span class="kpkg-detail-key">${escHtml(entry.key)}</span>` : null}
|
|
483
483
|
</div>
|
|
484
|
-
${loadingEntries === pkg.key && !rawData ? html`<p class="kpkg-detail-loading"
|
|
484
|
+
${loadingEntries === pkg.key && !rawData ? html`<p class="kpkg-detail-loading">${t('common.loading')}</p>` : null}
|
|
485
485
|
${val && html`<pre class="kpkg-detail-value">${val}</pre>`}
|
|
486
486
|
${renderEntryRefs(entry.references)}
|
|
487
487
|
${renderRelatedEntries(entry.related_entries, allEntries)}
|
|
@@ -616,7 +616,7 @@ export default function KnowledgeTab({ session, showToast, onStats }) {
|
|
|
616
616
|
<!-- MY KNOWLEDGE -->
|
|
617
617
|
<div class="kpkg-section">
|
|
618
618
|
<h3>${t('knowledge.myKnowledge.title')}</h3>
|
|
619
|
-
${loading && html`<${Spinner} text
|
|
619
|
+
${loading && html`<${Spinner} text=${t('common.loading')} />`}
|
|
620
620
|
${!loading && packages.length === 0 && html`
|
|
621
621
|
<p class="kpkg-empty">${t('knowledge.myKnowledge.empty')}</p>
|
|
622
622
|
`}
|
|
@@ -742,7 +742,7 @@ export default function KnowledgeTab({ session, showToast, onStats }) {
|
|
|
742
742
|
<!-- KNOWLEDGE ORGANISMS -->
|
|
743
743
|
<div class="kpkg-section">
|
|
744
744
|
<h3>${t('knowledge.organisms.title')}</h3>
|
|
745
|
-
${organismLoading && html`<${Spinner} text
|
|
745
|
+
${organismLoading && html`<${Spinner} text=${t('common.loading')} />`}
|
|
746
746
|
${!organismLoading && organismPackages.length === 0 && html`
|
|
747
747
|
<p class="kpkg-empty">${t('knowledge.organisms.empty')}</p>
|
|
748
748
|
`}
|
|
@@ -762,7 +762,7 @@ export default function KnowledgeTab({ session, showToast, onStats }) {
|
|
|
762
762
|
<!-- DISCOVER -->
|
|
763
763
|
<div class="kpkg-section">
|
|
764
764
|
<h3>${t('knowledge.discover.title')}</h3>
|
|
765
|
-
${discoverLoading && html`<${Spinner} text
|
|
765
|
+
${discoverLoading && html`<${Spinner} text=${t('common.loading')} />`}
|
|
766
766
|
${!discoverLoading && discovered.filter(p => p.sharing?.allow_clone !== false).length === 0 && html`
|
|
767
767
|
<p class="kpkg-empty">${t('knowledge.discover.empty')}</p>
|
|
768
768
|
`}
|
|
@@ -1,16 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file landing-page.js
|
|
3
|
-
* @description
|
|
4
|
-
* (
|
|
5
|
-
*
|
|
3
|
+
* @description Profile landing page. Navigation is a PERSISTENT, grouped sidebar
|
|
4
|
+
* (every tab always visible — no activity-based hiding) plus a content column
|
|
5
|
+
* showing either the selected tab or the home dashboard (ProfileCard +
|
|
6
|
+
* tier-based onboarding/app-strip). On mobile the sidebar is an off-canvas
|
|
7
|
+
* drawer. The logged-in pill + Logout live in the global shell header
|
|
8
|
+
* (spa.html), not here. Replaced the old new/active/experienced tier-adaptive
|
|
9
|
+
* menu, which was unpredictable for humans and agentic developers.
|
|
6
10
|
* @structure
|
|
7
|
-
* - computeTier() — exported heuristic
|
|
11
|
+
* - computeTier() — exported heuristic; now gates only the home onboarding content
|
|
8
12
|
* - tierLevel() — exported numeric tier comparison helper
|
|
9
|
-
* -
|
|
10
|
-
*
|
|
11
|
-
*
|
|
13
|
+
* - SIDEBAR_GROUPS — grouped, always-visible tab list
|
|
14
|
+
* - ProfileCard, HeroOnboarding, KnowledgeCallout, GhostTiles, CortexSection,
|
|
15
|
+
* AppStrip — home/section sub-components
|
|
12
16
|
* - LandingPage — main orchestrator (default export)
|
|
13
17
|
* @version-history
|
|
18
|
+
* v2.0.0 — 2026-06-03 — Replace tier-adaptive menu with a persistent grouped sidebar
|
|
19
|
+
* + content column + mobile drawer; computeTier now only gates home onboarding.
|
|
14
20
|
* v1.2.0 — 2026-03-19 — Expandable AppStrip chips with launch button; remove Generator primary style
|
|
15
21
|
* v1.1.0 — 2026-03-19 — Persist open tab to localStorage across page reloads
|
|
16
22
|
* v1.0.0 — 2026-03-18 — Initial adaptive landing page implementation
|
|
@@ -503,6 +509,50 @@ function InlineView({ tabId, label, onClose, renderTab }) {
|
|
|
503
509
|
`;
|
|
504
510
|
}
|
|
505
511
|
|
|
512
|
+
/* ───── Persistent sidebar groups (replaces the tier-adaptive menu) ─────
|
|
513
|
+
* Every tab is always present and grouped into stable sections — no activity-based
|
|
514
|
+
* hiding, so humans and agentic developers can predict where each tab lives.
|
|
515
|
+
* Group titles reuse existing i18n keys; tab labels reuse profile.tabs.* / *.tabLabel. */
|
|
516
|
+
const SIDEBAR_GROUPS = [
|
|
517
|
+
{ titleKey: 'profile.landing.menuDaily', items: [
|
|
518
|
+
{ id: 'agents', icon: '\u{1F916}', labelKey: 'profile.tabs.agents', badgeStat: 'agents' },
|
|
519
|
+
{ id: 'scheduler', icon: '⏰', labelKey: 'profile.tabs.scheduler' },
|
|
520
|
+
{ id: 'memory', icon: '\u{1F9E0}', labelKey: 'profile.tabs.memory' },
|
|
521
|
+
{ id: 'boards', icon: '\u{1F4CB}', labelKey: 'profile.tabs.boards' },
|
|
522
|
+
{ id: 'knowledge', icon: '\u{1F4DA}', labelKey: 'knowledge.tabLabel' },
|
|
523
|
+
{ id: 'notifications', icon: '\u{1F514}', labelKey: 'profile.tabs.notifications' },
|
|
524
|
+
{ id: 'apps', icon: '⚙️', labelKey: 'profile.tabs.apps' },
|
|
525
|
+
] },
|
|
526
|
+
{ titleKey: 'profile.landing.menuBuildShare', items: [
|
|
527
|
+
{ id: 'generator', icon: '\u{1F534}', labelKey: 'profile.generator.tabLabel' },
|
|
528
|
+
{ id: 'foundry', icon: '\u{1F3ED}', labelKey: 'profile.foundry.tabLabel' },
|
|
529
|
+
{ id: 'calibrator', icon: '\u{1F3AF}', labelKey: 'profile.calibrator.tabLabel' },
|
|
530
|
+
{ id: 'extensions', icon: '\u{1F50C}', labelKey: 'profile.tabs.extensions' },
|
|
531
|
+
{ id: 'capabilities', icon: '⚡', labelKey: 'capabilities.tabLabel' },
|
|
532
|
+
{ id: 'portfolio', icon: '\u{1F3A8}', labelKey: 'portfolio.tabLabel' },
|
|
533
|
+
{ id: 'packages', icon: '\u{1F4E6}', labelKey: 'profile.tabs.packages' },
|
|
534
|
+
] },
|
|
535
|
+
{ titleKey: 'profile.landing.menuTechnical', items: [
|
|
536
|
+
{ id: 'actions', icon: '\u{1F6E0}️', labelKey: 'profile.tabs.services' },
|
|
537
|
+
{ id: 'work', icon: '\u{1F4CB}', labelKey: 'profile.tabs.work' },
|
|
538
|
+
{ id: 'mcp', icon: '\u{1F517}', labelKey: 'profile.tabs.mcp' },
|
|
539
|
+
{ id: 'chatsessions', icon: '\u{1F4AC}', labelKey: 'profile.tabs.chatSessions' },
|
|
540
|
+
] },
|
|
541
|
+
{ titleKey: 'profile.landing.menuPersonal', items: [
|
|
542
|
+
{ id: 'wallet', icon: '\u{1F48E}', labelKey: 'profile.tabs.wallet' },
|
|
543
|
+
{ id: 'email', icon: '\u{1F4E7}', labelKey: 'profile.tabs.email' },
|
|
544
|
+
{ id: 'access', icon: '\u{1F510}', labelKey: 'profile.tabs.access' },
|
|
545
|
+
{ id: 'organisms', icon: '\u{1F3E2}', labelKey: 'profile.tabs.organisms' },
|
|
546
|
+
{ id: 'dataWallet', icon: '\u{1F512}', labelKey: 'profile.tabs.dataWallet' },
|
|
547
|
+
] },
|
|
548
|
+
{ titleKey: 'profile.landing.menuInfra', items: [
|
|
549
|
+
{ id: 'federation', icon: '\u{1F310}', labelKey: 'profile.tabs.federation' },
|
|
550
|
+
{ id: 'nodes', icon: '\u{1F5A5}️', labelKey: 'profile.tabs.nodes' },
|
|
551
|
+
{ id: 'nodeStats', icon: '\u{1F4CA}', labelKey: 'profile.tabs.nodeStats' },
|
|
552
|
+
{ id: 'security', icon: '\u{1F6E1}️', labelKey: 'profile.tabs.security' },
|
|
553
|
+
] },
|
|
554
|
+
];
|
|
555
|
+
|
|
506
556
|
/* ───── Main landing page ───── */
|
|
507
557
|
|
|
508
558
|
export default function LandingPage({ tier, stats, session, navigate, showToast, locale, renderTab, getTabLabel }) {
|
|
@@ -520,6 +570,7 @@ export default function LandingPage({ tier, stats, session, navigate, showToast,
|
|
|
520
570
|
return null;
|
|
521
571
|
});
|
|
522
572
|
const [expanded, setExpanded] = useState(false);
|
|
573
|
+
const [drawerOpen, setDrawerOpen] = useState(false);
|
|
523
574
|
|
|
524
575
|
const owner = session.owner;
|
|
525
576
|
|
|
@@ -578,11 +629,7 @@ export default function LandingPage({ tier, stats, session, navigate, showToast,
|
|
|
578
629
|
const isExperienced = tier === 'experienced';
|
|
579
630
|
|
|
580
631
|
return html`
|
|
581
|
-
<div class="pf-
|
|
582
|
-
|
|
583
|
-
<${ProfileCard} tier=${tier} stats=${stats} session=${session}
|
|
584
|
-
onEditProfile=${() => setEditOpen(true)}
|
|
585
|
-
onChangePassword=${() => setPwOpen(true)} />
|
|
632
|
+
<div class="pf-shell${drawerOpen ? ' pf-shell--open' : ''}">
|
|
586
633
|
|
|
587
634
|
${editOpen && html`<${EditProfileModal}
|
|
588
635
|
session=${session}
|
|
@@ -595,150 +642,54 @@ export default function LandingPage({ tier, stats, session, navigate, showToast,
|
|
|
595
642
|
onChanged=${() => { setPwOpen(false); showToast?.(t('profile.landing.passwordChanged')); }}
|
|
596
643
|
/>`}
|
|
597
644
|
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
${viewAt('hero')}
|
|
601
|
-
|
|
602
|
-
<${KnowledgeCallout} switchTab=${() => open('knowledge', 'knowledge-new')} />
|
|
603
|
-
${viewAt('knowledge-new')}
|
|
645
|
+
<button class="pf-mnav-toggle" onClick=${() => setDrawerOpen(o => !o)}>☰ ${t('profile.landing.menu')}</button>
|
|
646
|
+
<div class="pf-scrim" onClick=${() => setDrawerOpen(false)}></div>
|
|
604
647
|
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
<${MenuSection} title=${t('profile.landing.menuManagement')}>
|
|
612
|
-
<div class="pf-menu-grid">
|
|
613
|
-
<${MenuItem} icon="\u{1F9E0}" label=${t('profile.tabs.memory')} active=${isOpen('memory')} onClick=${() => open('memory', 'manage-new')} />
|
|
614
|
-
<${MenuItem} icon="\u{1F48E}" label=${t('profile.tabs.wallet')} active=${isOpen('wallet')} onClick=${() => open('wallet', 'manage-new')} />
|
|
615
|
-
<${MenuItem} icon="\u{1F510}" label=${t('profile.tabs.access')} active=${isOpen('access')} onClick=${() => open('access', 'manage-new')} />
|
|
616
|
-
<${MenuItem} icon="\u{1F4E7}" label=${t('profile.tabs.email')} active=${isOpen('email')} onClick=${() => open('email', 'manage-new')} />
|
|
617
|
-
</div>
|
|
618
|
-
<div class="pf-expand-trigger" onClick=${() => setExpanded(!expanded)}>
|
|
619
|
-
${expanded ? '\u25BE' : '\u25B8'} ${t('profile.landing.expandAll')}
|
|
620
|
-
</div>
|
|
621
|
-
${expanded && html`
|
|
622
|
-
<div class="pf-menu-grid pf-menu-grid-expanded">
|
|
623
|
-
<${MenuItem} icon="\u{1F916}" label=${t('profile.tabs.agents')} active=${isOpen('agents')} onClick=${() => open('agents', 'manage-new')} />
|
|
624
|
-
<${MenuItem} icon="\u{1F4AC}" label=${t('profile.tabs.chatSessions')} active=${isOpen('chatsessions')} onClick=${() => open('chatsessions', 'manage-new')} />
|
|
625
|
-
<${MenuItem} icon="\u{1F50C}" label=${t('profile.tabs.extensions')} active=${isOpen('extensions')} onClick=${() => open('extensions', 'manage-new')} />
|
|
626
|
-
<${MenuItem} icon="\u{1F534}" label=${t('profile.generator.tabLabel')} active=${isOpen('generator')} onClick=${() => open('generator', 'manage-new')} />
|
|
627
|
-
<${MenuItem} icon="\u{1F3ED}" label=${t('profile.foundry.tabLabel')} active=${isOpen('foundry')} onClick=${() => open('foundry', 'manage-new')} />
|
|
628
|
-
<${MenuItem} icon="\u{1F3AF}" label=${t('profile.calibrator.tabLabel')} active=${isOpen('calibrator')} onClick=${() => open('calibrator', 'manage-new')} />
|
|
629
|
-
<${MenuItem} icon="\u{1F4E6}" label=${t('profile.tabs.packages')} active=${isOpen('packages')} onClick=${() => open('packages', 'manage-new')} />
|
|
630
|
-
<${MenuItem} icon="\u{1F4DA}" label=${t('knowledge.tabLabel')} active=${isOpen('knowledge')} onClick=${() => open('knowledge', 'manage-new')} />
|
|
631
|
-
<${MenuItem} icon="\u{1F4CB}" label=${t('profile.tabs.boards')} active=${isOpen('boards')} onClick=${() => open('boards', 'manage-new')} />
|
|
632
|
-
<${MenuItem} icon="\u{1F3A8}" label=${t('portfolio.tabLabel')} active=${isOpen('portfolio')} onClick=${() => open('portfolio', 'manage-new')} />
|
|
633
|
-
<${MenuItem} icon="\u{1F6E0}\uFE0F" label=${t('profile.tabs.services')} active=${isOpen('actions')} onClick=${() => open('actions', 'manage-new')} />
|
|
634
|
-
<${MenuItem} icon="\u{1F4CB}" label=${t('profile.tabs.work')} active=${isOpen('work')} onClick=${() => open('work', 'manage-new')} />
|
|
635
|
-
<${MenuItem} icon="\u{1F3E2}" label=${t('profile.tabs.organisms')} active=${isOpen('organisms')} onClick=${() => open('organisms', 'manage-new')} />
|
|
636
|
-
<${MenuItem} icon="\u{1F512}" label=${t('profile.tabs.dataWallet')} active=${isOpen('dataWallet')} onClick=${() => open('dataWallet', 'manage-new')} />
|
|
637
|
-
<${MenuItem} icon="\u{1F514}" label=${t('profile.tabs.notifications')} active=${isOpen('notifications')} onClick=${() => open('notifications', 'manage-new')} />
|
|
638
|
-
<${MenuItem} icon="\u{1F512}" label=${t('profile.tabs.security')} active=${isOpen('security')} onClick=${() => open('security', 'manage-new')} />
|
|
639
|
-
<${MenuItem} icon="⚡" label=${t('capabilities.tabLabel')} active=${isOpen('capabilities')} onClick=${() => open('capabilities', 'manage-new')} />
|
|
640
|
-
</div>
|
|
641
|
-
`}
|
|
642
|
-
<//>
|
|
643
|
-
${viewAt('manage-new')}
|
|
644
|
-
`}
|
|
648
|
+
<aside class="pf-sidebar">
|
|
649
|
+
<div class="pf-side-identity">
|
|
650
|
+
<div class="pf-side-avatar"></div>
|
|
651
|
+
<div class="pf-side-id-name">${session.displayName || owner}</div>
|
|
652
|
+
</div>
|
|
645
653
|
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
654
|
+
<button class="pf-side-item${!openView ? ' pf-side-item--active' : ''}"
|
|
655
|
+
onClick=${() => { close(); setDrawerOpen(false); }}>
|
|
656
|
+
<span class="pf-side-ico">\u{1F3E0}</span><span class="pf-side-label">${t('profile.landing.home')}</span>
|
|
657
|
+
</button>
|
|
658
|
+
|
|
659
|
+
${SIDEBAR_GROUPS.map(g => html`
|
|
660
|
+
<div class="pf-side-group">
|
|
661
|
+
<div class="pf-side-group-title">${t(g.titleKey)}</div>
|
|
662
|
+
${g.items.map(it => html`
|
|
663
|
+
<button class="pf-side-item${isOpen(it.id) ? ' pf-side-item--active' : ''}"
|
|
664
|
+
onClick=${() => { open(it.id, 'main'); setDrawerOpen(false); }}>
|
|
665
|
+
<span class="pf-side-ico">${it.icon}</span>
|
|
666
|
+
<span class="pf-side-label">${t(it.labelKey)}</span>
|
|
667
|
+
${it.badgeStat && typeof stats?.[it.badgeStat] === 'number' && stats[it.badgeStat] > 0
|
|
668
|
+
? html`<span class="pf-side-badge">${stats[it.badgeStat]}</span>` : null}
|
|
669
|
+
</button>
|
|
670
|
+
`)}
|
|
660
671
|
</div>
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
${isActive && html`
|
|
665
|
-
<${KnowledgeButton} switchTab=${() => open('knowledge', 'knowledge-btn')} />
|
|
666
|
-
${viewAt('knowledge-btn')}
|
|
667
|
-
`}
|
|
672
|
+
`)}
|
|
673
|
+
</aside>
|
|
668
674
|
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
<${MenuItem} icon="\u{1F50C}" label=${t('profile.tabs.extensions')} active=${isOpen('extensions')} onClick=${() => open('extensions', 'build')} />
|
|
675
|
-
<${MenuItem} icon="⚡" label=${t('capabilities.tabLabel')} active=${isOpen('capabilities')} onClick=${() => open('capabilities', 'build')} />
|
|
676
|
-
<${MenuItem} icon="\u{1F3A8}" label=${t('portfolio.tabLabel')} active=${isOpen('portfolio')} onClick=${() => open('portfolio', 'build')} />
|
|
677
|
-
${isExperienced && html`
|
|
678
|
-
<${MenuItem} icon="\u{1F4E4}" label=${t('profile.landing.ownPackages')} active=${isOpen('packages')} onClick=${() => open('packages', 'build')} />
|
|
679
|
-
`}
|
|
675
|
+
<main class="pf-content">
|
|
676
|
+
${openView ? html`
|
|
677
|
+
<div class="pf-content-head">
|
|
678
|
+
<button class="pf-back-btn" onClick=${close}>← ${t('profile.landing.home')}</button>
|
|
679
|
+
<span class="pf-back-current">${getTabLabel(openView.tabId)}</span>
|
|
680
680
|
</div>
|
|
681
|
-
|
|
682
|
-
${viewAt('build')}
|
|
683
|
-
|
|
684
|
-
${isExperienced ? html`
|
|
685
|
-
<${MenuSection} title=${t('profile.landing.menuManagement')}>
|
|
686
|
-
<div class="pf-menu-subgroup">
|
|
687
|
-
<div class="pf-menu-subgroup-title">${t('profile.landing.menuTechnical')}</div>
|
|
688
|
-
<div class="pf-menu-grid">
|
|
689
|
-
<${MenuItem} icon="\u2699\uFE0F" label=${t('profile.tabs.apps')} active=${isOpen('apps')} onClick=${() => open('apps', 'manage')} />
|
|
690
|
-
<${MenuItem} icon="\u{1F517}" label=${t('profile.tabs.mcp')} active=${isOpen('mcp')} onClick=${() => open('mcp', 'manage')} />
|
|
691
|
-
<${MenuItem} icon="\u{1F6E0}\uFE0F" label=${t('profile.tabs.services')} active=${isOpen('actions')} onClick=${() => open('actions', 'manage')} />
|
|
692
|
-
<${MenuItem} icon="\u{1F4CB}" label=${t('profile.tabs.work')} active=${isOpen('work')} onClick=${() => open('work', 'manage')} />
|
|
693
|
-
<${MenuItem} icon="\u{1F4AC}" label=${t('profile.tabs.chatSessions')} active=${isOpen('chatsessions')} onClick=${() => open('chatsessions', 'manage')} />
|
|
694
|
-
</div>
|
|
695
|
-
</div>
|
|
696
|
-
<div class="pf-menu-subgroup">
|
|
697
|
-
<div class="pf-menu-subgroup-title">${t('profile.landing.menuPersonal')}</div>
|
|
698
|
-
<div class="pf-menu-grid">
|
|
699
|
-
<${MenuItem} icon="\u{1F48E}" label=${t('profile.tabs.wallet')} active=${isOpen('wallet')} onClick=${() => open('wallet', 'manage')} />
|
|
700
|
-
<${MenuItem} icon="\u{1F4E7}" label=${t('profile.tabs.email')} active=${isOpen('email')} onClick=${() => open('email', 'manage')} />
|
|
701
|
-
<${MenuItem} icon="\u{1F510}" label=${t('profile.tabs.access')} active=${isOpen('access')} onClick=${() => open('access', 'manage')} />
|
|
702
|
-
<${MenuItem} icon="\u{1F3E2}" label=${t('profile.tabs.organisms')} active=${isOpen('organisms')} onClick=${() => open('organisms', 'manage')} />
|
|
703
|
-
</div>
|
|
704
|
-
</div>
|
|
705
|
-
<//>
|
|
706
|
-
${viewAt('manage')}
|
|
707
|
-
|
|
708
|
-
<${MenuSection} title=${t('profile.landing.menuInfra')} annotation=${t('profile.landing.menuInfraAnnotation')}>
|
|
709
|
-
<div class="pf-menu-grid">
|
|
710
|
-
<${MenuItem} icon="\u{1F310}" label=${t('profile.tabs.federation')} indigo active=${isOpen('federation')} onClick=${() => open('federation', 'infra')} />
|
|
711
|
-
<${MenuItem} icon="\u{1F5A5}\uFE0F" label=${t('profile.tabs.nodes')} active=${isOpen('nodes')} onClick=${() => open('nodes', 'infra')} />
|
|
712
|
-
<${MenuItem} icon="\u{1F4CA}" label=${t('profile.tabs.nodeStats')} active=${isOpen('nodeStats')} onClick=${() => open('nodeStats', 'infra')} />
|
|
713
|
-
<${MenuItem} icon="\u{1F512}" label=${t('profile.tabs.security')} active=${isOpen('security')} onClick=${() => open('security', 'infra')} />
|
|
714
|
-
</div>
|
|
715
|
-
<//>
|
|
716
|
-
${viewAt('infra')}
|
|
681
|
+
<div class="pf-content-body">${renderTab(openView.tabId)}</div>
|
|
717
682
|
` : html`
|
|
718
|
-
<${
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
<div class="pf-expand-trigger" onClick=${() => setExpanded(!expanded)}>
|
|
727
|
-
${expanded ? '\u25BE' : '\u25B8'} ${t('profile.landing.expandMore')}
|
|
728
|
-
</div>
|
|
729
|
-
${expanded && html`
|
|
730
|
-
<div class="pf-menu-grid pf-menu-grid-expanded">
|
|
731
|
-
<${MenuItem} icon="\u{1F6E0}\uFE0F" label=${t('profile.tabs.services')} active=${isOpen('actions')} onClick=${() => open('actions', 'manage')} />
|
|
732
|
-
<${MenuItem} icon="\u{1F4CB}" label=${t('profile.tabs.work')} active=${isOpen('work')} onClick=${() => open('work', 'manage')} />
|
|
733
|
-
<${MenuItem} icon="\u{1F4AC}" label=${t('profile.tabs.chatSessions')} active=${isOpen('chatsessions')} onClick=${() => open('chatsessions', 'manage')} />
|
|
734
|
-
<${MenuItem} icon="\u{1F512}" label=${t('profile.tabs.dataWallet')} active=${isOpen('dataWallet')} onClick=${() => open('dataWallet', 'manage')} />
|
|
735
|
-
<${MenuItem} icon="\u{1F3E2}" label=${t('profile.tabs.organisms')} active=${isOpen('organisms')} onClick=${() => open('organisms', 'manage')} />
|
|
736
|
-
</div>
|
|
737
|
-
`}
|
|
738
|
-
<//>
|
|
739
|
-
${viewAt('manage')}
|
|
683
|
+
<${ProfileCard} tier=${tier} stats=${stats} session=${session}
|
|
684
|
+
onEditProfile=${() => setEditOpen(true)}
|
|
685
|
+
onChangePassword=${() => setPwOpen(true)} />
|
|
686
|
+
${isNew ? html`<${HeroOnboarding} switchTab=${(id) => open(id, 'main')} />` : null}
|
|
687
|
+
${(isNew || isActive) ? html`<${KnowledgeCallout} switchTab=${() => open('knowledge', 'main')} />` : null}
|
|
688
|
+
${isNew ? html`<${GhostTiles} switchTab=${() => open('packages', 'main')} />` : null}
|
|
689
|
+
<${CortexSection} switchTab=${() => open('extensions', 'main')} />
|
|
690
|
+
<${AppStrip} apps=${apps} switchTab=${(id) => open(id, 'main')} />
|
|
740
691
|
`}
|
|
741
|
-
|
|
692
|
+
</main>
|
|
742
693
|
</div>
|
|
743
694
|
`;
|
|
744
695
|
}
|
|
@@ -7,6 +7,10 @@
|
|
|
7
7
|
* v1.1.0 — 2026-03-18 — Fix: use AuthImage for thumbnails and authenticated download to avoid 401
|
|
8
8
|
* v1.2.0 — 2026-05-22 — Add Browse Home / Browse Remote panels for federation memory sync
|
|
9
9
|
* v1.3.0 — 2026-05-22 — Add timestamps, sort controls, fix group picker rotation bug
|
|
10
|
+
* v1.4.0 — 2026-06-02 — Component unification (#2): edit modal uses the canonical
|
|
11
|
+
* <Modal> component (Escape/backdrop close + header ✕).
|
|
12
|
+
* v1.5.0 — 2026-06-02 — Component unification (#1): "Copy URLs" button uses canonical
|
|
13
|
+
* <CopyButton> (toast preserved via onCopied).
|
|
10
14
|
*/
|
|
11
15
|
import { h } from 'preact';
|
|
12
16
|
import { useState, useEffect, useRef } from 'preact/hooks';
|
|
@@ -24,7 +28,8 @@ import { getNodeUrl } from '/js/services/auth.js';
|
|
|
24
28
|
import { listGroups } from '/js/services/sharing-groups.js';
|
|
25
29
|
import TagCloud from '/js/components/tag-cloud.js';
|
|
26
30
|
import TagEditor from '/js/components/tag-editor.js';
|
|
27
|
-
import { useConfirm } from '/components/Modal.js';
|
|
31
|
+
import { Modal, useConfirm } from '/components/Modal.js';
|
|
32
|
+
import { CopyButton } from '/components/CopyButton.js';
|
|
28
33
|
|
|
29
34
|
export default function MemoryTab({ session, showToast, onStats }) {
|
|
30
35
|
const { confirm, ConfirmUI } = useConfirm();
|
|
@@ -490,15 +495,17 @@ export default function MemoryTab({ session, showToast, onStats }) {
|
|
|
490
495
|
});
|
|
491
496
|
};
|
|
492
497
|
|
|
493
|
-
const
|
|
494
|
-
const urls = filtered.map(f => `${NODE_URL}/v1/memory/files/${encodeURIComponent(f.key || f.name)}`).join('\n');
|
|
495
|
-
navigator.clipboard.writeText(urls).then(() => showToast(t('profile.files.urlsCopied') || `${filtered.length} URLs copied`));
|
|
496
|
-
};
|
|
498
|
+
const fileUrls = filtered.map(f => `${NODE_URL}/v1/memory/files/${encodeURIComponent(f.key || f.name)}`).join('\n');
|
|
497
499
|
|
|
498
500
|
return html`
|
|
499
501
|
<div class="action-bar">
|
|
500
502
|
<button class="btn-primary" onClick=${() => setShowFileForm(!showFileForm)}>${t('profile.files.uploadBtn')}</button>
|
|
501
|
-
${filtered.length > 0 && html
|
|
503
|
+
${filtered.length > 0 && html`<${CopyButton}
|
|
504
|
+
text=${fileUrls}
|
|
505
|
+
label=${`\u{1F4CB} ${t('profile.files.copyUrls') || 'Copy URLs'} (${filtered.length})`}
|
|
506
|
+
title="Copy file URLs"
|
|
507
|
+
className="btn-outline btn-sm"
|
|
508
|
+
onCopied=${() => showToast(t('profile.files.urlsCopied') || `${filtered.length} URLs copied`)} />`}
|
|
502
509
|
<span class="text-meta-sm">${t('profile.files.sizeLimit')}</span>
|
|
503
510
|
</div>
|
|
504
511
|
<${TagCloud} tags=${[...allTags]} selected=${fileTagFilter} onToggle=${toggleTag} onClear=${() => setFileTagFilter(new Set())} />
|
|
@@ -1081,9 +1088,7 @@ function EditMemoryModal({ memKey, initialValue, initialVisibility, initialVersi
|
|
|
1081
1088
|
}
|
|
1082
1089
|
};
|
|
1083
1090
|
return html`
|
|
1084
|
-
|
|
1085
|
-
<div class="modal">
|
|
1086
|
-
<h3>${t('profile.memory.editTitle')}: ${escHtml(memKey)}</h3>
|
|
1091
|
+
<${Modal} open=${true} onClose=${onCancel} title=${`${t('profile.memory.editTitle')}: ${memKey}`}>
|
|
1087
1092
|
<div class="form-row flex-row mb-half">
|
|
1088
1093
|
<label class="pf-label-inline">${t('profile.memory.visLabel')}</label>
|
|
1089
1094
|
<button class="kpkg-vis-pill"
|
|
@@ -1111,6 +1116,5 @@ function EditMemoryModal({ memKey, initialValue, initialVisibility, initialVersi
|
|
|
1111
1116
|
<button class="btn-primary" onClick=${() => onSave(value, vis, initialVersion, vis === 'group' ? groupId : undefined)}>${t('profile.save')}</button>
|
|
1112
1117
|
<button class="btn-outline" onClick=${onCancel}>${t('profile.cancel')}</button>
|
|
1113
1118
|
</div>
|
|
1114
|
-
|
|
1115
|
-
</div>`;
|
|
1119
|
+
<//>`;
|
|
1116
1120
|
}
|
|
@@ -30,9 +30,9 @@ function fmtBytes(b) {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
function StatCard({ label, value, color }) {
|
|
33
|
-
return html`<div class="
|
|
34
|
-
<div class="stat-value" style=${`color:${color}`}>${value}</div>
|
|
35
|
-
<div class="stat-label">${label}</div>
|
|
33
|
+
return html`<div class="stat-card">
|
|
34
|
+
<div class="stat-card-value" style=${`color:${color}`}>${value}</div>
|
|
35
|
+
<div class="stat-card-label">${label}</div>
|
|
36
36
|
</div>`;
|
|
37
37
|
}
|
|
38
38
|
|
|
@@ -5,14 +5,21 @@
|
|
|
5
5
|
* @version-history
|
|
6
6
|
* v1.0.0 — 2026-03-16 — Initial nodes tab
|
|
7
7
|
* v1.1.0 — 2026-03-17 — Replace inline styles with CSS classes
|
|
8
|
+
* v1.2.0 — 2026-06-02 — Component unification (#1): tunnel-URL copy button uses
|
|
9
|
+
* canonical <CopyButton> (toast preserved via onCopied).
|
|
10
|
+
* v1.3.0 — 2026-06-02 — Component unification (#11): node status dot uses
|
|
11
|
+
* canonical <StatusDot> (online/offline/degraded/detached) instead of the
|
|
12
|
+
* bespoke 10px .pn-status-dot (now 8px, with title tooltip added).
|
|
8
13
|
*/
|
|
9
14
|
import { h } from 'preact';
|
|
10
15
|
import { useState, useEffect, useRef } from 'preact/hooks';
|
|
11
16
|
import htm from 'htm';
|
|
12
17
|
const html = htm.bind(h);
|
|
13
18
|
import { t } from '/js/i18n.js';
|
|
14
|
-
import { escHtml, timeAgo
|
|
19
|
+
import { escHtml, timeAgo } from '/js/utils.js';
|
|
15
20
|
import { Spinner } from './shared.js';
|
|
21
|
+
import { CopyButton } from '/components/CopyButton.js';
|
|
22
|
+
import { StatusDot } from '/components/StatusDot.js';
|
|
16
23
|
import { useConfirm } from '/components/Modal.js';
|
|
17
24
|
import * as nodesService from '/js/services/nodes.js';
|
|
18
25
|
import { getNodeUrl } from '/js/services/auth.js';
|
|
@@ -99,7 +106,7 @@ export default function NodesTab({ session, showToast, onStats }) {
|
|
|
99
106
|
setExpandedNodes(s);
|
|
100
107
|
}}>
|
|
101
108
|
<div class="pn-header-left">
|
|
102
|
-
|
|
109
|
+
<${StatusDot} status=${statusClass} title=${statusLabel} />
|
|
103
110
|
<span class="pn-name">${escHtml(node.node_id)}</span>
|
|
104
111
|
</div>
|
|
105
112
|
<div class="pn-badges">
|
|
@@ -117,7 +124,7 @@ export default function NodesTab({ session, showToast, onStats }) {
|
|
|
117
124
|
<span class="pn-detail-label">${t('profile.nodes.tunnelUrl')}</span>
|
|
118
125
|
<span class="pn-detail-value flex-row">
|
|
119
126
|
<code class="text-meta-sm">${tunnelUrl}</code>
|
|
120
|
-
|
|
127
|
+
<${CopyButton} text=${tunnelUrl} label=${t('profile.nodes.copyUrl')} className="pn-copy-btn" onCopied=${() => showToast(t('profile.nodes.copied'))} />
|
|
121
128
|
</span>
|
|
122
129
|
</div>
|
|
123
130
|
<div class="pn-padding-half">
|
|
@@ -27,13 +27,13 @@ export default function NotificationsTab({ session, showToast }) {
|
|
|
27
27
|
|
|
28
28
|
// Re-check email verification when other tabs update data (e.g. email confirmed)
|
|
29
29
|
useEffect(() => {
|
|
30
|
-
const handler = () => { if (session) checkSubscription(); };
|
|
30
|
+
const handler = () => { if (session) checkSubscription({ showSpinner: false }); }; // silent
|
|
31
31
|
window.addEventListener('aimeat-live-update', handler);
|
|
32
32
|
return () => window.removeEventListener('aimeat-live-update', handler);
|
|
33
33
|
}, [session]);
|
|
34
34
|
|
|
35
|
-
async function checkSubscription() {
|
|
36
|
-
setLoading(true);
|
|
35
|
+
async function checkSubscription({ showSpinner = true } = {}) {
|
|
36
|
+
if (showSpinner) setLoading(true);
|
|
37
37
|
try {
|
|
38
38
|
// Get VAPID key
|
|
39
39
|
const vapidRes = await apiGet('/v1/push/vapid-key');
|