@arronqzy/react-view 1.0.36 → 1.0.37
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/package.json +4 -4
- package/readme.md +1 -0
- package/src/index.ts +6 -0
- package/src/panel/hooks/useWorkspaceProjects.ts +19 -2
- package/src/panel/library/workspace-project-cache.ts +27 -0
- package/src/panel/library/workspace-project-db.ts +4 -0
- package/src/panel/library/workspace-project-sync.ts +31 -0
- package/src/panel/library/workspace-storage.ts +38 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arronqzy/react-view",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.37",
|
|
4
4
|
"files": [
|
|
5
5
|
"src",
|
|
6
6
|
"dist",
|
|
@@ -30,13 +30,13 @@
|
|
|
30
30
|
"@codemirror/lang-json": "^6.0.1",
|
|
31
31
|
"@codemirror/theme-one-dark": "^6.1.2",
|
|
32
32
|
"@codemirror/view": "^6.36.2",
|
|
33
|
-
"@arronqzy/blueprint-dsl": "1.0.17",
|
|
34
33
|
"@arronqzy/ui": "1.0.10",
|
|
34
|
+
"@arronqzy/blueprint-dsl": "1.0.17",
|
|
35
35
|
"@arronqzy/i18n": "0.1.17",
|
|
36
|
-
"@arronqzy/react-blueprint": "1.0.22",
|
|
37
36
|
"@arronqzy/rx-store": "1.0.8",
|
|
38
37
|
"@arronqzy/view-scene3d": "0.1.5",
|
|
39
38
|
"@arronqzy/view-table": "0.1.8",
|
|
39
|
+
"@arronqzy/react-blueprint": "1.0.22",
|
|
40
40
|
"@arronqzy/webllm-assistant": "0.1.16"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
@@ -45,8 +45,8 @@
|
|
|
45
45
|
"@types/use-sync-external-store": "^1.5.0",
|
|
46
46
|
"eslint": "^8.57.0",
|
|
47
47
|
"typescript": "^5.5.4",
|
|
48
|
-
"@arronqzy/typescript-config": "1.0.0",
|
|
49
48
|
"@arronqzy/eslint-config": "0.0.0",
|
|
49
|
+
"@arronqzy/typescript-config": "1.0.0",
|
|
50
50
|
"@arronqzy/tailwind": "1.0.2"
|
|
51
51
|
},
|
|
52
52
|
"scripts": {
|
package/readme.md
CHANGED
|
@@ -154,6 +154,7 @@ const dataUrl = await getPreviewSnapshot({
|
|
|
154
154
|
| `addEventSubscription` / `AbuilderEvents` | 工作区事件 |
|
|
155
155
|
| `getPreviewSnapshot` | 预览截图 data URL |
|
|
156
156
|
| `parseWorkspaceData` 等 | 校验 / 解析 / 空工作区 |
|
|
157
|
+
| `listWorkspaceProjects` / `deleteWorkspaceProject` / `clearWorkspaceProjects` | 列出 / 删除 / 清空浏览器 IndexedDB 中保存的工作区(参数 `nameSpace`) |
|
|
157
158
|
| `createView` / `createAction` | 视图 DSL 扩展点(`src/core`) |
|
|
158
159
|
|
|
159
160
|
## 样式
|
package/src/index.ts
CHANGED
|
@@ -19,5 +19,11 @@ export type {
|
|
|
19
19
|
WorkspaceData,
|
|
20
20
|
} from "./panel/library/event-subscription";
|
|
21
21
|
export type { WorkspaceProjectRecord } from "./panel/library/workspace-project-db";
|
|
22
|
+
export {
|
|
23
|
+
listWorkspaceProjects,
|
|
24
|
+
deleteWorkspaceProject,
|
|
25
|
+
clearWorkspaceProjects,
|
|
26
|
+
} from "./panel/library/workspace-storage";
|
|
27
|
+
export type { WorkspaceProjectListItem } from "./panel/library/workspace-storage";
|
|
22
28
|
export { getPreviewSnapshot } from "./panel/library/preview-snapshot";
|
|
23
29
|
export type { GetPreviewSnapshotOptions } from "./panel/library/preview-snapshot";
|
|
@@ -5,14 +5,17 @@ import type { BlueprintDocument, BlueprintMetaDraft } from "@arronqzy/react-blue
|
|
|
5
5
|
import type { State } from "@arronqzy/rx-store";
|
|
6
6
|
import {
|
|
7
7
|
createWorkspaceProjectId,
|
|
8
|
-
deleteWorkspaceProject,
|
|
9
8
|
getWorkspaceProject,
|
|
10
9
|
listWorkspaceProjects,
|
|
11
10
|
putWorkspaceProject,
|
|
12
11
|
type WorkspaceProjectListItem,
|
|
13
12
|
type WorkspaceProjectRecord,
|
|
14
13
|
} from "../library/workspace-project-db";
|
|
15
|
-
import {
|
|
14
|
+
import { deleteWorkspaceProject } from "../library/workspace-storage";
|
|
15
|
+
import {
|
|
16
|
+
broadcastWorkspaceProjectUpdate,
|
|
17
|
+
subscribeWorkspaceProjectsChanged,
|
|
18
|
+
} from "../library/workspace-project-sync";
|
|
16
19
|
import { writeWorkspacePreviewCache, readWorkspacePreviewCache } from "../library/workspace-project-cache";
|
|
17
20
|
import {
|
|
18
21
|
cloneWorkspaceSnapshot,
|
|
@@ -159,6 +162,20 @@ export function useWorkspaceProjects({
|
|
|
159
162
|
void refreshProjects();
|
|
160
163
|
}, [refreshProjects]);
|
|
161
164
|
|
|
165
|
+
useEffect(() => {
|
|
166
|
+
return subscribeWorkspaceProjectsChanged((message) => {
|
|
167
|
+
const removedActive =
|
|
168
|
+
message.type === "cleared" ||
|
|
169
|
+
(activeProjectId !== null && message.projectIds.includes(activeProjectId));
|
|
170
|
+
if (removedActive) {
|
|
171
|
+
setActiveProjectId(null);
|
|
172
|
+
setActiveProjectName(null);
|
|
173
|
+
syncedSnapshotRef.current = null;
|
|
174
|
+
}
|
|
175
|
+
void refreshProjects();
|
|
176
|
+
}, nameSpace);
|
|
177
|
+
}, [activeProjectId, nameSpace, refreshProjects]);
|
|
178
|
+
|
|
162
179
|
useEffect(() => {
|
|
163
180
|
if (!pendingRevisionSyncRef.current) return;
|
|
164
181
|
syncedPanelRevisionRef.current = panelRevision;
|
|
@@ -36,3 +36,30 @@ export function readWorkspacePreviewCache(
|
|
|
36
36
|
return null;
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
|
+
|
|
40
|
+
export function removeWorkspacePreviewCache(
|
|
41
|
+
projectId: string,
|
|
42
|
+
nameSpace?: string | null
|
|
43
|
+
): void {
|
|
44
|
+
try {
|
|
45
|
+
localStorage.removeItem(previewCacheKey(projectId, nameSpace));
|
|
46
|
+
} catch {
|
|
47
|
+
// ignore private mode
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function clearWorkspacePreviewCaches(nameSpace?: string | null): void {
|
|
52
|
+
try {
|
|
53
|
+
const suffix = appStorageKey("", nameSpace);
|
|
54
|
+
const keys: string[] = [];
|
|
55
|
+
for (let i = 0; i < localStorage.length; i += 1) {
|
|
56
|
+
const key = localStorage.key(i);
|
|
57
|
+
if (!key || !key.startsWith(CACHE_PREFIX)) continue;
|
|
58
|
+
// 无 nameSpace 时 key 不带 "__<ns>" 后缀,避免误删其他 nameSpace 的标记
|
|
59
|
+
if (suffix ? key.endsWith(suffix) : !key.includes("__")) keys.push(key);
|
|
60
|
+
}
|
|
61
|
+
keys.forEach((key) => localStorage.removeItem(key));
|
|
62
|
+
} catch {
|
|
63
|
+
// ignore private mode
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -286,3 +286,7 @@ export async function deleteWorkspaceProject(
|
|
|
286
286
|
): Promise<void> {
|
|
287
287
|
await runTransaction<undefined>("readwrite", (store) => store.delete(id), nameSpace);
|
|
288
288
|
}
|
|
289
|
+
|
|
290
|
+
export async function clearWorkspaceProjectStore(nameSpace?: string | null): Promise<void> {
|
|
291
|
+
await runTransaction<undefined>("readwrite", (store) => store.clear(), nameSpace);
|
|
292
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { appStorageKey } from "@arronqzy/blueprint-dsl";
|
|
2
2
|
|
|
3
3
|
const CHANNEL_PREFIX = "arronqzy-workspace-project";
|
|
4
|
+
const LIST_CHANNEL = "arronqzy-workspace-projects-changed";
|
|
4
5
|
|
|
5
6
|
export type WorkspaceProjectSyncMessage = {
|
|
6
7
|
type: "updated";
|
|
@@ -8,6 +9,36 @@ export type WorkspaceProjectSyncMessage = {
|
|
|
8
9
|
updatedAt: number;
|
|
9
10
|
};
|
|
10
11
|
|
|
12
|
+
export type WorkspaceProjectsChangedMessage =
|
|
13
|
+
| { type: "deleted"; projectIds: string[] }
|
|
14
|
+
| { type: "cleared" };
|
|
15
|
+
|
|
16
|
+
export function broadcastWorkspaceProjectsChanged(
|
|
17
|
+
message: WorkspaceProjectsChangedMessage,
|
|
18
|
+
nameSpace?: string | null
|
|
19
|
+
): void {
|
|
20
|
+
if (typeof BroadcastChannel === "undefined") return;
|
|
21
|
+
const channel = new BroadcastChannel(appStorageKey(LIST_CHANNEL, nameSpace));
|
|
22
|
+
channel.postMessage(message);
|
|
23
|
+
channel.close();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function subscribeWorkspaceProjectsChanged(
|
|
27
|
+
onChange: (message: WorkspaceProjectsChangedMessage) => void,
|
|
28
|
+
nameSpace?: string | null
|
|
29
|
+
): () => void {
|
|
30
|
+
if (typeof BroadcastChannel === "undefined") {
|
|
31
|
+
return () => {};
|
|
32
|
+
}
|
|
33
|
+
const channel = new BroadcastChannel(appStorageKey(LIST_CHANNEL, nameSpace));
|
|
34
|
+
channel.onmessage = (event: MessageEvent<WorkspaceProjectsChangedMessage>) => {
|
|
35
|
+
const data = event.data;
|
|
36
|
+
if (!data || (data.type !== "deleted" && data.type !== "cleared")) return;
|
|
37
|
+
onChange(data);
|
|
38
|
+
};
|
|
39
|
+
return () => channel.close();
|
|
40
|
+
}
|
|
41
|
+
|
|
11
42
|
export function getWorkspaceProjectChannelName(
|
|
12
43
|
projectId: string,
|
|
13
44
|
nameSpace?: string | null
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import {
|
|
2
|
+
clearWorkspaceProjectStore,
|
|
3
|
+
deleteWorkspaceProject as deleteWorkspaceProjectRecord,
|
|
4
|
+
listWorkspaceProjects,
|
|
5
|
+
} from "./workspace-project-db";
|
|
6
|
+
import {
|
|
7
|
+
clearWorkspacePreviewCaches,
|
|
8
|
+
removeWorkspacePreviewCache,
|
|
9
|
+
} from "./workspace-project-cache";
|
|
10
|
+
import { broadcastWorkspaceProjectsChanged } from "./workspace-project-sync";
|
|
11
|
+
|
|
12
|
+
export { listWorkspaceProjects };
|
|
13
|
+
export type { WorkspaceProjectListItem } from "./workspace-project-db";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* 删除 IndexedDB 中保存的单个工作区(及其 localStorage 预览标记)。
|
|
17
|
+
* `nameSpace` 需与 `ReactViewPanel` 的 `nameSpace` 一致;已挂载的面板会自动刷新工作区列表。
|
|
18
|
+
*/
|
|
19
|
+
export async function deleteWorkspaceProject(
|
|
20
|
+
id: string,
|
|
21
|
+
nameSpace?: string | null
|
|
22
|
+
): Promise<void> {
|
|
23
|
+
await deleteWorkspaceProjectRecord(id, nameSpace);
|
|
24
|
+
removeWorkspacePreviewCache(id, nameSpace);
|
|
25
|
+
broadcastWorkspaceProjectsChanged({ type: "deleted", projectIds: [id] }, nameSpace);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* 清空该 `nameSpace` 下保存的全部工作区,返回删除的数量。
|
|
30
|
+
* 不影响蓝图库、执行日志、接口集合等其他存储。
|
|
31
|
+
*/
|
|
32
|
+
export async function clearWorkspaceProjects(nameSpace?: string | null): Promise<number> {
|
|
33
|
+
const items = await listWorkspaceProjects(nameSpace);
|
|
34
|
+
await clearWorkspaceProjectStore(nameSpace);
|
|
35
|
+
clearWorkspacePreviewCaches(nameSpace);
|
|
36
|
+
broadcastWorkspaceProjectsChanged({ type: "cleared" }, nameSpace);
|
|
37
|
+
return items.length;
|
|
38
|
+
}
|