@rexvane/piweb 0.3.16 → 0.3.17
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/.next/BUILD_ID +1 -1
- package/.next/app-path-routes-manifest.json +8 -11
- package/.next/build-manifest.json +3 -3
- package/.next/prerender-manifest.json +6 -6
- package/.next/react-loadable-manifest.json +4 -16
- package/.next/required-server-files.js +1 -3
- package/.next/required-server-files.json +1 -3
- package/.next/routes-manifest.json +0 -20
- package/.next/server/app/_global-error/page.js +2 -2
- package/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_global-error.html +1 -1
- package/.next/server/app/_global-error.rsc +1 -1
- package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/_not-found/page.js +1 -1
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_not-found.html +1 -1
- package/.next/server/app/_not-found.rsc +4 -7
- package/.next/server/app/_not-found.segments/_full.segment.rsc +4 -7
- package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -5
- package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -5
- package/.next/server/app/api/agent/[id]/events/route.js +2 -2
- package/.next/server/app/api/agent/[id]/events/route.js.nft.json +1 -1
- package/.next/server/app/api/agent/[id]/route.js +1 -1
- package/.next/server/app/api/agent/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/agent/[id]/tree/route.js +1 -1
- package/.next/server/app/api/agent/[id]/tree/route.js.nft.json +1 -1
- package/.next/server/app/api/agent/new/route.js +1 -1
- package/.next/server/app/api/agent/new/route.js.nft.json +1 -1
- package/.next/server/app/api/config/route.js +1 -1
- package/.next/server/app/api/config/route.js.nft.json +1 -1
- package/.next/server/app/api/files/route.js +1 -1
- package/.next/server/app/api/files/route.js.nft.json +1 -1
- package/.next/server/app/api/git/route.js +2 -2
- package/.next/server/app/api/git/route.js.nft.json +1 -1
- package/.next/server/app/api/growth/route.js +1 -1
- package/.next/server/app/api/growth/route.js.nft.json +1 -1
- package/.next/server/app/api/health/route.js +1 -1
- package/.next/server/app/api/models/route.js +1 -1
- package/.next/server/app/api/models/route.js.nft.json +1 -1
- package/.next/server/app/api/pi-settings/route.js +1 -1
- package/.next/server/app/api/pi-settings/route.js.nft.json +1 -1
- package/.next/server/app/api/plugins/route.js +1 -1
- package/.next/server/app/api/plugins/route.js.nft.json +1 -1
- package/.next/server/app/api/prompts/route.js +1 -1
- package/.next/server/app/api/prompts/route.js.nft.json +1 -1
- package/.next/server/app/api/security/route.js +1 -1
- package/.next/server/app/api/security/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/[id]/export/route.js +1 -1
- package/.next/server/app/api/sessions/[id]/export/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/[id]/route.js +1 -1
- package/.next/server/app/api/sessions/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/import/route.js +3 -3
- package/.next/server/app/api/sessions/import/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/route.js +1 -1
- package/.next/server/app/api/sessions/route.js.nft.json +1 -1
- package/.next/server/app/api/skills/route.js +2 -2
- package/.next/server/app/api/skills/route.js.nft.json +1 -1
- package/.next/server/app/api/update/route.js +2 -2
- package/.next/server/app/api/update/route.js.nft.json +1 -1
- package/.next/server/app/api/version/route.js +1 -1
- package/.next/server/app/api/version/route.js.nft.json +1 -1
- package/.next/server/app/api/web-auth/route.js +1 -1
- package/.next/server/app/api/workspaces/route.js +1 -1
- package/.next/server/app/api/workspaces/route.js.nft.json +1 -1
- package/.next/server/app/icon.svg/route.js +1 -1
- package/.next/server/app/index.html +1 -1
- package/.next/server/app/index.rsc +6 -9
- package/.next/server/app/index.segments/__PAGE__.segment.rsc +4 -7
- package/.next/server/app/index.segments/_full.segment.rsc +6 -9
- package/.next/server/app/index.segments/_tree.segment.rsc +2 -5
- package/.next/server/app/login/page.js +1 -1
- package/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/.next/server/app/login.html +1 -1
- package/.next/server/app/login.rsc +5 -8
- package/.next/server/app/login.segments/_full.segment.rsc +5 -8
- package/.next/server/app/login.segments/_tree.segment.rsc +2 -5
- package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +3 -6
- package/.next/server/app/page.js +1 -1
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app-paths-manifest.json +8 -11
- package/.next/server/chunks/496.js +1 -1
- package/.next/server/chunks/532.js +1 -1
- package/.next/server/chunks/686.js +4 -8
- package/.next/server/middleware-build-manifest.js +1 -1
- package/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/.next/server/pages/404.html +1 -1
- package/.next/server/pages/500.html +1 -1
- package/.next/server/server-reference-manifest.json +1 -1
- package/.next/static/chunks/2608.ec8ff1f5767c9056.js +1 -0
- package/.next/static/chunks/2716.93be8ad5c970c516.js +1 -0
- package/.next/static/chunks/4632.112d2e893d48d188.js +1 -0
- package/.next/static/chunks/4673.c1fb1580efc6ace7.js +1 -0
- package/.next/static/chunks/4686-f4a037d609cea3f2.js +1 -0
- package/.next/static/chunks/app/_global-error/page-f77e9ede9808b18e.js +1 -0
- package/.next/static/chunks/app/api/agent/[id]/events/route-f77e9ede9808b18e.js +1 -0
- package/.next/static/chunks/app/api/agent/[id]/route-f77e9ede9808b18e.js +1 -0
- package/.next/static/chunks/app/api/agent/[id]/tree/route-f77e9ede9808b18e.js +1 -0
- package/.next/static/chunks/app/api/agent/new/route-f77e9ede9808b18e.js +1 -0
- package/.next/static/chunks/app/api/config/route-f77e9ede9808b18e.js +1 -0
- package/.next/static/chunks/app/api/files/route-f77e9ede9808b18e.js +1 -0
- package/.next/static/chunks/app/api/git/route-f77e9ede9808b18e.js +1 -0
- package/.next/static/chunks/app/api/growth/route-f77e9ede9808b18e.js +1 -0
- package/.next/static/chunks/app/api/health/route-f77e9ede9808b18e.js +1 -0
- package/.next/static/chunks/app/api/models/route-f77e9ede9808b18e.js +1 -0
- package/.next/static/chunks/app/api/pi-settings/route-f77e9ede9808b18e.js +1 -0
- package/.next/static/chunks/app/api/plugins/route-f77e9ede9808b18e.js +1 -0
- package/.next/static/chunks/app/api/prompts/route-f77e9ede9808b18e.js +1 -0
- package/.next/static/chunks/app/api/security/route-f77e9ede9808b18e.js +1 -0
- package/.next/static/chunks/app/api/sessions/[id]/export/route-f77e9ede9808b18e.js +1 -0
- package/.next/static/chunks/app/api/sessions/[id]/route-f77e9ede9808b18e.js +1 -0
- package/.next/static/chunks/app/api/sessions/import/route-f77e9ede9808b18e.js +1 -0
- package/.next/static/chunks/app/api/sessions/route-f77e9ede9808b18e.js +1 -0
- package/.next/static/chunks/app/api/skills/route-f77e9ede9808b18e.js +1 -0
- package/.next/static/chunks/app/api/update/route-f77e9ede9808b18e.js +1 -0
- package/.next/static/chunks/app/api/version/route-f77e9ede9808b18e.js +1 -0
- package/.next/static/chunks/app/api/web-auth/route-f77e9ede9808b18e.js +1 -0
- package/.next/static/chunks/app/api/workspaces/route-f77e9ede9808b18e.js +1 -0
- package/.next/static/chunks/app/page-b51087831582ee37.js +1 -0
- package/.next/static/chunks/next/dist/client/components/builtin/app-error-f77e9ede9808b18e.js +1 -0
- package/.next/static/chunks/next/dist/client/components/builtin/forbidden-f77e9ede9808b18e.js +1 -0
- package/.next/static/chunks/next/dist/client/components/builtin/not-found-f77e9ede9808b18e.js +1 -0
- package/.next/static/chunks/next/dist/client/components/builtin/unauthorized-f77e9ede9808b18e.js +1 -0
- package/.next/static/chunks/webpack-c31263fd83d75ce6.js +1 -0
- package/.next/static/css/850c2fd130ffa2fc.css +1 -0
- package/.next/static/zsynuO_9Kx6nrXgkTUJ04/_buildManifest.js +1 -0
- package/.next/types/routes.d.ts +1 -4
- package/.next/types/validator.ts +0 -27
- package/README.md +17 -29
- package/assets/archive.jpg +0 -0
- package/assets/growth-1.jpg +0 -0
- package/assets/growth-2.jpg +0 -0
- package/assets/import.jpg +0 -0
- package/assets/main.jpg +0 -0
- package/assets/outline.jpg +0 -0
- package/assets/prompts-1.jpg +0 -0
- package/assets/prompts-2.jpg +0 -0
- package/assets/providers-1.jpg +0 -0
- package/assets/providers-2.jpg +0 -0
- package/assets/providers-3.jpg +0 -0
- package/assets/trace-1.jpg +0 -0
- package/assets/trace-2.png +0 -0
- package/assets/trace-3.png +0 -0
- package/assets/trace-4.png +0 -0
- package/assets/viewer-1.jpg +0 -0
- package/assets/viewer-2.jpg +0 -0
- package/bin/pi.js +50 -0
- package/next.config.ts +32 -7
- package/package.json +4 -9
- package/scripts/launcher.mjs +1 -1
- package/scripts/pick-folder.ps1 +2 -11
- package/scripts/release.mjs +31 -11
- package/scripts/verify-package.mjs +0 -53
- package/src/app/api/config/route.ts +1 -4
- package/src/app/api/growth/route.ts +14 -14
- package/src/app/api/models/route.ts +2 -1
- package/src/app/api/security/route.ts +3 -8
- package/src/app/api/update/route.ts +2 -8
- package/src/app/globals.css +90 -777
- package/src/app/layout.tsx +6 -13
- package/src/components/AppShell.tsx +229 -521
- package/src/components/ChatInput.tsx +26 -153
- package/src/components/ChatWindow.tsx +231 -51
- package/src/components/ContextMeter.tsx +17 -11
- package/src/components/FileViewer.tsx +11 -10
- package/src/components/GitPanel.tsx +11 -13
- package/src/components/ModelSelector.tsx +6 -19
- package/src/components/PiMark.tsx +38 -5
- package/src/components/ProjectPanel.tsx +111 -95
- package/src/components/PromptPanel.tsx +51 -132
- package/src/components/SessionImportSection.tsx +37 -53
- package/src/components/SessionSidebar.tsx +57 -159
- package/src/components/SettingsPanel.tsx +193 -330
- package/src/components/icons.tsx +0 -23
- package/src/hooks/useGrowth.ts +123 -156
- package/src/hooks/usePiWeb.ts +15 -122
- package/src/i18n.tsx +42 -98
- package/src/lib/agent-manager.ts +21 -187
- package/src/lib/command-validation.ts +1 -9
- package/src/lib/growth-service.ts +390 -166
- package/src/lib/growth-tracker.ts +64 -264
- package/src/lib/growth-turns.ts +31 -1
- package/src/lib/models/model-scope.ts +15 -0
- package/src/lib/models-service.ts +16 -0
- package/src/lib/pi-settings.ts +7 -0
- package/src/lib/pi.ts +2 -3
- package/src/lib/session-import/claude.ts +2 -13
- package/src/lib/session-import/codex.ts +8 -44
- package/src/lib/session-import/files.ts +0 -14
- package/src/lib/session-import/grok.ts +24 -54
- package/src/lib/session-import/index.ts +0 -5
- package/src/lib/session-import/types.ts +0 -12
- package/src/lib/session-import/writer.ts +3 -8
- package/src/lib/skills-service.ts +9 -16
- package/src/lib/theme.ts +1 -68
- package/src/lib/trajectory.ts +0 -1
- package/src/lib/types.ts +27 -36
- package/tsconfig.json +2 -1
- package/.next/server/app/api/swarm/[id]/route.js +0 -1
- package/.next/server/app/api/swarm/[id]/route.js.nft.json +0 -1
- package/.next/server/app/api/swarm/[id]/route_client-reference-manifest.js +0 -1
- package/.next/server/app/api/swarm/route.js +0 -1
- package/.next/server/app/api/swarm/route.js.nft.json +0 -1
- package/.next/server/app/api/swarm/route_client-reference-manifest.js +0 -1
- package/.next/server/app/api/tests/route.js +0 -2
- package/.next/server/app/api/tests/route.js.nft.json +0 -1
- package/.next/server/app/api/tests/route_client-reference-manifest.js +0 -1
- package/.next/server/chunks/757.js +0 -1
- package/.next/server/chunks/775.js +0 -3
- package/.next/static/0t1jBUAuVaTFTXxRyIo3q/_buildManifest.js +0 -1
- package/.next/static/chunks/2608.43c58236c9cce8e6.js +0 -1
- package/.next/static/chunks/2716.4ec42df1d51354c9.js +0 -1
- package/.next/static/chunks/4632.62139b565b657aac.js +0 -1
- package/.next/static/chunks/4673.7796104395deb8d7.js +0 -1
- package/.next/static/chunks/4686-17f21a006739a596.js +0 -1
- package/.next/static/chunks/7577.10af9bb661652da8.js +0 -1
- package/.next/static/chunks/8866.38ec4ac4ee5a1b74.js +0 -1
- package/.next/static/chunks/app/_global-error/page-5148173b3f55e415.js +0 -1
- package/.next/static/chunks/app/api/agent/[id]/events/route-5148173b3f55e415.js +0 -1
- package/.next/static/chunks/app/api/agent/[id]/route-5148173b3f55e415.js +0 -1
- package/.next/static/chunks/app/api/agent/[id]/tree/route-5148173b3f55e415.js +0 -1
- package/.next/static/chunks/app/api/agent/new/route-5148173b3f55e415.js +0 -1
- package/.next/static/chunks/app/api/config/route-5148173b3f55e415.js +0 -1
- package/.next/static/chunks/app/api/files/route-5148173b3f55e415.js +0 -1
- package/.next/static/chunks/app/api/git/route-5148173b3f55e415.js +0 -1
- package/.next/static/chunks/app/api/growth/route-5148173b3f55e415.js +0 -1
- package/.next/static/chunks/app/api/health/route-5148173b3f55e415.js +0 -1
- package/.next/static/chunks/app/api/models/route-5148173b3f55e415.js +0 -1
- package/.next/static/chunks/app/api/pi-settings/route-5148173b3f55e415.js +0 -1
- package/.next/static/chunks/app/api/plugins/route-5148173b3f55e415.js +0 -1
- package/.next/static/chunks/app/api/prompts/route-5148173b3f55e415.js +0 -1
- package/.next/static/chunks/app/api/security/route-5148173b3f55e415.js +0 -1
- package/.next/static/chunks/app/api/sessions/[id]/export/route-5148173b3f55e415.js +0 -1
- package/.next/static/chunks/app/api/sessions/[id]/route-5148173b3f55e415.js +0 -1
- package/.next/static/chunks/app/api/sessions/import/route-5148173b3f55e415.js +0 -1
- package/.next/static/chunks/app/api/sessions/route-5148173b3f55e415.js +0 -1
- package/.next/static/chunks/app/api/skills/route-5148173b3f55e415.js +0 -1
- package/.next/static/chunks/app/api/swarm/[id]/route-5148173b3f55e415.js +0 -1
- package/.next/static/chunks/app/api/swarm/route-5148173b3f55e415.js +0 -1
- package/.next/static/chunks/app/api/tests/route-5148173b3f55e415.js +0 -1
- package/.next/static/chunks/app/api/update/route-5148173b3f55e415.js +0 -1
- package/.next/static/chunks/app/api/version/route-5148173b3f55e415.js +0 -1
- package/.next/static/chunks/app/api/web-auth/route-5148173b3f55e415.js +0 -1
- package/.next/static/chunks/app/api/workspaces/route-5148173b3f55e415.js +0 -1
- package/.next/static/chunks/app/page-14379b8060d5cf07.js +0 -1
- package/.next/static/chunks/next/dist/client/components/builtin/app-error-5148173b3f55e415.js +0 -1
- package/.next/static/chunks/next/dist/client/components/builtin/forbidden-5148173b3f55e415.js +0 -1
- package/.next/static/chunks/next/dist/client/components/builtin/not-found-5148173b3f55e415.js +0 -1
- package/.next/static/chunks/next/dist/client/components/builtin/unauthorized-5148173b3f55e415.js +0 -1
- package/.next/static/chunks/webpack-d1a69ad9edb38b11.js +0 -1
- package/.next/static/css/d0a0162cb481abe8.css +0 -1
- package/.next/types/app/api/swarm/[id]/route.ts +0 -353
- package/.next/types/app/api/swarm/route.ts +0 -353
- package/.next/types/app/api/tests/route.ts +0 -353
- package/assets/archive.png +0 -0
- package/assets/growth-1.png +0 -0
- package/assets/growth-2.png +0 -0
- package/assets/import.png +0 -0
- package/assets/main.png +0 -0
- package/assets/outline.png +0 -0
- package/assets/prompts-1.png +0 -0
- package/assets/prompts-2.png +0 -0
- package/assets/providers-1.png +0 -0
- package/assets/providers-2.png +0 -0
- package/assets/providers-3.png +0 -0
- package/assets/trace-1.png +0 -0
- package/assets/viewer-1.png +0 -0
- package/assets/viewer-2.png +0 -0
- package/scripts/managed-niubash-assets.mjs +0 -146
- package/scripts/prepare-niubash-packages.mjs +0 -182
- package/scripts/run-test-file.mjs +0 -34
- package/scripts/smoke-managed-niubash.mjs +0 -62
- package/scripts/verify-release-config.mjs +0 -24
- package/src/app/api/swarm/[id]/route.ts +0 -28
- package/src/app/api/swarm/route.ts +0 -24
- package/src/app/api/tests/route.ts +0 -27
- package/src/components/SwarmCoordinatorPod.tsx +0 -1021
- package/src/components/TestInspectorPod.tsx +0 -549
- package/src/lib/delegation.ts +0 -93
- package/src/lib/growth-rounds.ts +0 -84
- package/src/lib/managed-niubash.ts +0 -231
- package/src/lib/runtime-activity.ts +0 -27
- package/src/lib/session-import/lock.ts +0 -25
- package/src/lib/swarm-service.ts +0 -371
- package/src/lib/test-run-service.ts +0 -122
- package/src/lib/workflow.ts +0 -55
- /package/.next/static/{0t1jBUAuVaTFTXxRyIo3q → zsynuO_9Kx6nrXgkTUJ04}/_ssgManifest.js +0 -0
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* 技能 / 提示模板,含扩展与 npm 包提供的那些);热会话额外给出"组装后的系统提示词"
|
|
7
7
|
* 与每个工具的定义,它们不是文件、没有路径,直接在本面板内展开查看。
|
|
8
8
|
*/
|
|
9
|
-
import { useCallback, useEffect,
|
|
9
|
+
import { useCallback, useEffect, useState } from "react";
|
|
10
10
|
import { useI18n } from "@/i18n";
|
|
11
11
|
import { IconRefreshOutline14, IconCloseOutline14 } from "@/components/icons";
|
|
12
12
|
|
|
@@ -67,46 +67,30 @@ export function PromptPanel({
|
|
|
67
67
|
onClose: () => void;
|
|
68
68
|
}) {
|
|
69
69
|
const { t } = useI18n();
|
|
70
|
-
const
|
|
71
|
-
const [catalog, setCatalog] = useState<{ owner: string; data: PromptSourcesData } | null>(null);
|
|
72
|
-
const data = catalog?.owner === owner ? catalog.data : null;
|
|
70
|
+
const [data, setData] = useState<PromptSourcesData | null>(null);
|
|
73
71
|
const [error, setError] = useState<string | null>(null);
|
|
74
72
|
const [busy, setBusy] = useState(false);
|
|
75
73
|
const [opening, setOpening] = useState<string | null>(null);
|
|
76
|
-
const listRequest = useRef<AbortController | null>(null);
|
|
77
|
-
const readRequest = useRef<AbortController | null>(null);
|
|
78
74
|
|
|
79
75
|
const load = useCallback(async () => {
|
|
80
|
-
listRequest.current?.abort();
|
|
81
|
-
readRequest.current?.abort();
|
|
82
|
-
const controller = new AbortController();
|
|
83
|
-
listRequest.current = controller;
|
|
84
|
-
const current = () => listRequest.current === controller && !controller.signal.aborted;
|
|
85
|
-
setCatalog(null);
|
|
86
|
-
setOpening(null);
|
|
87
76
|
setBusy(true);
|
|
88
77
|
setError(null);
|
|
89
78
|
try {
|
|
90
79
|
const query = new URLSearchParams({ cwd });
|
|
91
80
|
if (sessionId) query.set("session", sessionId);
|
|
92
|
-
const response = await fetch(`/api/prompts?${query.toString()}
|
|
81
|
+
const response = await fetch(`/api/prompts?${query.toString()}`);
|
|
93
82
|
const body = await response.json();
|
|
94
|
-
if (!current()) return;
|
|
95
83
|
if (!response.ok || !body.success) throw new Error(body.error || `request failed (${response.status})`);
|
|
96
|
-
|
|
84
|
+
setData(body.data as PromptSourcesData);
|
|
97
85
|
} catch (err) {
|
|
98
|
-
|
|
86
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
99
87
|
} finally {
|
|
100
|
-
|
|
88
|
+
setBusy(false);
|
|
101
89
|
}
|
|
102
|
-
}, [cwd, sessionId
|
|
90
|
+
}, [cwd, sessionId]);
|
|
103
91
|
|
|
104
92
|
useEffect(() => {
|
|
105
93
|
void load();
|
|
106
|
-
return () => {
|
|
107
|
-
listRequest.current?.abort();
|
|
108
|
-
readRequest.current?.abort();
|
|
109
|
-
};
|
|
110
94
|
}, [load, refreshKey]);
|
|
111
95
|
|
|
112
96
|
const originLabel = (origin: PromptSourceOrigin): string => {
|
|
@@ -131,28 +115,21 @@ export function PromptPanel({
|
|
|
131
115
|
/** 文件类:按需读内容,交给外部查看器 */
|
|
132
116
|
const openFile = async (source: PromptSource) => {
|
|
133
117
|
if (!source.path || !onOpenContent) return;
|
|
134
|
-
readRequest.current?.abort();
|
|
135
|
-
const controller = new AbortController();
|
|
136
|
-
const catalogRequest = listRequest.current;
|
|
137
|
-
readRequest.current = controller;
|
|
138
|
-
const current = () => readRequest.current === controller && !controller.signal.aborted && listRequest.current === catalogRequest;
|
|
139
118
|
setOpening(source.path);
|
|
140
119
|
setError(null);
|
|
141
120
|
try {
|
|
142
121
|
const response = await fetch("/api/prompts", {
|
|
143
122
|
method: "POST",
|
|
144
|
-
signal: controller.signal,
|
|
145
123
|
headers: { "Content-Type": "application/json" },
|
|
146
124
|
body: JSON.stringify({ action: "read", filePath: source.path, cwd }),
|
|
147
125
|
});
|
|
148
126
|
const body = await response.json();
|
|
149
|
-
if (!current()) return;
|
|
150
127
|
if (!response.ok || !body.success) throw new Error(body.error || "read failed");
|
|
151
128
|
onOpenContent(source.path, body.data.content as string);
|
|
152
129
|
} catch (err) {
|
|
153
|
-
|
|
130
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
154
131
|
} finally {
|
|
155
|
-
|
|
132
|
+
setOpening(null);
|
|
156
133
|
}
|
|
157
134
|
};
|
|
158
135
|
|
|
@@ -161,94 +138,50 @@ export function PromptPanel({
|
|
|
161
138
|
);
|
|
162
139
|
const hasTools = (data?.tools?.length ?? 0) > 0;
|
|
163
140
|
|
|
164
|
-
const fileExtBadge = (name: string): string => {
|
|
165
|
-
const ext = name.split(".").pop()?.toUpperCase() ?? "DOC";
|
|
166
|
-
return ext.length <= 4 ? ext : "DOC";
|
|
167
|
-
};
|
|
168
|
-
|
|
169
141
|
return (
|
|
170
|
-
<div className="flex min-h-0 flex-1 flex-col
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
<
|
|
174
|
-
<
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
title={t.promptRefresh}
|
|
182
|
-
aria-label={t.promptRefresh}
|
|
183
|
-
onClick={() => void load()}
|
|
184
|
-
>
|
|
185
|
-
<span className={busy ? "piweb-spin" : undefined} style={{ display: "inline-flex" }}>
|
|
186
|
-
<IconRefreshOutline14 size={13} />
|
|
187
|
-
</span>
|
|
188
|
-
</button>
|
|
189
|
-
<button
|
|
190
|
-
type="button"
|
|
191
|
-
className="w-7 h-7 clay-btn bg-white dark:bg-slate-800 text-slate-700 hover:text-rose-600 dark:text-slate-300 transition-colors shadow-sm"
|
|
192
|
-
title={t.close}
|
|
193
|
-
aria-label={t.close}
|
|
194
|
-
onClick={onClose}
|
|
195
|
-
>
|
|
196
|
-
<IconCloseOutline14 size={13} />
|
|
197
|
-
</button>
|
|
198
|
-
</div>
|
|
142
|
+
<div className="flex min-h-0 flex-1 flex-col">
|
|
143
|
+
<div className="hairline-b flex items-center gap-2 px-4 py-2.5">
|
|
144
|
+
<span className="min-w-0 flex-1 truncate" style={{ fontSize: 13.5, fontWeight: 600 }}>{t.promptPanel}</span>
|
|
145
|
+
<button type="button" className="icon-btn" style={{ width: 26, height: 26 }} title={t.promptRefresh} aria-label={t.promptRefresh} onClick={() => void load()}>
|
|
146
|
+
<span className={busy ? "piweb-spin" : undefined} style={{ display: "inline-flex" }}>
|
|
147
|
+
<IconRefreshOutline14 size={14} />
|
|
148
|
+
</span>
|
|
149
|
+
</button>
|
|
150
|
+
<button type="button" className="icon-btn" style={{ width: 26, height: 26 }} title={t.close} aria-label={t.close} onClick={onClose}>
|
|
151
|
+
<IconCloseOutline14 size={14} />
|
|
152
|
+
</button>
|
|
199
153
|
</div>
|
|
200
|
-
|
|
201
|
-
<div className="min-h-0 flex-1 overflow-y-auto px-1 space-y-4 text-xs">
|
|
154
|
+
<div className="min-h-0 flex-1 overflow-auto px-3 py-3" style={{ fontSize: 12.5 }}>
|
|
202
155
|
{error && (
|
|
203
|
-
<div className="rounded-
|
|
156
|
+
<div className="mb-2 rounded-lg px-2 py-1.5" style={{ background: "var(--dsw-hover)", color: "var(--dsw-danger)" }} role="alert">
|
|
204
157
|
{error}
|
|
205
158
|
</div>
|
|
206
159
|
)}
|
|
207
|
-
|
|
208
|
-
{!data && busy && <div className="text-slate-500 py-4 text-center">{t.promptLoading}</div>}
|
|
209
|
-
|
|
160
|
+
{!data && busy && <div style={{ color: "var(--dsw-label-tertiary)" }}>{t.promptLoading}</div>}
|
|
210
161
|
{data && !data.sessionReady && (
|
|
211
|
-
<div className="rounded-
|
|
162
|
+
<div className="mb-2 rounded-lg px-2 py-1.5" style={{ background: "var(--dsw-hover)", color: "var(--dsw-label-caption)" }} role="status">
|
|
212
163
|
{t.promptColdHint}
|
|
213
164
|
</div>
|
|
214
165
|
)}
|
|
215
166
|
|
|
216
167
|
{groups.map((group) => (
|
|
217
|
-
<section key={group.kind} className="
|
|
218
|
-
<div className="
|
|
219
|
-
|
|
220
|
-
<span className="text-[10px] text-slate-500 dark:text-slate-400 font-mono font-semibold">{group.items.length} 项</span>
|
|
221
|
-
</div>
|
|
222
|
-
<div className="flex flex-col gap-1.5">
|
|
168
|
+
<section key={group.kind} className="mb-3">
|
|
169
|
+
<div className="mb-1 px-1" style={{ fontSize: 11.5, color: "var(--dsw-label-caption)" }}>{kindLabel(group.kind)}</div>
|
|
170
|
+
<div className="flex flex-col gap-1">
|
|
223
171
|
{group.items.map((source) => (
|
|
224
172
|
<button
|
|
225
173
|
key={`${source.kind}:${source.path ?? source.name}`}
|
|
226
174
|
type="button"
|
|
227
|
-
className=
|
|
228
|
-
|
|
229
|
-
}`}
|
|
175
|
+
className="flex w-full items-center gap-2 rounded-lg px-2 py-1.5 text-left"
|
|
176
|
+
style={{ background: opening === source.path ? "var(--dsw-active)" : "transparent", border: "0.5px solid var(--dsw-border-l2)" }}
|
|
230
177
|
title={source.path ?? source.name}
|
|
231
178
|
onClick={() => void openFile(source)}
|
|
232
179
|
>
|
|
233
|
-
<
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
<div className="text-xs font-bold text-slate-900 dark:text-slate-100 truncate">{source.name}</div>
|
|
239
|
-
<div className="text-[11px] text-slate-600 dark:text-slate-400 truncate">{source.path ?? kindLabel(source.kind)}</div>
|
|
240
|
-
</div>
|
|
241
|
-
</div>
|
|
242
|
-
<div className="text-right flex-none flex flex-col items-end gap-0.5">
|
|
243
|
-
{source.bytes !== undefined && (
|
|
244
|
-
<span className="text-[11px] font-mono font-bold text-slate-800 dark:text-slate-200 block">
|
|
245
|
-
{formatBytes(source.bytes)}
|
|
246
|
-
</span>
|
|
247
|
-
)}
|
|
248
|
-
<span className="text-[10px] px-2 py-0.5 rounded-full bg-slate-100 dark:bg-slate-800 text-slate-700 dark:text-slate-300 font-semibold border border-slate-200 dark:border-slate-700">
|
|
249
|
-
{originLabel(source.origin)}
|
|
250
|
-
</span>
|
|
251
|
-
</div>
|
|
180
|
+
<span className="min-w-0 flex-1 truncate" style={{ color: "var(--dsw-label-primary)" }}>{source.name}</span>
|
|
181
|
+
<span className="flex-none" style={{ fontSize: 10.5, color: "var(--dsw-label-tertiary)" }}>{formatBytes(source.bytes)}</span>
|
|
182
|
+
<span className="flex-none rounded-md px-1.5 py-0.5" style={{ fontSize: 10.5, border: "0.5px solid var(--dsw-border-l3)", color: "var(--dsw-label-tertiary)" }}>
|
|
183
|
+
{originLabel(source.origin)}
|
|
184
|
+
</span>
|
|
252
185
|
</button>
|
|
253
186
|
))}
|
|
254
187
|
</div>
|
|
@@ -256,17 +189,15 @@ export function PromptPanel({
|
|
|
256
189
|
))}
|
|
257
190
|
|
|
258
191
|
{hasTools && (
|
|
259
|
-
<section className="
|
|
260
|
-
<div className="
|
|
261
|
-
|
|
262
|
-
<span className="text-[10px] text-slate-500 dark:text-slate-400 font-mono font-semibold">{data!.tools!.length} 个工具</span>
|
|
263
|
-
</div>
|
|
264
|
-
<div className="flex flex-col gap-1.5">
|
|
192
|
+
<section className="mb-3">
|
|
193
|
+
<div className="mb-1 px-1" style={{ fontSize: 11.5, color: "var(--dsw-label-caption)" }}>{t.promptKindTool}</div>
|
|
194
|
+
<div className="flex flex-col gap-1">
|
|
265
195
|
{data!.tools!.map((tool) => (
|
|
266
196
|
<button
|
|
267
197
|
key={`tool:${tool.name}`}
|
|
268
198
|
type="button"
|
|
269
|
-
className="
|
|
199
|
+
className="flex w-full items-center gap-2 rounded-lg px-2 py-1.5 text-left"
|
|
200
|
+
style={{ border: "0.5px solid var(--dsw-border-l2)" }}
|
|
270
201
|
title={tool.name}
|
|
271
202
|
onClick={() =>
|
|
272
203
|
onOpenContent?.(
|
|
@@ -283,16 +214,8 @@ export function PromptPanel({
|
|
|
283
214
|
)
|
|
284
215
|
}
|
|
285
216
|
>
|
|
286
|
-
<
|
|
287
|
-
|
|
288
|
-
TOOL
|
|
289
|
-
</div>
|
|
290
|
-
<div className="min-w-0 flex-1">
|
|
291
|
-
<div className="text-xs font-bold text-slate-900 dark:text-slate-100 truncate">{tool.name}</div>
|
|
292
|
-
<div className="text-[11px] text-slate-600 dark:text-slate-400 truncate">{tool.description || t.promptKindTool}</div>
|
|
293
|
-
</div>
|
|
294
|
-
</div>
|
|
295
|
-
<span className="text-[10px] px-2 py-0.5 rounded-full bg-slate-100 dark:bg-slate-800 text-slate-700 dark:text-slate-300 font-semibold border border-slate-200 dark:border-slate-700 flex-none">
|
|
217
|
+
<span className="min-w-0 flex-1 truncate" style={{ color: "var(--dsw-label-primary)" }}>{tool.name}</span>
|
|
218
|
+
<span className="flex-none rounded-md px-1.5 py-0.5" style={{ fontSize: 10.5, border: "0.5px solid var(--dsw-border-l3)", color: "var(--dsw-label-tertiary)" }}>
|
|
296
219
|
{tool.source === "builtin" ? t.promptToolBuiltin : t.promptToolExtension}
|
|
297
220
|
</span>
|
|
298
221
|
</button>
|
|
@@ -302,35 +225,31 @@ export function PromptPanel({
|
|
|
302
225
|
)}
|
|
303
226
|
|
|
304
227
|
{data?.assembledSystemPrompt && (
|
|
305
|
-
<section className="
|
|
306
|
-
<div className="
|
|
228
|
+
<section className="mb-3">
|
|
229
|
+
<div className="mb-1 px-1" style={{ fontSize: 11.5, color: "var(--dsw-label-caption)" }}>{t.promptKindAssembled}</div>
|
|
307
230
|
<button
|
|
308
231
|
type="button"
|
|
309
|
-
className="w-full
|
|
232
|
+
className="w-full rounded-lg px-2 py-1.5 text-left"
|
|
233
|
+
style={{ border: "0.5px solid var(--dsw-border-l2)" }}
|
|
310
234
|
title={t.promptAssembledKey}
|
|
311
235
|
onClick={() => onOpenContent?.("system-prompt.md", data.assembledSystemPrompt ?? "")}
|
|
312
236
|
>
|
|
313
|
-
<
|
|
314
|
-
π
|
|
315
|
-
</div>
|
|
316
|
-
<span className="truncate font-bold text-slate-900 dark:text-slate-100 text-xs">{t.promptAssembledKey}</span>
|
|
237
|
+
<span className="truncate" style={{ color: "var(--dsw-label-primary)" }}>{t.promptAssembledKey}</span>
|
|
317
238
|
</button>
|
|
318
239
|
</section>
|
|
319
240
|
)}
|
|
320
241
|
|
|
321
242
|
{data?.compactedSummary && (
|
|
322
|
-
<section className="
|
|
323
|
-
<div className="
|
|
243
|
+
<section className="mb-3">
|
|
244
|
+
<div className="mb-1 px-1" style={{ fontSize: 11.5, color: "var(--dsw-label-caption)" }}>{t.promptKindCompacted}</div>
|
|
324
245
|
<button
|
|
325
246
|
type="button"
|
|
326
|
-
className="w-full
|
|
247
|
+
className="w-full rounded-lg px-2 py-1.5 text-left"
|
|
248
|
+
style={{ border: "0.5px solid var(--dsw-border-l2)" }}
|
|
327
249
|
title={t.promptCompactedKey}
|
|
328
250
|
onClick={() => onOpenContent?.("compacted-summary.md", data.compactedSummary ?? "")}
|
|
329
251
|
>
|
|
330
|
-
<
|
|
331
|
-
SUM
|
|
332
|
-
</div>
|
|
333
|
-
<span className="truncate font-bold text-slate-900 dark:text-slate-100 text-xs">{t.promptCompactedKey}</span>
|
|
252
|
+
<span className="truncate" style={{ color: "var(--dsw-label-primary)" }}>{t.promptCompactedKey}</span>
|
|
334
253
|
</button>
|
|
335
254
|
</section>
|
|
336
255
|
)}
|
|
@@ -36,8 +36,6 @@ interface ImportOutcome {
|
|
|
36
36
|
reason?: string;
|
|
37
37
|
messageCount?: number;
|
|
38
38
|
workspace?: string;
|
|
39
|
-
/** 已成功导入,但源里的运行时注入/加密内容等无法作为对话还原 */
|
|
40
|
-
skipped?: string[];
|
|
41
39
|
}
|
|
42
40
|
|
|
43
41
|
interface ImportReport {
|
|
@@ -62,8 +60,6 @@ function dayOf(ms?: number): string {
|
|
|
62
60
|
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
|
|
63
61
|
}
|
|
64
62
|
|
|
65
|
-
const summaryKey = (summary: Pick<Summary, "source" | "externalId">) => `${summary.source}:${summary.externalId}`;
|
|
66
|
-
|
|
67
63
|
export function SessionImportSection({ cwd }: { cwd: string }) {
|
|
68
64
|
const { t } = useI18n();
|
|
69
65
|
const [summaries, setSummaries] = useState<Summary[]>([]);
|
|
@@ -87,14 +83,9 @@ export function SessionImportSection({ cwd }: { cwd: string }) {
|
|
|
87
83
|
setFailure(json.error || t.toastError);
|
|
88
84
|
return;
|
|
89
85
|
}
|
|
90
|
-
|
|
91
|
-
const nextImported = new Set<string>(json.data.imported ?? []);
|
|
92
|
-
const selectable = new Set(nextSummaries.map(summaryKey));
|
|
93
|
-
setSummaries(nextSummaries);
|
|
86
|
+
setSummaries(json.data.sessions ?? []);
|
|
94
87
|
setErrors(json.data.errors ?? []);
|
|
95
|
-
setImportedKeys(
|
|
96
|
-
// 重新扫描后,源会话可能已经消失或被另一个请求导入;不要留下幽灵选择
|
|
97
|
-
setSelected((previous) => new Set([...previous].filter((item) => selectable.has(item) && !nextImported.has(item))));
|
|
88
|
+
setImportedKeys(new Set<string>(json.data.imported ?? []));
|
|
98
89
|
} catch (error) {
|
|
99
90
|
setFailure(error instanceof Error ? error.message : String(error));
|
|
100
91
|
} finally {
|
|
@@ -118,6 +109,8 @@ export function SessionImportSection({ cwd }: { cwd: string }) {
|
|
|
118
109
|
void scan();
|
|
119
110
|
}, [scan]);
|
|
120
111
|
|
|
112
|
+
const key = (summary: Summary) => `${summary.source}:${summary.externalId}`;
|
|
113
|
+
|
|
121
114
|
const groups = useMemo(() => {
|
|
122
115
|
const bySource = new Map<string, Summary[]>();
|
|
123
116
|
for (const summary of summaries) {
|
|
@@ -127,30 +120,27 @@ export function SessionImportSection({ cwd }: { cwd: string }) {
|
|
|
127
120
|
}
|
|
128
121
|
return SOURCE_ORDER.filter((source) => bySource.has(source)).map((source) => {
|
|
129
122
|
const rows = [...(bySource.get(source) as Summary[])].sort((left, right) => (right.updatedAt ?? right.createdAt ?? 0) - (left.updatedAt ?? left.createdAt ?? 0));
|
|
130
|
-
return { source, rows, imported: rows.filter((row) => importedKeys.has(
|
|
123
|
+
return { source, rows, imported: rows.filter((row) => importedKeys.has(key(row))).length };
|
|
131
124
|
});
|
|
132
125
|
}, [summaries, importedKeys]);
|
|
133
126
|
|
|
134
127
|
/**
|
|
135
128
|
* 一次只显示一个来源:六个工具各列 15 条就是 90 行,全铺出来既难找也没必要。
|
|
136
|
-
*
|
|
137
|
-
* 直接派生有效来源,不用 effect 回填,避免初始化 effect 覆盖用户刚完成的点击。
|
|
129
|
+
* 默认落在第一个有会话的来源上(SOURCE_ORDER 的顺序),用户切换后不被扫描结果重置。
|
|
138
130
|
*/
|
|
139
131
|
const [activeSource, setActiveSource] = useState("");
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
const visibleSource = activeSource && groups.some((group) => group.source === activeSource) ? activeSource : defaultSource;
|
|
146
|
-
const activeGroup = groups.find((group) => group.source === visibleSource);
|
|
132
|
+
useEffect(() => {
|
|
133
|
+
if (activeSource && groups.some((group) => group.source === activeSource)) return;
|
|
134
|
+
setActiveSource(groups[0]?.source ?? "");
|
|
135
|
+
}, [groups, activeSource]);
|
|
136
|
+
const activeGroup = groups.find((group) => group.source === activeSource);
|
|
147
137
|
|
|
148
138
|
const toggle = (summary: Summary) => {
|
|
149
|
-
if (importedKeys.has(
|
|
139
|
+
if (importedKeys.has(key(summary))) return;
|
|
150
140
|
setSelected((previous) => {
|
|
151
141
|
const next = new Set(previous);
|
|
152
|
-
if (next.has(
|
|
153
|
-
else next.add(
|
|
142
|
+
if (next.has(key(summary))) next.delete(key(summary));
|
|
143
|
+
else next.add(key(summary));
|
|
154
144
|
return next;
|
|
155
145
|
});
|
|
156
146
|
};
|
|
@@ -159,9 +149,9 @@ export function SessionImportSection({ cwd }: { cwd: string }) {
|
|
|
159
149
|
setSelected((previous) => {
|
|
160
150
|
const next = new Set(previous);
|
|
161
151
|
for (const row of rows) {
|
|
162
|
-
if (importedKeys.has(
|
|
163
|
-
if (checked) next.add(
|
|
164
|
-
else next.delete(
|
|
152
|
+
if (importedKeys.has(key(row))) continue;
|
|
153
|
+
if (checked) next.add(key(row));
|
|
154
|
+
else next.delete(key(row));
|
|
165
155
|
}
|
|
166
156
|
return next;
|
|
167
157
|
});
|
|
@@ -169,7 +159,7 @@ export function SessionImportSection({ cwd }: { cwd: string }) {
|
|
|
169
159
|
|
|
170
160
|
const run = async () => {
|
|
171
161
|
if (!selected.size) return;
|
|
172
|
-
const items = summaries.filter((summary) => selected.has(
|
|
162
|
+
const items = summaries.filter((summary) => selected.has(key(summary))).map((summary) => ({ source: summary.source, externalId: summary.externalId }));
|
|
173
163
|
setImporting(true);
|
|
174
164
|
setFailure(null);
|
|
175
165
|
setReport(null);
|
|
@@ -208,7 +198,6 @@ export function SessionImportSection({ cwd }: { cwd: string }) {
|
|
|
208
198
|
|
|
209
199
|
const failures = report?.results.filter((result) => result.status === "failed") ?? [];
|
|
210
200
|
const skipped = report?.results.filter((result) => result.status === "skipped") ?? [];
|
|
211
|
-
const importedWithNotes = report?.results.filter((result) => result.status === "imported" && result.skipped?.length) ?? [];
|
|
212
201
|
|
|
213
202
|
return (
|
|
214
203
|
<div className="flex flex-col gap-4" data-testid="session-import">
|
|
@@ -288,11 +277,6 @@ export function SessionImportSection({ cwd }: { cwd: string }) {
|
|
|
288
277
|
{sourceLabel(result.source)} · {result.title || result.externalId} — {result.reason}
|
|
289
278
|
</div>
|
|
290
279
|
))}
|
|
291
|
-
{importedWithNotes.map((result) => (
|
|
292
|
-
<div key={`note-${result.source}-${result.externalId}`} className="mt-1" style={{ fontSize: 11.5, color: "var(--dsw-label-caption)" }}>
|
|
293
|
-
{sourceLabel(result.source)} · {result.title || result.externalId} — {result.skipped?.join(";")}
|
|
294
|
-
</div>
|
|
295
|
-
))}
|
|
296
280
|
{failures.map((result) => (
|
|
297
281
|
<div key={`fail-${result.source}-${result.externalId}`} className="mt-1" style={{ fontSize: 11.5, color: "var(--dsw-danger)" }}>
|
|
298
282
|
{sourceLabel(result.source)} · {result.title || result.externalId} — {result.reason}
|
|
@@ -305,25 +289,27 @@ export function SessionImportSection({ cwd }: { cwd: string }) {
|
|
|
305
289
|
|
|
306
290
|
{/* 来源选择器:选中哪个就只列哪个工具的会话 */}
|
|
307
291
|
{groups.length > 0 && (
|
|
308
|
-
<div className="flex flex-wrap items-center gap-
|
|
292
|
+
<div className="flex flex-wrap items-center gap-1.5" role="tablist" aria-label={t.importPickSource} data-testid="import-source-tabs">
|
|
309
293
|
{groups.map((group) => {
|
|
310
|
-
const active = group.source ===
|
|
294
|
+
const active = group.source === activeSource;
|
|
311
295
|
return (
|
|
312
296
|
<button
|
|
313
297
|
key={group.source}
|
|
314
298
|
type="button"
|
|
315
299
|
role="tab"
|
|
316
300
|
aria-selected={active}
|
|
317
|
-
className=
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
301
|
+
className="rounded-full px-3 py-1 transition-colors"
|
|
302
|
+
style={{
|
|
303
|
+
fontSize: 12,
|
|
304
|
+
border: `0.5px solid ${active ? "var(--dsw-accent)" : "var(--dsw-border-l2)"}`,
|
|
305
|
+
background: active ? "var(--dsw-accent)" : "transparent",
|
|
306
|
+
color: active ? "#fff" : "var(--dsw-label-tertiary)",
|
|
307
|
+
}}
|
|
322
308
|
onClick={() => setActiveSource(group.source)}
|
|
323
309
|
data-testid={`import-source-${group.source}`}
|
|
324
310
|
>
|
|
325
|
-
|
|
326
|
-
<span
|
|
311
|
+
{sourceLabel(group.source)}
|
|
312
|
+
<span style={{ marginLeft: 6, opacity: 0.75 }}>{group.rows.length}</span>
|
|
327
313
|
</button>
|
|
328
314
|
);
|
|
329
315
|
})}
|
|
@@ -337,37 +323,35 @@ export function SessionImportSection({ cwd }: { cwd: string }) {
|
|
|
337
323
|
{t.importGroupCount.replace("{n}", String(activeGroup.rows.length)).replace("{imported}", String(activeGroup.imported))}
|
|
338
324
|
</span>
|
|
339
325
|
<div className="flex-1" />
|
|
340
|
-
<button className="
|
|
326
|
+
<button className="rounded-lg px-2 py-0.5" style={{ fontSize: 11.5, color: "var(--dsw-label-tertiary)" }} onClick={() => selectGroup(activeGroup.rows, true)}>
|
|
341
327
|
{t.importSelectAll}
|
|
342
328
|
</button>
|
|
343
|
-
<button className="
|
|
329
|
+
<button className="rounded-lg px-2 py-0.5" style={{ fontSize: 11.5, color: "var(--dsw-label-caption)" }} onClick={() => selectGroup(activeGroup.rows, false)}>
|
|
344
330
|
{t.importSelectNone}
|
|
345
331
|
</button>
|
|
346
332
|
</div>
|
|
347
333
|
<div className="flex flex-col gap-1.5">
|
|
348
334
|
{activeGroup.rows.map((row) => {
|
|
349
|
-
const rowKey =
|
|
335
|
+
const rowKey = key(row);
|
|
350
336
|
const done = importedKeys.has(rowKey);
|
|
351
337
|
const checked = selected.has(rowKey);
|
|
352
338
|
return (
|
|
353
339
|
<label
|
|
354
340
|
key={rowKey}
|
|
355
|
-
className=
|
|
356
|
-
|
|
357
|
-
}`}
|
|
358
|
-
style={{ opacity: done ? 0.55 : 1 }}
|
|
341
|
+
className="flex cursor-pointer items-center gap-3 rounded-xl px-3 py-2"
|
|
342
|
+
style={{ border: `0.5px solid ${checked ? "var(--dsw-accent)" : "var(--dsw-border-l2)"}`, opacity: done ? 0.55 : 1 }}
|
|
359
343
|
>
|
|
360
344
|
<input type="checkbox" checked={checked} disabled={done} onChange={() => toggle(row)} />
|
|
361
345
|
<div className="min-w-0 flex-1">
|
|
362
|
-
<div className="truncate
|
|
346
|
+
<div className="truncate" style={{ fontSize: 12.5 }} title={row.title}>
|
|
363
347
|
{row.title || t.importUntitled}
|
|
364
348
|
</div>
|
|
365
|
-
<div className="truncate
|
|
349
|
+
<div className="truncate" style={{ fontSize: 11, color: "var(--dsw-label-caption)" }} title={row.projectPath}>
|
|
366
350
|
{row.projectPath || t.importNoProject}
|
|
367
351
|
</div>
|
|
368
352
|
</div>
|
|
369
353
|
{done && (
|
|
370
|
-
<span className="
|
|
354
|
+
<span className="rounded-full px-2 py-0.5" style={{ fontSize: 10, background: "var(--dsw-hover)", color: "var(--dsw-label-caption)" }}>
|
|
371
355
|
{t.importAlready}
|
|
372
356
|
</span>
|
|
373
357
|
)}
|