@nextclaw/ui 0.13.9 → 0.13.10-beta.1
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/CHANGELOG.md +32 -0
- package/dist/assets/{api-CIJxdHmy.js → api-DhI2lb1f.js} +10 -5
- package/dist/assets/app-presenter-provider-BFbrQp8q.js +3 -0
- package/dist/assets/arrow-left-CI0Ocu9p.js +1 -0
- package/dist/assets/{channels-list-page-C_Xe0CNX.js → channels-list-page-B6CvmU9T.js} +1 -1
- package/dist/assets/{chat-page-CXRtoQR2.js → chat-page-Ch4ShlKB.js} +1 -1
- package/dist/assets/{config-split-page-DBAcw9mJ.js → config-split-page-bO0K6uQv.js} +1 -1
- package/dist/assets/{confirm-dialog-DwPTxq8C.js → confirm-dialog-DXRWJ5uB.js} +1 -1
- package/dist/assets/{desktop-update-config-BqABa_1C.js → desktop-update-config-DPk5V1Nl.js} +1 -1
- package/dist/assets/{dist-BfcibKyv.js → dist-DQoV-62W.js} +1 -1
- package/dist/assets/{dist-WjhKB-pc.js → dist-T6rf86Nf.js} +1 -1
- package/dist/assets/{doc-browser-8EEDwGCJ.js → doc-browser-CTFB6ACN.js} +1 -1
- package/dist/assets/{doc-browser-context-DLJOy6Am.js → doc-browser-context-CP2tI-Br.js} +1 -1
- package/dist/assets/doc-browser-yi02ASOL.js +1 -0
- package/dist/assets/{ellipsis-H-4aNwgt.js → ellipsis-B7CbNPNr.js} +1 -1
- package/dist/assets/{es2015-B5k1IpKX.js → es2015-BSPOGpH4.js} +1 -1
- package/dist/assets/{external-link-BN1wd-eI.js → external-link-CefT35zP.js} +1 -1
- package/dist/assets/index-CevK3jug.css +1 -0
- package/dist/assets/{index-WJt0X9wC.js → index-DZoXsgdz.js} +43 -43
- package/dist/assets/{key-round-D-7IaAQS.js → key-round-BpM3GZn4.js} +1 -1
- package/dist/assets/{loader-circle-CB38Q7Ws.js → loader-circle-_edjOFsw.js} +1 -1
- package/dist/assets/mcp-marketplace-page-9maf_9fL.js +1 -0
- package/dist/assets/{mcp-marketplace-page-ju1KH3TG.js → mcp-marketplace-page-WAgpy0hp.js} +1 -1
- package/dist/assets/{model-config-CgS6dp65.js → model-config-CixioI5U.js} +1 -1
- package/dist/assets/{notice-card-DW9BLKpG.js → notice-card-BLklZuEa.js} +1 -1
- package/dist/assets/play-DD0bg50i.js +1 -0
- package/dist/assets/plus-zZ2GC_AJ.js +1 -0
- package/dist/assets/{popover-ofN845gZ.js → popover-D_pJfOlM.js} +1 -1
- package/dist/assets/{provider-scoped-model-input-DaDqi8Zy.js → provider-scoped-model-input-BbWqk2yz.js} +1 -1
- package/dist/assets/{providers-list-CZNQXY4n.js → providers-list-C_JOSjYd.js} +1 -1
- package/dist/assets/{react-Bq34NL59.js → react-Bl8iJUcF.js} +1 -1
- package/dist/assets/{refresh-cw-DJttSXS8.js → refresh-cw-CqfS1EhK.js} +1 -1
- package/dist/assets/remote-qtmzkte2.js +1 -0
- package/dist/assets/rotate-cw-C7EvaSlb.js +1 -0
- package/dist/assets/{runtime-config-page-gUjM6Z_A.js → runtime-config-page-ByvKO6Yn.js} +1 -1
- package/dist/assets/{save-DtAFbS7x.js → save-CQERCODg.js} +1 -1
- package/dist/assets/search-C0b2yzmt.js +1 -0
- package/dist/assets/{search-config-C04PrmHj.js → search-config-Cl2_NgFY.js} +1 -1
- package/dist/assets/{secrets-config-DvxHdz9h.js → secrets-config-BkR72J4g.js} +1 -1
- package/dist/assets/{status-dot-D4jbKDLB.js → status-dot-DY0xUUvK.js} +1 -1
- package/dist/assets/{tabs-Ca2vw7YQ.js → tabs-C77i1w90.js} +1 -1
- package/dist/assets/{tabs-custom-DzGDjYxf.js → tabs-custom-CFpR54-m.js} +1 -1
- package/dist/assets/{tag-chip-CW-_pHjH.js → tag-chip-Kib_ljle.js} +1 -1
- package/dist/assets/{tooltip-Cq2mERPk.js → tooltip-fs7VQG7d.js} +1 -1
- package/dist/assets/{trash-2-rumaEu9l.js → trash-2-Bb8mTTLl.js} +1 -1
- package/dist/assets/x-BV4iiea8.js +1 -0
- package/dist/index.html +60 -33
- package/dist/sw.js +6 -31
- package/index.html +35 -8
- package/package.json +8 -8
- package/public/sw.js +6 -31
- package/src/app/index.tsx +0 -2
- package/src/features/panel-apps/components/panel-app-list-item.test.tsx +4 -0
- package/src/features/panel-apps/components/panel-apps-list.tsx +27 -1
- package/src/features/panel-apps/hooks/use-panel-apps.ts +10 -0
- package/src/features/panel-apps/managers/panel-app-bridge.manager.test.ts +18 -40
- package/src/features/panel-apps/managers/panel-app-bridge.manager.ts +24 -36
- package/src/features/panel-apps/utils/panel-app-view.utils.test.ts +4 -0
- package/src/features/pwa/components/pwa-install-entry.test.tsx +5 -46
- package/src/features/pwa/components/pwa-install-entry.tsx +1 -35
- package/src/features/pwa/index.ts +1 -1
- package/src/features/pwa/managers/pwa-install.manager.ts +0 -2
- package/src/features/pwa/managers/pwa-runtime.manager.ts +2 -120
- package/src/features/pwa/managers/pwa-service-worker-cache.manager.test.ts +7 -5
- package/src/features/pwa/stores/pwa.store.ts +1 -3
- package/src/features/pwa/types/pwa.types.ts +0 -2
- package/src/features/right-panel-resources/utils/right-panel-resource-uri.utils.test.ts +4 -0
- package/src/features/service-apps/components/service-apps-panel.tsx +3 -3
- package/src/shared/lib/api/index.ts +1 -1
- package/src/shared/lib/api/{ncp-session-query-cache.test.ts → ncp-session-query-cache.utils.test.ts} +23 -0
- package/src/shared/lib/api/{ncp-session-query-cache.ts → ncp-session-query-cache.utils.ts} +9 -11
- package/src/shared/lib/api/types.ts +4 -0
- package/src/shared/lib/i18n/runtime/doc-browser-labels.utils.ts +5 -0
- package/dist/assets/app-presenter-provider-CKZqZfv5.js +0 -3
- package/dist/assets/arrow-left-DHcD-tbC.js +0 -1
- package/dist/assets/doc-browser-DlT90zQD.js +0 -1
- package/dist/assets/index-BCq7kbC8.css +0 -1
- package/dist/assets/mcp-marketplace-page-CmZwt64F.js +0 -1
- package/dist/assets/play-DGpH8jeI.js +0 -1
- package/dist/assets/plus-CkcQjwuH.js +0 -1
- package/dist/assets/remote-CYmsM9DD.js +0 -1
- package/dist/assets/rotate-cw-D_xslHna.js +0 -1
- package/dist/assets/search-CNMRwAFx.js +0 -1
- package/dist/assets/x-DGqjdMUt.js +0 -1
|
@@ -1,11 +1,6 @@
|
|
|
1
|
-
import { usePwaStore } from '@/features/pwa/stores/pwa.store';
|
|
2
|
-
|
|
3
|
-
const PWA_DEV_RESET_SESSION_KEY = 'nextclaw-pwa-dev-sw-reset';
|
|
4
|
-
|
|
5
1
|
export class PwaRuntimeManager {
|
|
6
2
|
private started = false;
|
|
7
3
|
private registration: ServiceWorkerRegistration | null = null;
|
|
8
|
-
private reloadWhenControllerChanges = false;
|
|
9
4
|
|
|
10
5
|
start = async () => {
|
|
11
6
|
if (this.started || typeof window === 'undefined') {
|
|
@@ -25,55 +20,9 @@ export class PwaRuntimeManager {
|
|
|
25
20
|
try {
|
|
26
21
|
const registration = await navigator.serviceWorker.register('/sw.js');
|
|
27
22
|
this.registration = registration;
|
|
28
|
-
this.bindRegistration(registration);
|
|
29
|
-
navigator.serviceWorker.addEventListener('controllerchange', this.handleControllerChange);
|
|
30
|
-
await this.syncUpdateAvailability();
|
|
31
23
|
} catch {
|
|
32
|
-
usePwaStore.setState({
|
|
33
|
-
registrationFailed: true
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
syncUpdateAvailability = async () => {
|
|
39
|
-
if (
|
|
40
|
-
typeof window === 'undefined' ||
|
|
41
|
-
!('serviceWorker' in navigator) ||
|
|
42
|
-
typeof navigator.serviceWorker.getRegistration !== 'function'
|
|
43
|
-
) {
|
|
44
|
-
usePwaStore.setState({
|
|
45
|
-
updateAvailable: false
|
|
46
|
-
});
|
|
47
24
|
return;
|
|
48
25
|
}
|
|
49
|
-
|
|
50
|
-
const registration = this.registration ?? (await navigator.serviceWorker.getRegistration('/sw.js')) ?? null;
|
|
51
|
-
usePwaStore.setState({
|
|
52
|
-
updateAvailable: this.shouldSurfaceUpdate(registration)
|
|
53
|
-
});
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
applyUpdate = async () => {
|
|
57
|
-
const registration = this.registration ?? (await navigator.serviceWorker.getRegistration('/sw.js')) ?? null;
|
|
58
|
-
if (!registration) {
|
|
59
|
-
window.location.reload();
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
if (!registration.waiting) {
|
|
64
|
-
await registration.update();
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const waitingWorker = registration.waiting;
|
|
68
|
-
if (!waitingWorker) {
|
|
69
|
-
window.location.reload();
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
this.reloadWhenControllerChanges = true;
|
|
74
|
-
waitingWorker.postMessage({
|
|
75
|
-
type: 'SKIP_WAIT'
|
|
76
|
-
});
|
|
77
26
|
};
|
|
78
27
|
|
|
79
28
|
stop = () => {
|
|
@@ -81,34 +30,8 @@ export class PwaRuntimeManager {
|
|
|
81
30
|
return;
|
|
82
31
|
}
|
|
83
32
|
|
|
84
|
-
navigator.serviceWorker.removeEventListener('controllerchange', this.handleControllerChange);
|
|
85
33
|
this.started = false;
|
|
86
34
|
this.registration = null;
|
|
87
|
-
this.reloadWhenControllerChanges = false;
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
private bindRegistration = (registration: ServiceWorkerRegistration) => {
|
|
91
|
-
registration.addEventListener('updatefound', () => {
|
|
92
|
-
const installingWorker = registration.installing;
|
|
93
|
-
if (!installingWorker) {
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
installingWorker.addEventListener('statechange', () => {
|
|
98
|
-
if (installingWorker.state === 'installed') {
|
|
99
|
-
void this.syncUpdateAvailability();
|
|
100
|
-
}
|
|
101
|
-
});
|
|
102
|
-
});
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
private handleControllerChange = () => {
|
|
106
|
-
if (!this.reloadWhenControllerChanges) {
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
this.reloadWhenControllerChanges = false;
|
|
111
|
-
window.location.reload();
|
|
112
35
|
};
|
|
113
36
|
|
|
114
37
|
private isEligibleInstallContext = (): boolean => {
|
|
@@ -123,13 +46,6 @@ export class PwaRuntimeManager {
|
|
|
123
46
|
return import.meta.env.DEV && !import.meta.env.VITEST;
|
|
124
47
|
};
|
|
125
48
|
|
|
126
|
-
private shouldSurfaceUpdate = (registration: ServiceWorkerRegistration | null): boolean => {
|
|
127
|
-
if (!registration?.waiting || !navigator.serviceWorker.controller) {
|
|
128
|
-
return false;
|
|
129
|
-
}
|
|
130
|
-
return usePwaStore.getState().installability === 'installed';
|
|
131
|
-
};
|
|
132
|
-
|
|
133
49
|
private cleanupDevelopmentRegistrations = async () => {
|
|
134
50
|
if (typeof navigator.serviceWorker.getRegistrations !== 'function') {
|
|
135
51
|
return;
|
|
@@ -142,21 +58,10 @@ export class PwaRuntimeManager {
|
|
|
142
58
|
.some((scriptUrl) => scriptUrl.endsWith('/sw.js'))
|
|
143
59
|
);
|
|
144
60
|
|
|
145
|
-
if (nextclawRegistrations.length === 0) {
|
|
146
|
-
this.clearDevResetMarker();
|
|
147
|
-
return;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
61
|
await Promise.all(nextclawRegistrations.map(async (registration) => await registration.unregister()));
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
if (navigator.serviceWorker.controller && !this.hasDevResetMarker()) {
|
|
154
|
-
this.setDevResetMarker();
|
|
155
|
-
window.location.reload();
|
|
156
|
-
return;
|
|
62
|
+
if (nextclawRegistrations.length > 0) {
|
|
63
|
+
await this.clearNextClawCaches();
|
|
157
64
|
}
|
|
158
|
-
|
|
159
|
-
this.clearDevResetMarker();
|
|
160
65
|
};
|
|
161
66
|
|
|
162
67
|
private clearNextClawCaches = async () => {
|
|
@@ -168,29 +73,6 @@ export class PwaRuntimeManager {
|
|
|
168
73
|
await Promise.all(keys.filter((key) => key.startsWith('nextclaw-ui-')).map(async (key) => await caches.delete(key)));
|
|
169
74
|
};
|
|
170
75
|
|
|
171
|
-
private hasDevResetMarker = (): boolean => {
|
|
172
|
-
try {
|
|
173
|
-
return window.sessionStorage.getItem(PWA_DEV_RESET_SESSION_KEY) === '1';
|
|
174
|
-
} catch {
|
|
175
|
-
return false;
|
|
176
|
-
}
|
|
177
|
-
};
|
|
178
|
-
|
|
179
|
-
private setDevResetMarker = () => {
|
|
180
|
-
try {
|
|
181
|
-
window.sessionStorage.setItem(PWA_DEV_RESET_SESSION_KEY, '1');
|
|
182
|
-
} catch {
|
|
183
|
-
// ignore sessionStorage availability failures in dev cleanup
|
|
184
|
-
}
|
|
185
|
-
};
|
|
186
|
-
|
|
187
|
-
private clearDevResetMarker = () => {
|
|
188
|
-
try {
|
|
189
|
-
window.sessionStorage.removeItem(PWA_DEV_RESET_SESSION_KEY);
|
|
190
|
-
} catch {
|
|
191
|
-
// ignore sessionStorage availability failures in dev cleanup
|
|
192
|
-
}
|
|
193
|
-
};
|
|
194
76
|
}
|
|
195
77
|
|
|
196
78
|
export const pwaRuntimeManager = new PwaRuntimeManager();
|
|
@@ -6,11 +6,13 @@ describe('NextClaw service worker cache policy', () => {
|
|
|
6
6
|
});
|
|
7
7
|
|
|
8
8
|
it('does not fall back to stale navigation responses', () => {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
expect(serviceWorkerSource).not.toContain("request.mode === 'navigate'");
|
|
10
|
+
expect(serviceWorkerSource).not.toContain('handleNavigation');
|
|
11
|
+
expect(serviceWorkerSource).toContain('SHELL_ASSETS.includes(url.pathname)');
|
|
12
|
+
});
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
it('does not force service worker activation or page control', () => {
|
|
15
|
+
expect(serviceWorkerSource).not.toContain('skipWaiting');
|
|
16
|
+
expect(serviceWorkerSource).not.toContain('clients.claim');
|
|
15
17
|
});
|
|
16
18
|
});
|
|
@@ -8,9 +8,7 @@ export function createInitialPwaState(): PwaInstallStateSnapshot {
|
|
|
8
8
|
installability: 'unsupported',
|
|
9
9
|
installMethod: 'none',
|
|
10
10
|
blockedReason: 'missing-browser-support',
|
|
11
|
-
dismissedInstallPrompt: isPwaInstallBannerDismissed()
|
|
12
|
-
updateAvailable: false,
|
|
13
|
-
registrationFailed: false
|
|
11
|
+
dismissedInstallPrompt: isPwaInstallBannerDismissed()
|
|
14
12
|
};
|
|
15
13
|
}
|
|
16
14
|
|
|
@@ -4,11 +4,15 @@ import { createPanelAppRightPanelResourceTarget } from '@/features/right-panel-r
|
|
|
4
4
|
|
|
5
5
|
function createPanelAppEntry(overrides: Partial<PanelAppEntryView> = {}): PanelAppEntryView {
|
|
6
6
|
return {
|
|
7
|
+
appId: 'demo',
|
|
8
|
+
clientDeclared: false,
|
|
9
|
+
clientGranted: false,
|
|
7
10
|
contentPath: '/api/panel-apps/demo/content',
|
|
8
11
|
createdAt: '2026-06-02T00:00:00.000Z',
|
|
9
12
|
favorite: false,
|
|
10
13
|
fileName: 'demo.html',
|
|
11
14
|
id: 'demo',
|
|
15
|
+
kind: 'single-file',
|
|
12
16
|
openCount: 0,
|
|
13
17
|
sizeBytes: 1024,
|
|
14
18
|
title: 'Demo App',
|
|
@@ -77,9 +77,9 @@ export function ServiceAppsPanel({
|
|
|
77
77
|
);
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
const apps = serviceApps.data?.entries ?? [];
|
|
81
|
-
const actions = serviceActions.data?.actions ?? [];
|
|
82
|
-
const grants = serviceActionGrants.data?.grants ?? [];
|
|
80
|
+
const apps: ServiceAppRecordView[] = serviceApps.data?.entries ?? [];
|
|
81
|
+
const actions: ServiceActionView[] = serviceActions.data?.actions ?? [];
|
|
82
|
+
const grants: ServiceActionGrantView[] = serviceActionGrants.data?.grants ?? [];
|
|
83
83
|
const discover = (appId: string) => {
|
|
84
84
|
void discoverServiceAppActions.mutateAsync(appId).then((result) => {
|
|
85
85
|
setDiscoveredActionsByApp((current) => ({
|
|
@@ -11,7 +11,7 @@ export * from './utils/mcp-marketplace.utils';
|
|
|
11
11
|
export * from './utils/ncp-attachments.utils';
|
|
12
12
|
export * from './utils/ncp-session.utils';
|
|
13
13
|
export * from './ncp-session.types';
|
|
14
|
-
export * from './ncp-session-query-cache';
|
|
14
|
+
export * from './ncp-session-query-cache.utils';
|
|
15
15
|
export * from './raw-client.utils';
|
|
16
16
|
export * from './utils/remote.utils';
|
|
17
17
|
export * from './remote.types';
|
package/src/shared/lib/api/{ncp-session-query-cache.test.ts → ncp-session-query-cache.utils.test.ts}
RENAMED
|
@@ -131,6 +131,29 @@ describe('ncp-session-query-cache', () => {
|
|
|
131
131
|
});
|
|
132
132
|
});
|
|
133
133
|
|
|
134
|
+
it('keeps the realtime running overlay when a newer persisted idle summary arrives', () => {
|
|
135
|
+
const current = updateNcpSessionRunStatusList(createSessionsList(), {
|
|
136
|
+
sessionKey: 'session-1',
|
|
137
|
+
status: 'running'
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
const updated = upsertNcpSessionSummaryList(current, {
|
|
141
|
+
sessionId: 'session-1',
|
|
142
|
+
messageCount: 2,
|
|
143
|
+
createdAt: '2026-03-29T08:00:00.000Z',
|
|
144
|
+
updatedAt: '2026-03-29T10:01:00.000Z',
|
|
145
|
+
lastMessageAt: '2026-03-29T10:01:00.000Z',
|
|
146
|
+
status: 'idle',
|
|
147
|
+
metadata: { last_activity_preview: { state: 'running' } }
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
expect(updated?.sessions[0]).toMatchObject({
|
|
151
|
+
sessionId: 'session-1',
|
|
152
|
+
messageCount: 2,
|
|
153
|
+
status: 'running'
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
|
|
134
157
|
it('applies realtime upsert/delete events to every ncp-sessions query cache entry', () => {
|
|
135
158
|
const queryClient = new QueryClient();
|
|
136
159
|
queryClient.setQueryData(['ncp-sessions', 200], createSessionsList());
|
|
@@ -14,18 +14,11 @@ function shouldReplaceSessionSummary(
|
|
|
14
14
|
next: NcpSessionSummaryView
|
|
15
15
|
): boolean {
|
|
16
16
|
const timeOrder = next.updatedAt.localeCompare(current.updatedAt);
|
|
17
|
-
if (timeOrder
|
|
18
|
-
return
|
|
19
|
-
}
|
|
20
|
-
if (timeOrder < 0) {
|
|
21
|
-
return false;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
if (current.status === next.status) {
|
|
25
|
-
return true;
|
|
17
|
+
if (timeOrder !== 0) {
|
|
18
|
+
return timeOrder > 0;
|
|
26
19
|
}
|
|
27
20
|
|
|
28
|
-
return next.status === 'idle';
|
|
21
|
+
return current.status === next.status || next.status === 'idle';
|
|
29
22
|
}
|
|
30
23
|
|
|
31
24
|
export function upsertNcpSessionSummaryList(
|
|
@@ -40,7 +33,12 @@ export function upsertNcpSessionSummaryList(
|
|
|
40
33
|
const nextSessions =
|
|
41
34
|
existingIndex >= 0
|
|
42
35
|
? current.sessions.map((session, index) =>
|
|
43
|
-
index === existingIndex && shouldReplaceSessionSummary(session, summary)
|
|
36
|
+
index === existingIndex && shouldReplaceSessionSummary(session, summary)
|
|
37
|
+
? {
|
|
38
|
+
...summary,
|
|
39
|
+
status: session.status === 'running' && summary.status === 'idle' ? 'running' : summary.status
|
|
40
|
+
}
|
|
41
|
+
: session
|
|
44
42
|
)
|
|
45
43
|
: [...current.sessions, summary];
|
|
46
44
|
const sortedSessions = sortSessionSummaries(nextSessions);
|
|
@@ -363,7 +363,9 @@ export type ServerPathReadView = { requestedPath: string; resolvedPath: string;
|
|
|
363
363
|
|
|
364
364
|
export type PanelAppEntryView = {
|
|
365
365
|
id: string;
|
|
366
|
+
appId: string;
|
|
366
367
|
fileName: string;
|
|
368
|
+
kind: "single-file" | "folder";
|
|
367
369
|
title: string;
|
|
368
370
|
description?: string;
|
|
369
371
|
icon?: string;
|
|
@@ -372,6 +374,8 @@ export type PanelAppEntryView = {
|
|
|
372
374
|
updatedAt: string;
|
|
373
375
|
sizeBytes: number;
|
|
374
376
|
favorite: boolean;
|
|
377
|
+
clientDeclared: boolean;
|
|
378
|
+
clientGranted: boolean;
|
|
375
379
|
lastOpenedAt?: string;
|
|
376
380
|
openCount: number;
|
|
377
381
|
};
|
|
@@ -39,6 +39,11 @@ export const DOC_BROWSER_LABELS = {
|
|
|
39
39
|
zh: '将删除这个面板应用文件,删除后不可恢复。',
|
|
40
40
|
en: 'This will delete the panel app file and cannot be undone.',
|
|
41
41
|
},
|
|
42
|
+
panelAppsClientGrantTitle: { zh: 'NextClaw Client SDK', en: 'NextClaw Client SDK' },
|
|
43
|
+
panelAppsClientGrantDescription: {
|
|
44
|
+
zh: '允许这个面板应用使用完整 NextClaw Client SDK。',
|
|
45
|
+
en: 'Allow this panel app to use the full NextClaw Client SDK.',
|
|
46
|
+
},
|
|
42
47
|
panelAppsLastOpened: { zh: '上次打开', en: 'Last opened' },
|
|
43
48
|
panelAppsUpdated: { zh: '更新于', en: 'Updated' },
|
|
44
49
|
serviceAppsTitle: { zh: '服务应用', en: 'Service Apps' },
|