@nextclaw/ui 0.16.0 → 0.17.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.
Files changed (73) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/assets/api-DJ6ZKWFY.js +13 -0
  3. package/dist/assets/{appearance-settings-page-CfwDf9ag.js → appearance-settings-page-B-juoJ6F.js} +1 -1
  4. package/dist/assets/{channels-list-page-Dyn83ZlS.js → channels-list-page-mVHYa7xW.js} +1 -1
  5. package/dist/assets/{chat-page-CL0IMvgF.js → chat-page-DsMYGNee.js} +1 -1
  6. package/dist/assets/{config-split-page-D4D4HFhq.js → config-split-page-BaqLcRxk.js} +1 -1
  7. package/dist/assets/{confirm-dialog-Cv6-9Nnj.js → confirm-dialog-DasFoaCT.js} +1 -1
  8. package/dist/assets/{desktop-update-config-Bckgulvm.js → desktop-update-config-CoEvKrpB.js} +1 -1
  9. package/dist/assets/{dist-BrRgjiq1.js → dist-C741xUwt.js} +1 -1
  10. package/dist/assets/{dist-Bh_tj3FN.js → dist-zOKNc7QQ.js} +1 -1
  11. package/dist/assets/doc-browser-BbirIYbj.js +1 -0
  12. package/dist/assets/{doc-browser-BlWjhmnM.js → doc-browser-Crqog5cn.js} +1 -1
  13. package/dist/assets/{doc-browser-context-NGYa66Xg.js → doc-browser-context-BT8NWQyM.js} +1 -1
  14. package/dist/assets/{form-actions-CeKgh4SQ.js → form-actions-BcukaMyR.js} +1 -1
  15. package/dist/assets/index-1f4Pv2q3.css +1 -0
  16. package/dist/assets/index-BYWLjYFQ.js +109 -0
  17. package/dist/assets/loader-circle-LVHz84Xj.js +1 -0
  18. package/dist/assets/mcp-marketplace-page-2SsrbaiQ.js +1 -0
  19. package/dist/assets/{mcp-marketplace-page-DfNmMqKs.js → mcp-marketplace-page-XgYLOAkK.js} +1 -1
  20. package/dist/assets/{model-config-page-DHzyDV5v.js → model-config-page-DL8ljJK-.js} +1 -1
  21. package/dist/assets/{navigation-link-CzGgQGi_.js → navigation-link-BoMNAKyw.js} +1 -1
  22. package/dist/assets/plus-BeGZHC3f.js +1 -0
  23. package/dist/assets/{provider-scoped-model-input-CjrHwzFb.js → provider-scoped-model-input-CB-vojwC.js} +1 -1
  24. package/dist/assets/{providers-config-page-ZPvJWHFN.js → providers-config-page-C80nti5H.js} +1 -1
  25. package/dist/assets/{react-BXRf96P-.js → react-DND3vEAM.js} +1 -1
  26. package/dist/assets/{refresh-cw-ChKuqgPR.js → refresh-cw-DZ_Y89ld.js} +1 -1
  27. package/dist/assets/remote-Codkr9SX.js +1 -0
  28. package/dist/assets/rotate-cw-CP3pQ4R8.js +1 -0
  29. package/dist/assets/{runtime-config-page-CGpPQD8K.js → runtime-config-page-Um1XDqXJ.js} +1 -1
  30. package/dist/assets/{save-BWGNAKV5.js → save-BgMfxs5u.js} +1 -1
  31. package/dist/assets/{search-DFcT_9wJ.js → search-C7ruoV7u.js} +1 -1
  32. package/dist/assets/{search-config-page-DBBzVAQZ.js → search-config-page-BTjfOZ6q.js} +1 -1
  33. package/dist/assets/{secrets-config-page-bnJ8sIB7.js → secrets-config-page-BFjiSz73.js} +1 -1
  34. package/dist/assets/security-config-Dx-wMb4q.js +1 -0
  35. package/dist/assets/{select-BnNrv8si.js → select-BMX2ooE-.js} +1 -1
  36. package/dist/assets/{settings-2-CFHrgKTX.js → settings-2-BNQF6hed.js} +1 -1
  37. package/dist/assets/skeleton-CWZ0IO2D.js +1 -0
  38. package/dist/assets/{tag-chip-L5w4xfS7.js → tag-chip-BL-UXlVO.js} +1 -1
  39. package/dist/assets/x-BSu1xwPK.js +1 -0
  40. package/dist/index.html +19 -19
  41. package/package.json +4 -4
  42. package/src/features/app-data/components/app-data-removal-choice.tsx +43 -0
  43. package/src/features/app-data/components/app-retained-data-section.tsx +179 -0
  44. package/src/features/app-data/components/app-storage-usage.tsx +59 -0
  45. package/src/features/app-data/hooks/use-app-data.ts +26 -0
  46. package/src/features/app-data/index.ts +8 -0
  47. package/src/features/apps/components/__tests__/app-packages-panel.test.tsx +114 -10
  48. package/src/features/apps/components/__tests__/apps-panel.test.tsx +18 -2
  49. package/src/features/apps/components/app-package-card.tsx +98 -53
  50. package/src/features/apps/components/app-packages-panel.tsx +78 -23
  51. package/src/features/apps/components/apps-panel.tsx +14 -3
  52. package/src/features/apps/hooks/use-app-packages.ts +7 -2
  53. package/src/features/apps/managers/__tests__/app-package-operation-settlement.manager.test.ts +5 -0
  54. package/src/features/apps/managers/app-package-operation-settlement.manager.ts +8 -2
  55. package/src/features/service-apps/components/__tests__/service-apps-panel.test.tsx +91 -6
  56. package/src/features/service-apps/components/service-app-delete-dialog.tsx +122 -0
  57. package/src/features/service-apps/components/service-app-list-item.tsx +50 -21
  58. package/src/features/service-apps/components/service-apps-panel.tsx +38 -2
  59. package/src/features/service-apps/hooks/use-service-apps.ts +4 -1
  60. package/src/shared/lib/i18n/locales/en-US/doc-browser.json +26 -1
  61. package/src/shared/lib/i18n/locales/zh-CN/doc-browser.json +26 -1
  62. package/dist/assets/api-Dket1cmq.js +0 -13
  63. package/dist/assets/doc-browser-Da9hDsoQ.js +0 -1
  64. package/dist/assets/index-Bz5yNMXA.js +0 -109
  65. package/dist/assets/index-DSLK7zgR.css +0 -1
  66. package/dist/assets/loader-circle-DLp2jNIf.js +0 -1
  67. package/dist/assets/mcp-marketplace-page-CIWbjXM8.js +0 -1
  68. package/dist/assets/plus-Dfj3tJ_m.js +0 -1
  69. package/dist/assets/remote-C2enAZbs.js +0 -1
  70. package/dist/assets/rotate-cw-BGkZpcc7.js +0 -1
  71. package/dist/assets/security-config-CfbXSpgX.js +0 -1
  72. package/dist/assets/skeleton-tfWhGuJT.js +0 -1
  73. package/dist/assets/x-BCSE3LCQ.js +0 -1
@@ -2,10 +2,12 @@ import { useState } from "react";
2
2
  import type {
3
3
  ServiceActionGrantView,
4
4
  ServiceActionListView,
5
+ AppDataEntry,
5
6
  ServiceAppRecordView,
6
7
  } from "@nextclaw/client-sdk";
7
8
  import {
8
9
  AlertTriangle,
10
+ Boxes,
9
11
  CheckCircle2,
10
12
  ChevronDown,
11
13
  CircleDashed,
@@ -20,7 +22,7 @@ import {
20
22
  type LucideIcon,
21
23
  Wrench,
22
24
  } from "lucide-react";
23
- import { ConfirmDialog } from "@/shared/components/ui/confirm-dialog";
25
+ import { ServiceAppDeleteDialog } from "@/features/service-apps/components/service-app-delete-dialog";
24
26
  import {
25
27
  Popover,
26
28
  PopoverContent,
@@ -44,10 +46,15 @@ export function ServiceAppListItem({
44
46
  actionsOpen,
45
47
  grants,
46
48
  deletePending,
49
+ deleteError,
50
+ dataEntry,
51
+ dataLoading,
47
52
  isDiscovering,
48
53
  onActionsOpenChange,
49
54
  onDiscover,
55
+ onManagePackage,
50
56
  onDelete,
57
+ onResetDelete,
51
58
  onRestart,
52
59
  onRevoke,
53
60
  }: {
@@ -56,26 +63,32 @@ export function ServiceAppListItem({
56
63
  actionsOpen: boolean;
57
64
  grants: ServiceActionGrantView[];
58
65
  deletePending: boolean;
66
+ deleteError: unknown;
67
+ dataEntry?: AppDataEntry;
68
+ dataLoading: boolean;
59
69
  isDiscovering: boolean;
60
70
  onActionsOpenChange: (open: boolean) => void;
61
71
  onDiscover: (appId: string) => void;
62
- onDelete: (appId: string) => void;
72
+ onManagePackage: (packageId: string) => void;
73
+ onDelete: (appId: string, purgeData: boolean, onSuccess: () => void) => void;
74
+ onResetDelete: () => void;
63
75
  onRestart: (appId: string) => void;
64
76
  onRevoke: (grant: ServiceActionGrantView) => void;
65
77
  }) {
66
78
  const [isMenuOpen, setIsMenuOpen] = useState(false);
67
79
  const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false);
68
80
  const [isDiagnosticsOpen, setIsDiagnosticsOpen] = useState(false);
69
- const canConnectAndDiscover =
70
- app.status !== "starting" && app.status !== "stopped";
71
- const canDisconnectRuntime =
72
- app.status === "running" || app.status === "failed";
81
+ const [purgeData, setPurgeData] = useState(false);
82
+ const canConnectAndDiscover = app.status !== "starting" && app.status !== "stopped";
83
+ const canDisconnectRuntime = app.status === "running" || app.status === "failed";
84
+ const managedPackageId = app.sourceKind === "package" ? app.packageId : undefined;
73
85
  const diagnostics = getServiceAppDiagnostics(app);
74
86
  const openDeleteDialog = () => {
75
87
  setIsMenuOpen(false);
88
+ setPurgeData(false);
89
+ onResetDelete();
76
90
  setIsDeleteDialogOpen(true);
77
91
  };
78
-
79
92
  return (
80
93
  <TooltipProvider delayDuration={250}>
81
94
  <section className="group bg-card transition-colors hover:bg-muted/25">
@@ -156,13 +169,24 @@ export function ServiceAppListItem({
156
169
  onRestart(app.id);
157
170
  }}
158
171
  />
159
- <ServiceAppMenuItem
160
- destructive
161
- disabled={deletePending}
162
- icon={Trash2}
163
- label={t("serviceAppsDelete")}
164
- onClick={openDeleteDialog}
165
- />
172
+ {managedPackageId ? (
173
+ <ServiceAppMenuItem
174
+ icon={Boxes}
175
+ label={t("serviceAppsManagePackage")}
176
+ onClick={() => {
177
+ setIsMenuOpen(false);
178
+ onManagePackage(managedPackageId);
179
+ }}
180
+ />
181
+ ) : (
182
+ <ServiceAppMenuItem
183
+ destructive
184
+ disabled={deletePending}
185
+ icon={Trash2}
186
+ label={t("serviceAppsDelete")}
187
+ onClick={openDeleteDialog}
188
+ />
189
+ )}
166
190
  </PopoverContent>
167
191
  </Popover>
168
192
  </div>
@@ -233,16 +257,21 @@ export function ServiceAppListItem({
233
257
  ) : null}
234
258
  </div>
235
259
 
236
- <ConfirmDialog
260
+ {app.sourceKind !== "package" ? (
261
+ <ServiceAppDeleteDialog
262
+ appId={app.id}
263
+ appTitle={app.title}
264
+ dataEntry={dataEntry}
265
+ dataLoading={dataLoading}
266
+ deleteError={deleteError}
267
+ deletePending={deletePending}
237
268
  open={isDeleteDialogOpen}
269
+ purgeData={purgeData}
270
+ onDelete={onDelete}
238
271
  onOpenChange={setIsDeleteDialogOpen}
239
- title={t("serviceAppsDeleteConfirmTitle")}
240
- description={`${t("serviceAppsDeleteConfirmDescription")} ${app.title}`}
241
- confirmLabel={t("delete")}
242
- variant="destructive"
243
- onConfirm={() => onDelete(app.id)}
244
- onCancel={() => undefined}
272
+ onPurgeDataChange={setPurgeData}
245
273
  />
274
+ ) : null}
246
275
  </section>
247
276
  </TooltipProvider>
248
277
  );
@@ -2,9 +2,11 @@ import { useState } from "react";
2
2
  import type {
3
3
  ServiceActionGrantView,
4
4
  ServiceActionListView,
5
+ AppDataEntry,
5
6
  ServiceAppRecordView,
6
7
  } from "@nextclaw/client-sdk";
7
8
  import { RefreshCw, Server } from "lucide-react";
9
+ import { useAppData } from "@/features/app-data";
8
10
  import { ServiceAppListItem } from "@/features/service-apps/components/service-app-list-item";
9
11
  import {
10
12
  useDeleteServiceApp,
@@ -25,8 +27,13 @@ import { t } from "@/shared/lib/i18n";
25
27
 
26
28
  type ServiceActionView = ServiceActionListView["actions"][number];
27
29
 
28
- export function ServiceAppsPanel() {
30
+ export function ServiceAppsPanel({
31
+ onManagePackage,
32
+ }: {
33
+ onManagePackage: (packageId: string) => void;
34
+ }) {
29
35
  const serviceApps = useServiceApps();
36
+ const appData = useAppData();
30
37
  const serviceActions = useServiceActions();
31
38
  const serviceActionGrants = useServiceActionGrants();
32
39
  const deleteServiceApp = useDeleteServiceApp();
@@ -44,6 +51,7 @@ export function ServiceAppsPanel() {
44
51
  void serviceApps.refetch();
45
52
  void serviceActions.refetch();
46
53
  void serviceActionGrants.refetch();
54
+ void appData.refetch();
47
55
  };
48
56
 
49
57
  if (
@@ -73,6 +81,7 @@ export function ServiceAppsPanel() {
73
81
  }
74
82
 
75
83
  const apps: ServiceAppRecordView[] = serviceApps.data?.entries ?? [];
84
+ const diagnostics = serviceApps.data?.diagnostics ?? [];
76
85
  const actions: ServiceActionView[] = serviceActions.data?.actions ?? [];
77
86
  const grants: ServiceActionGrantView[] =
78
87
  serviceActionGrants.data?.grants ?? [];
@@ -85,6 +94,9 @@ export function ServiceAppsPanel() {
85
94
  setExpandedActionsByApp((current) => ({ ...current, [appId]: true }));
86
95
  });
87
96
  };
97
+ const workspaceDataEntries = (appData.data?.entries ?? [])
98
+ .filter((entry): entry is AppDataEntry =>
99
+ entry.source === "workspace-service" && entry.lifecycle === "active");
88
100
 
89
101
  return (
90
102
  <div className="flex h-full min-h-0 flex-col bg-card text-card-foreground">
@@ -108,6 +120,22 @@ export function ServiceAppsPanel() {
108
120
  </TooltipProvider>
109
121
  </div>
110
122
 
123
+ {diagnostics.length > 0 ? (
124
+ <div
125
+ role="alert"
126
+ className="mx-3 mt-3 rounded-xl border border-destructive/20 bg-destructive/5 px-3 py-2.5 text-xs text-destructive sm:mx-4"
127
+ >
128
+ <div className="font-medium">{t("serviceAppsLoadFailed")}</div>
129
+ <ul className="mt-1 space-y-1">
130
+ {diagnostics.map((diagnostic) => (
131
+ <li key={diagnostic.stagedPath} className="break-words">
132
+ {diagnostic.appId}: {diagnostic.message}
133
+ </li>
134
+ ))}
135
+ </ul>
136
+ </div>
137
+ ) : null}
138
+
111
139
  {apps.length === 0 ? (
112
140
  <div className="flex flex-1 items-center justify-center px-6 py-8 text-center">
113
141
  <div className="w-full max-w-xs">
@@ -136,6 +164,9 @@ export function ServiceAppsPanel() {
136
164
  actionsOpen={Boolean(expandedActionsByApp[app.id])}
137
165
  grants={grants}
138
166
  deletePending={deleteServiceApp.isPending}
167
+ deleteError={deleteServiceApp.error}
168
+ dataEntry={workspaceDataEntries.find((entry) => entry.appId === app.id)}
169
+ dataLoading={appData.isLoading}
139
170
  isDiscovering={discoverServiceAppActions.isPending}
140
171
  onActionsOpenChange={(open) =>
141
172
  setExpandedActionsByApp((current) => ({
@@ -144,7 +175,12 @@ export function ServiceAppsPanel() {
144
175
  }))
145
176
  }
146
177
  onDiscover={discover}
147
- onDelete={(appId) => void deleteServiceApp.mutate(appId)}
178
+ onManagePackage={onManagePackage}
179
+ onDelete={(appId, purgeData, onSuccess) => void deleteServiceApp.mutate(
180
+ { appId, purgeData },
181
+ { onSuccess },
182
+ )}
183
+ onResetDelete={deleteServiceApp.reset}
148
184
  onRestart={(appId) => void restartServiceApp.mutate(appId)}
149
185
  onRevoke={(grant) =>
150
186
  void revokeServiceActionGrant.mutate({
@@ -4,6 +4,7 @@ import { nextclawClient } from '@/shared/lib/api';
4
4
  const SERVICE_APPS_QUERY_KEY = ['service-apps'] as const;
5
5
  const SERVICE_ACTIONS_QUERY_KEY = ['service-actions'] as const;
6
6
  const SERVICE_ACTION_GRANTS_QUERY_KEY = ['service-action-grants'] as const;
7
+ const APP_DATA_QUERY_KEY = ['app-data'] as const;
7
8
 
8
9
  export function useServiceApps() {
9
10
  return useQuery({
@@ -42,12 +43,14 @@ export function useRestartServiceApp() {
42
43
  export function useDeleteServiceApp() {
43
44
  const queryClient = useQueryClient();
44
45
  return useMutation({
45
- mutationFn: (appId: string) => nextclawClient.serviceApps.deleteServiceApp(appId),
46
+ mutationFn: (input: { appId: string; purgeData: boolean }) =>
47
+ nextclawClient.serviceApps.deleteServiceApp(input.appId, input.purgeData),
46
48
  onSuccess: async () => {
47
49
  await Promise.all([
48
50
  queryClient.invalidateQueries({ queryKey: SERVICE_APPS_QUERY_KEY }),
49
51
  queryClient.invalidateQueries({ queryKey: SERVICE_ACTIONS_QUERY_KEY }),
50
52
  queryClient.invalidateQueries({ queryKey: SERVICE_ACTION_GRANTS_QUERY_KEY }),
53
+ queryClient.invalidateQueries({ queryKey: APP_DATA_QUERY_KEY }),
51
54
  ]);
52
55
  },
53
56
  });
@@ -34,6 +34,8 @@
34
34
  "appPackagesLibraryTitle": "Your apps",
35
35
  "appPackagesLibraryDescription": "Open and manage the apps in NextClaw. Installs continue in the background, and personal data stays local.",
36
36
  "appPackagesLoading": "Loading apps…",
37
+ "appPackagesDataUsageUnavailable": "Size unavailable",
38
+ "appPackagesNoDataYet": "No data yet",
37
39
  "appPackagesLoadFailed": "Failed to load apps",
38
40
  "appPackagesRefresh": "Refresh apps",
39
41
  "appPackagesBrowse": "Add apps",
@@ -117,6 +119,25 @@
117
119
  "appPackagesRollbackCompleted": "App version switched",
118
120
  "appPackagesUninstallCompleted": "App uninstalled",
119
121
  "appPackagesNextClawRequirement": "Requires NextClaw",
122
+ "appDataRetainedTitle": "Saved app data",
123
+ "appDataRetainedDescription": "Data kept after an app was removed stays here until you reinstall the app or delete the data.",
124
+ "appDataLoadFailed": "Failed to load saved app data",
125
+ "appDataDiagnosticsTitle": "Some app data needs attention",
126
+ "appDataDeleteAction": "Delete data",
127
+ "appDataDeleteTitle": "Permanently delete this app data?",
128
+ "appDataDeleteDescription": "This removes the app's private data from this device. Files you exported or saved outside the app remain untouched.",
129
+ "appDataDeletePermanently": "Permanently delete data",
130
+ "appDataDeleting": "Deleting data…",
131
+ "appDataDeleteCompleted": "App data deleted",
132
+ "appDataDeleteFailed": "Failed to delete app data",
133
+ "appDataStorageTotal": "Total app data",
134
+ "appDataStoragePath": "Managed instance path",
135
+ "appDataClassData": "Personal data",
136
+ "appDataClassConfig": "Settings",
137
+ "appDataClassState": "State",
138
+ "appDataClassCache": "Cache",
139
+ "appDataClassTemporary": "Temporary",
140
+ "appDataClassLogs": "Logs",
120
141
  "panelAppsTitle": "Panel Apps",
121
142
  "panelAppsLoading": "Loading panel apps...",
122
143
  "panelAppsLoadFailed": "Failed to load panel apps",
@@ -163,8 +184,12 @@
163
184
  "serviceAppsDisconnectRuntimeHint": "Close the current runtime connection and return the service app to not connected.",
164
185
  "serviceAppsMoreActions": "More actions",
165
186
  "serviceAppsDelete": "Delete service app",
187
+ "serviceAppsManagePackage": "Manage in Apps",
166
188
  "serviceAppsDeleteConfirmTitle": "Delete service app?",
167
- "serviceAppsDeleteConfirmDescription": "This will delete the service app directory and cannot be undone.",
189
+ "serviceAppsDeleteConfirmDescription": "The service source will be deleted. Its private data is kept by default.",
190
+ "serviceAppsKeepDataDescription": "Delete the service source but keep its private data for a future copy of the same service.",
191
+ "serviceAppsDeleteDataDescription": "Permanently delete the service source and its managed private data.",
192
+ "serviceAppsDataUnavailable": "Storage details are unavailable. Keep data selected or refresh before deleting.",
168
193
  "serviceAppsStatus_idle": "Not connected",
169
194
  "serviceAppsStatus_starting": "Connecting",
170
195
  "serviceAppsStatus_running": "Connected",
@@ -34,6 +34,8 @@
34
34
  "appPackagesLibraryTitle": "你的应用",
35
35
  "appPackagesLibraryDescription": "打开和管理装进 NextClaw 的应用。安装会在后台继续,个人数据保存在本机。",
36
36
  "appPackagesLoading": "加载应用中…",
37
+ "appPackagesDataUsageUnavailable": "大小不可用",
38
+ "appPackagesNoDataYet": "尚无数据",
37
39
  "appPackagesLoadFailed": "应用加载失败",
38
40
  "appPackagesRefresh": "刷新应用",
39
41
  "appPackagesBrowse": "添加应用",
@@ -117,6 +119,25 @@
117
119
  "appPackagesRollbackCompleted": "应用版本已切换",
118
120
  "appPackagesUninstallCompleted": "应用已卸载",
119
121
  "appPackagesNextClawRequirement": "需要 NextClaw",
122
+ "appDataRetainedTitle": "已保留的应用数据",
123
+ "appDataRetainedDescription": "卸载应用时保留的数据会留在这里。重新安装可以继续使用,也可以单独永久删除。",
124
+ "appDataLoadFailed": "已保留的应用数据加载失败",
125
+ "appDataDiagnosticsTitle": "部分应用数据需要处理",
126
+ "appDataDeleteAction": "删除数据",
127
+ "appDataDeleteTitle": "永久删除这些应用数据?",
128
+ "appDataDeleteDescription": "这会从本机移除该应用的私有数据。已导出或保存在应用目录之外的文件不会被删除。",
129
+ "appDataDeletePermanently": "永久删除数据",
130
+ "appDataDeleting": "正在删除数据…",
131
+ "appDataDeleteCompleted": "应用数据已删除",
132
+ "appDataDeleteFailed": "应用数据删除失败",
133
+ "appDataStorageTotal": "应用数据总量",
134
+ "appDataStoragePath": "受管实例路径",
135
+ "appDataClassData": "个人数据",
136
+ "appDataClassConfig": "设置",
137
+ "appDataClassState": "状态",
138
+ "appDataClassCache": "缓存",
139
+ "appDataClassTemporary": "临时文件",
140
+ "appDataClassLogs": "日志",
120
141
  "panelAppsTitle": "面板应用",
121
142
  "panelAppsLoading": "加载面板应用中...",
122
143
  "panelAppsLoadFailed": "面板应用加载失败",
@@ -163,8 +184,12 @@
163
184
  "serviceAppsDisconnectRuntimeHint": "断开当前运行时连接,并将服务应用恢复为未连接状态。",
164
185
  "serviceAppsMoreActions": "更多操作",
165
186
  "serviceAppsDelete": "删除服务应用",
187
+ "serviceAppsManagePackage": "在应用中管理",
166
188
  "serviceAppsDeleteConfirmTitle": "删除服务应用?",
167
- "serviceAppsDeleteConfirmDescription": "这会删除服务应用目录,且无法撤销。",
189
+ "serviceAppsDeleteConfirmDescription": "服务源码会被删除,私有数据默认保留。",
190
+ "serviceAppsKeepDataDescription": "删除服务源码,但保留私有数据,之后放回同一服务仍可继续使用。",
191
+ "serviceAppsDeleteDataDescription": "永久删除服务源码及其受管私有数据。",
192
+ "serviceAppsDataUnavailable": "暂时无法读取存储详情。请保留数据,或刷新后再删除。",
168
193
  "serviceAppsStatus_idle": "未连接",
169
194
  "serviceAppsStatus_starting": "连接中",
170
195
  "serviceAppsStatus_running": "已连接",