@jetcrab/pi-desk 1.1.1 → 1.1.5-dev
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/docs/pi-desk/README.md +47 -0
- package/docs/pi-desk/commands.md +76 -0
- package/docs/pi-desk/examples/local-application/browser/application.js +106 -0
- package/docs/pi-desk/examples/local-application/browser/entry.js +9 -0
- package/docs/pi-desk/examples/local-application/package.json +9 -0
- package/docs/pi-desk/examples/local-application/pi-desk.ts +11 -0
- package/docs/pi-desk/plugins.md +119 -0
- package/package.json +3 -2
- package/src/client/l2_biz/pi-settings/hooks/l2-use-pi-settings.ts +37 -21
- package/src/client/l2_biz/pi-settings/l2-pi-settings.tsx +37 -43
- package/src/client/l2_biz/pi-settings/views/l2-mcp-settings-editor.tsx +3 -1
- package/src/client/l2_biz/pi-settings/views/l2-mcp-settings-list.tsx +1 -1
- package/src/client/l2_biz/plugin-host/hooks/l2-use-plugin-catalog.ts +3 -1
- package/src/client/l2_biz/plugin-host/hooks/l2-use-plugin-download-source.ts +5 -1
- package/src/client/l2_biz/plugin-host/l2-plugin-capability-details.tsx +57 -41
- package/src/client/l2_biz/plugin-host/l2-plugin-management-controls.tsx +89 -116
- package/src/client/l2_biz/plugin-host/l2-plugin-management.tsx +492 -338
- package/src/client/l2_biz/plugin-host/l2-use-plugin-management.ts +72 -22
- package/src/client/l2_biz/plugin-host/views/l2-plugin-catalog-detail.tsx +104 -76
- package/src/client/l2_biz/plugin-host/views/l2-plugin-catalog-search.tsx +101 -56
- package/src/client/l2_biz/plugin-host/views/l2-plugin-direct-install.tsx +91 -59
- package/src/client/l2_biz/plugin-host/views/l2-plugin-download-source.tsx +36 -27
- package/src/client/l2_biz/plugin-host/views/l2-plugin-installed-list.tsx +218 -208
- package/src/client/l2_biz/plugin-host/views/l2-plugin-management-channel.tsx +12 -5
- package/src/client/l2_biz/plugin-host/views/l2-plugin-management-dialog.tsx +84 -106
- package/src/client/l2_biz/plugin-host/views/l2-plugin-readme.tsx +29 -15
- package/src/client/l2_biz/settings/hooks/l2-use-project-model-default-settings.ts +22 -11
- package/src/client/l2_biz/settings/l2-settings.tsx +6 -11
- package/src/client/l2_biz/settings/views/l2-project-model-default-settings.tsx +20 -14
- package/src/client/l2_biz/terminal/l2-terminal-workspace.tsx +35 -1
- package/src/client/l2_biz/workbench/file-workspace/l2-work-session-file-preview.tsx +6 -2
- package/src/client/l2_biz/workbench/hooks/l2-workbench-chat-viewport.ts +14 -1
- package/src/client/l2_biz/workbench/l2-workbench-branch-picker.tsx +33 -5
- package/src/client/l2_biz/workbench/l2-workbench-sidebar-layout.tsx +3 -1
- package/src/client/l2_biz/workbench/l2-workbench.tsx +20 -3
- package/src/client/l3_modules/conversation/l3-conversation-call-summary.tsx +0 -3
- package/src/client/l3_modules/project-files/l3-file-context-menu-content.tsx +1 -0
- package/src/client/l4_foundation/ui/l4-app-dialog.tsx +3 -1
- package/src/client/l4_foundation/ui/l4-image-viewer.tsx +21 -0
- package/src/client/l4_foundation/ui/shadcn/checkbox.tsx +27 -0
- package/src/client/l4_foundation/ui/shadcn/context-menu.tsx +8 -1
- package/src/client/l4_foundation/ui/shadcn/dropdown-menu.tsx +5 -0
- package/src/client/l4_foundation/ui/shadcn/popover.tsx +2 -0
- package/src/client/l4_foundation/ui/shadcn/select.tsx +2 -0
- package/src/client/l4_foundation/ui/shadcn/switch.tsx +31 -0
- package/src/client/l4_foundation/ui/shadcn/tabs.tsx +74 -0
- package/src/common/l2_biz/plugin/l2-plugin-management-messages.ts +52 -22
- package/src/common/l3_modules/conversation/l3-conversation-locale-messages.ts +2 -2
- package/src/common/l3_modules/conversation/l3-conversation-pidesk.ts +1 -1
- package/src/common/l4_foundation/plugin/l4-plugin-package.ts +1 -0
- package/src/server/l2_biz/plugin-management/l2-plugin-catalog.ts +16 -5
- package/src/server/l2_biz/plugin-management/l2-plugin-commands.ts +21 -1
- package/src/server/l2_biz/plugin-management/l2-plugin-management.ts +21 -2
- package/src/server/l2_biz/plugin-management/l2-plugin-updates.ts +17 -3
- package/src/server/l4_foundation/pi/l4-pi-basic-session-services.ts +3 -3
- package/src/server/l4_foundation/pi/l4-pi-package-maintenance-runner.mts +4 -11
- package/src/server/l4_foundation/pi/l4-pi-plugin-registry-config.ts +52 -34
- package/src/server/l4_foundation/pi/l4-pi-plugin-registry-network.ts +5 -3
- package/src/server/l4_foundation/pi/l4-pi-plugin-registry.ts +23 -8
- package/src/server/l4_foundation/pi/l4-pi-session-initialization.ts +2 -5
- package/src/server/l4_foundation/pidesk/l4-pidesk-command.ts +8 -1
- package/src/server/l4_foundation/pidesk/l4-pidesk-runtime.ts +24 -38
- package/src/server/l4_foundation/pidesk/l4-pidesk-system-prompt.ts +11 -0
- package/temp/build/pi-desk/release/.next/BUILD_ID +1 -1
- package/temp/build/pi-desk/release/.next/build-manifest.json +3 -3
- package/temp/build/pi-desk/release/.next/prerender-manifest.json +3 -3
- package/temp/build/pi-desk/release/.next/react-loadable-manifest.json +1 -1
- package/temp/build/pi-desk/release/.next/required-server-files.js +3 -3
- package/temp/build/pi-desk/release/.next/required-server-files.json +3 -3
- package/temp/build/pi-desk/release/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/_global-error.html +1 -1
- package/temp/build/pi-desk/release/.next/server/app/_global-error.rsc +3 -3
- package/temp/build/pi-desk/release/.next/server/app/_global-error.segments/_full.segment.rsc +3 -3
- package/temp/build/pi-desk/release/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +3 -3
- package/temp/build/pi-desk/release/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/temp/build/pi-desk/release/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/health/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/login/page.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/page.js +79 -79
- package/temp/build/pi-desk/release/.next/server/app/page_client-reference-manifest.js +1 -1
- package/temp/build/pi-desk/release/.next/server/chunks/25406.js +8 -77
- package/temp/build/pi-desk/release/.next/server/chunks/{81107.js → 35348.js} +2 -2
- package/temp/build/pi-desk/release/.next/server/chunks/35985.js +4 -4
- package/temp/build/pi-desk/release/.next/server/chunks/36361.js +1 -1
- package/temp/build/pi-desk/release/.next/server/chunks/47757.js +6 -75
- package/temp/build/pi-desk/release/.next/server/chunks/50520.js +4 -4
- package/temp/build/pi-desk/release/.next/server/chunks/58330.js +1 -1
- package/temp/build/pi-desk/release/.next/server/chunks/84231.js +2 -2
- package/temp/build/pi-desk/release/.next/server/chunks/89236.js +2 -2
- package/temp/build/pi-desk/release/.next/server/chunks/92386.js +5 -5
- package/temp/build/pi-desk/release/.next/server/chunks/94518.js +1 -1
- package/temp/build/pi-desk/release/.next/server/chunks/9874.js +1 -1
- package/temp/build/pi-desk/release/.next/server/middleware-build-manifest.js +1 -1
- package/temp/build/pi-desk/release/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/temp/build/pi-desk/release/.next/server/pages/500.html +1 -1
- package/temp/build/pi-desk/release/.next/server/server-reference-manifest.json +1 -1
- package/temp/build/pi-desk/release/.next/static/chunks/14197-3d3ddd426ac06c9c.js +3 -0
- package/temp/build/pi-desk/release/.next/static/chunks/34903-e4205c0becabea76.js +318 -0
- package/temp/build/pi-desk/release/.next/static/chunks/{54206.7c0792096df8a5cf.js → 54206.82a63ab971911eda.js} +3 -3
- package/temp/build/pi-desk/release/.next/static/chunks/74132-876f256c7a6101af.js +13 -0
- package/temp/build/pi-desk/release/.next/static/chunks/78923-17a9c337b29dcecd.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/96995-8f8313ea2ac3abd7.js +62 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/{layout-7c5409cced9c2501.js → layout-4faf3a52d219296d.js} +2 -2
- package/temp/build/pi-desk/release/.next/static/chunks/app/login/{page-8c87fb9e6c918848.js → page-bf893718bb151f3c.js} +1 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/page-28e1d77d6b884657.js +158 -0
- package/temp/build/pi-desk/release/.next/static/chunks/{webpack-45424d28099bbefa.js → webpack-7bfbf627379fb4c1.js} +1 -1
- package/temp/build/pi-desk/release/.next/static/css/3213ee28336bddc2.css +1 -0
- package/temp/build/pi-desk/release/.next/trace-build +1 -1
- package/src/server/l4_foundation/pidesk/l4-pidesk-skill-template.ts +0 -87
- package/temp/build/pi-desk/release/.next/static/chunks/27491-8b2d3e345b9142ea.js +0 -318
- package/temp/build/pi-desk/release/.next/static/chunks/7089-600a8f5593b7846c.js +0 -3
- package/temp/build/pi-desk/release/.next/static/chunks/74132-0884df6a6f11861a.js +0 -13
- package/temp/build/pi-desk/release/.next/static/chunks/78923-539a8b5f7af3c54a.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/96995-ae32167974365050.js +0 -62
- package/temp/build/pi-desk/release/.next/static/chunks/app/page-39b146293b6eb488.js +0 -158
- package/temp/build/pi-desk/release/.next/static/css/56486914a8ba0a1b.css +0 -1
- /package/temp/build/pi-desk/release/.next/static/{STVrBHA3z9KPtvBE4WcE2 → IgHJ40fniC07-ioYUKobL}/_buildManifest.js +0 -0
- /package/temp/build/pi-desk/release/.next/static/{STVrBHA3z9KPtvBE4WcE2 → IgHJ40fniC07-ioYUKobL}/_ssgManifest.js +0 -0
|
@@ -64,7 +64,7 @@ export function L2WorkbenchChatViewportManager({
|
|
|
64
64
|
onSaveSnapshot,
|
|
65
65
|
onClearSnapshot
|
|
66
66
|
}: L2WorkbenchChatViewportManagerProps): null {
|
|
67
|
-
const { scrollRef, scrollToBottom, state, stopScroll } = useStickToBottomContext()
|
|
67
|
+
const { isAtBottom, scrollRef, scrollToBottom, state, stopScroll } = useStickToBottomContext()
|
|
68
68
|
const positioningRef = useRef(false)
|
|
69
69
|
const initializedRef = useRef(false)
|
|
70
70
|
const positionedUserAnchorRef = useRef<string | null>(null)
|
|
@@ -73,6 +73,19 @@ export function L2WorkbenchChatViewportManager({
|
|
|
73
73
|
const suspendedSnapshotRef = useRef<L2WorkbenchChatViewportSnapshot | null>(null)
|
|
74
74
|
const suspendedScrollTopRef = useRef<number | null>(null)
|
|
75
75
|
|
|
76
|
+
useLayoutEffect(() => {
|
|
77
|
+
const scrollElement = scrollRef.current
|
|
78
|
+
if (!scrollElement || !visible || !isAtBottom) return
|
|
79
|
+
|
|
80
|
+
// 同高度的内容换位不会触发 ResizeObserver,浏览器锚定产生的上移会被误判为用户上翻。
|
|
81
|
+
const previousOverflowAnchor = scrollElement.style.overflowAnchor
|
|
82
|
+
scrollElement.style.overflowAnchor = 'none'
|
|
83
|
+
logL3ConversationScroll('viewport:anchor-lock', scrollElement)
|
|
84
|
+
return () => {
|
|
85
|
+
scrollElement.style.overflowAnchor = previousOverflowAnchor
|
|
86
|
+
}
|
|
87
|
+
}, [isAtBottom, scrollRef, visible])
|
|
88
|
+
|
|
76
89
|
useLayoutEffect(() => {
|
|
77
90
|
const scrollElement = scrollRef.current
|
|
78
91
|
if (!scrollElement) return
|
|
@@ -517,6 +517,38 @@ export function L2WorkbenchBranchPicker({
|
|
|
517
517
|
if (childIndex >= 0) selectIndex(childIndex)
|
|
518
518
|
}, [rows, selectIndex, selectedRow])
|
|
519
519
|
|
|
520
|
+
const handleEscape = useCallback((): void => {
|
|
521
|
+
if (confirmation) onCancelRunning()
|
|
522
|
+
else if (query) {
|
|
523
|
+
setQuery('')
|
|
524
|
+
setFoldedEntryIds(new Set())
|
|
525
|
+
scrollListTo(0)
|
|
526
|
+
} else requestClose(true)
|
|
527
|
+
}, [confirmation, onCancelRunning, query, requestClose, scrollListTo])
|
|
528
|
+
|
|
529
|
+
useEffect(() => {
|
|
530
|
+
if (!mobile || !present) return
|
|
531
|
+
const handleKeyDown = (event: KeyboardEvent): void => {
|
|
532
|
+
if (
|
|
533
|
+
event.key !== 'Escape' ||
|
|
534
|
+
event.defaultPrevented ||
|
|
535
|
+
event.isComposing ||
|
|
536
|
+
event.repeat ||
|
|
537
|
+
event.altKey ||
|
|
538
|
+
event.ctrlKey ||
|
|
539
|
+
event.metaKey ||
|
|
540
|
+
event.shiftKey ||
|
|
541
|
+
panelRef.current?.closest('[inert]')
|
|
542
|
+
)
|
|
543
|
+
return
|
|
544
|
+
event.preventDefault()
|
|
545
|
+
event.stopImmediatePropagation()
|
|
546
|
+
handleEscape()
|
|
547
|
+
}
|
|
548
|
+
window.addEventListener('keydown', handleKeyDown)
|
|
549
|
+
return () => window.removeEventListener('keydown', handleKeyDown)
|
|
550
|
+
}, [handleEscape, mobile, present])
|
|
551
|
+
|
|
520
552
|
const handleSearchKeyDown = (event: ReactKeyboardEvent<HTMLInputElement>): void => {
|
|
521
553
|
if (event.nativeEvent.isComposing) return
|
|
522
554
|
event.stopPropagation()
|
|
@@ -561,11 +593,7 @@ export function L2WorkbenchBranchPicker({
|
|
|
561
593
|
return
|
|
562
594
|
case 'Escape':
|
|
563
595
|
event.preventDefault()
|
|
564
|
-
|
|
565
|
-
setQuery('')
|
|
566
|
-
setFoldedEntryIds(new Set())
|
|
567
|
-
scrollListTo(0)
|
|
568
|
-
} else requestClose(true)
|
|
596
|
+
handleEscape()
|
|
569
597
|
return
|
|
570
598
|
}
|
|
571
599
|
}
|
|
@@ -1343,8 +1343,7 @@ export function L2Workbench({
|
|
|
1343
1343
|
event.ctrlKey ||
|
|
1344
1344
|
event.metaKey ||
|
|
1345
1345
|
event.shiftKey ||
|
|
1346
|
-
event.isComposing
|
|
1347
|
-
branchPicker !== null
|
|
1346
|
+
event.isComposing
|
|
1348
1347
|
) {
|
|
1349
1348
|
return
|
|
1350
1349
|
}
|
|
@@ -1356,9 +1355,27 @@ export function L2Workbench({
|
|
|
1356
1355
|
return
|
|
1357
1356
|
}
|
|
1358
1357
|
|
|
1358
|
+
if (branchPicker !== null) return
|
|
1359
1359
|
const workId = focusedWorkIdRef.current
|
|
1360
1360
|
if (!workId) return
|
|
1361
1361
|
|
|
1362
|
+
if (mobile) {
|
|
1363
|
+
branchPickerShortcutLastEscapeRef.current = 0
|
|
1364
|
+
const workspace = fileRuntime.getWorkspace(workId)
|
|
1365
|
+
const column = document.querySelector(`[data-work-id="${CSS.escape(workId)}"]`)
|
|
1366
|
+
// 手机返回可能落在 BODY;隐藏在终端或侧栏下的文件不能响应。
|
|
1367
|
+
if (
|
|
1368
|
+
workspace?.windowOpen &&
|
|
1369
|
+
workspace.activePane === 'files' &&
|
|
1370
|
+
column &&
|
|
1371
|
+
!column.closest('[inert]')
|
|
1372
|
+
) {
|
|
1373
|
+
event.preventDefault()
|
|
1374
|
+
fileRuntime.hideWindow(workId)
|
|
1375
|
+
}
|
|
1376
|
+
return
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1362
1379
|
const now = Date.now()
|
|
1363
1380
|
if (now - branchPickerShortcutLastEscapeRef.current >= BRANCH_PICKER_SHORTCUT_INTERVAL_MS) {
|
|
1364
1381
|
branchPickerShortcutLastEscapeRef.current = now
|
|
@@ -1372,7 +1389,7 @@ export function L2Workbench({
|
|
|
1372
1389
|
|
|
1373
1390
|
window.addEventListener('keydown', handleKeyDown)
|
|
1374
1391
|
return () => window.removeEventListener('keydown', handleKeyDown)
|
|
1375
|
-
}, [branchPicker, closeMobileDrawer, mobile, openBranchPicker])
|
|
1392
|
+
}, [branchPicker, closeMobileDrawer, fileRuntime, mobile, openBranchPicker])
|
|
1376
1393
|
|
|
1377
1394
|
useEffect(
|
|
1378
1395
|
() =>
|
|
@@ -29,7 +29,6 @@ export function L3ConversationCallSummary({
|
|
|
29
29
|
const { t } = useTranslation('conversation')
|
|
30
30
|
const [open, setOpen] = useState(false)
|
|
31
31
|
const [hoverBlocked, setHoverBlocked] = useState(false)
|
|
32
|
-
const trigger = useRef<HTMLButtonElement>(null)
|
|
33
32
|
const popup = useRef<HTMLDivElement>(null)
|
|
34
33
|
const hoverPreview = useRef(false)
|
|
35
34
|
|
|
@@ -63,7 +62,6 @@ export function L3ConversationCallSummary({
|
|
|
63
62
|
}}
|
|
64
63
|
>
|
|
65
64
|
<PopoverTrigger
|
|
66
|
-
ref={trigger}
|
|
67
65
|
openOnHover={!hoverBlocked}
|
|
68
66
|
delay={250}
|
|
69
67
|
closeDelay={180}
|
|
@@ -77,7 +75,6 @@ export function L3ConversationCallSummary({
|
|
|
77
75
|
align="start"
|
|
78
76
|
side="top"
|
|
79
77
|
initialFocus={() => (hoverPreview.current ? false : true)}
|
|
80
|
-
finalFocus={() => (hoverPreview.current ? false : trigger.current)}
|
|
81
78
|
className={cn(styles.panel, 'w-[30rem] gap-0 p-2')}
|
|
82
79
|
>
|
|
83
80
|
<div className="flex shrink-0 items-center gap-2 border-b px-1 pb-1">
|
|
@@ -19,6 +19,7 @@ export function L3FileContextMenuContent({ children }: { children: ReactNode }):
|
|
|
19
19
|
>
|
|
20
20
|
<ContextMenuPrimitive.Popup
|
|
21
21
|
data-slot="context-menu-content"
|
|
22
|
+
finalFocus={false}
|
|
22
23
|
className={cn(l4MenuPopupClassName, 'flex flex-col overflow-hidden p-0')}
|
|
23
24
|
>
|
|
24
25
|
<L4ScrollArea className="min-h-0" viewportClassName="p-1">
|
|
@@ -68,14 +68,16 @@ function L4AppDialogContent({
|
|
|
68
68
|
children,
|
|
69
69
|
showCloseButton = true,
|
|
70
70
|
finalFocus = false,
|
|
71
|
+
backdropClassName,
|
|
71
72
|
...props
|
|
72
73
|
}: DialogPrimitive.Popup.Props & {
|
|
73
74
|
showCloseButton?: boolean
|
|
75
|
+
backdropClassName?: string
|
|
74
76
|
}): React.JSX.Element {
|
|
75
77
|
const { t } = useTranslation('common')
|
|
76
78
|
return (
|
|
77
79
|
<L4AppDialogPortal>
|
|
78
|
-
<L4AppDialogBackdrop />
|
|
80
|
+
<L4AppDialogBackdrop className={backdropClassName} forceRender={Boolean(backdropClassName)} />
|
|
79
81
|
<DialogPrimitive.Popup
|
|
80
82
|
data-slot="app-dialog-content"
|
|
81
83
|
finalFocus={finalFocus}
|
|
@@ -209,6 +209,26 @@ export function L4ImageViewer(props: L4ImageViewerProps): React.JSX.Element | nu
|
|
|
209
209
|
let viewer: L4ViewerRuntime | null = null
|
|
210
210
|
let resizeFrame = 0
|
|
211
211
|
let resizeObserver: ResizeObserver | null = null
|
|
212
|
+
const handleEscape = (event: KeyboardEvent): void => {
|
|
213
|
+
if (
|
|
214
|
+
event.key !== 'Escape' ||
|
|
215
|
+
event.defaultPrevented ||
|
|
216
|
+
event.isComposing ||
|
|
217
|
+
event.altKey ||
|
|
218
|
+
event.ctrlKey ||
|
|
219
|
+
event.metaKey ||
|
|
220
|
+
event.shiftKey ||
|
|
221
|
+
!viewer?.fulled
|
|
222
|
+
)
|
|
223
|
+
return
|
|
224
|
+
// Viewer.js 自身关闭时不 preventDefault,且会与下层弹窗同时响应。
|
|
225
|
+
event.preventDefault()
|
|
226
|
+
event.stopImmediatePropagation()
|
|
227
|
+
if (!event.repeat) {
|
|
228
|
+
viewerRoot(instanceClass)?.querySelector<HTMLElement>('.viewer-button')?.click()
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
window.addEventListener('keydown', handleEscape, true)
|
|
212
232
|
const initialize = (): void => {
|
|
213
233
|
if (disposed) return
|
|
214
234
|
const initialIndex = initialIndexRef.current
|
|
@@ -299,6 +319,7 @@ export function L4ImageViewer(props: L4ImageViewerProps): React.JSX.Element | nu
|
|
|
299
319
|
|
|
300
320
|
return () => {
|
|
301
321
|
disposed = true
|
|
322
|
+
window.removeEventListener('keydown', handleEscape, true)
|
|
302
323
|
resizeObserver?.disconnect()
|
|
303
324
|
cancelAnimationFrame(resizeFrame)
|
|
304
325
|
if (viewerRef.current === viewer) viewerRef.current = null
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { Checkbox as CheckboxPrimitive } from '@base-ui/react/checkbox'
|
|
4
|
+
import { cn } from '@client/l4_foundation/lib/l4-utils'
|
|
5
|
+
import { CheckIcon } from 'lucide-react'
|
|
6
|
+
|
|
7
|
+
function Checkbox({ className, ...props }: CheckboxPrimitive.Root.Props) {
|
|
8
|
+
return (
|
|
9
|
+
<CheckboxPrimitive.Root
|
|
10
|
+
data-slot="checkbox"
|
|
11
|
+
className={cn(
|
|
12
|
+
'peer relative flex size-4 shrink-0 items-center justify-center rounded-[4px] border border-input transition-colors outline-none group-has-disabled/field:opacity-50 group-has-[:focus-visible]/field-label:ring-0 group-has-[:focus-visible]/field-label:not-data-checked:border-input after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 aria-invalid:aria-checked:border-primary dark:bg-input/30 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 data-checked:border-primary data-checked:bg-primary data-checked:text-primary-foreground group-has-[:focus-visible]/field-label:data-checked:border-primary dark:data-checked:bg-primary',
|
|
13
|
+
className
|
|
14
|
+
)}
|
|
15
|
+
{...props}
|
|
16
|
+
>
|
|
17
|
+
<CheckboxPrimitive.Indicator
|
|
18
|
+
data-slot="checkbox-indicator"
|
|
19
|
+
className="grid place-content-center text-current transition-none [&>svg]:size-3.5"
|
|
20
|
+
>
|
|
21
|
+
<CheckIcon />
|
|
22
|
+
</CheckboxPrimitive.Indicator>
|
|
23
|
+
</CheckboxPrimitive.Root>
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export { Checkbox }
|
|
@@ -34,6 +34,7 @@ function ContextMenuContent({
|
|
|
34
34
|
alignOffset = 4,
|
|
35
35
|
side = 'right',
|
|
36
36
|
sideOffset = 0,
|
|
37
|
+
finalFocus = false,
|
|
37
38
|
...props
|
|
38
39
|
}: ContextMenuPrimitive.Popup.Props &
|
|
39
40
|
Pick<ContextMenuPrimitive.Positioner.Props, 'align' | 'alignOffset' | 'side' | 'sideOffset'>) {
|
|
@@ -48,6 +49,7 @@ function ContextMenuContent({
|
|
|
48
49
|
>
|
|
49
50
|
<ContextMenuPrimitive.Popup
|
|
50
51
|
data-slot="context-menu-content"
|
|
52
|
+
finalFocus={finalFocus}
|
|
51
53
|
className={cn(l4MenuPopupClassName, className)}
|
|
52
54
|
{...props}
|
|
53
55
|
/>
|
|
@@ -134,10 +136,15 @@ function ContextMenuSubTrigger({
|
|
|
134
136
|
)
|
|
135
137
|
}
|
|
136
138
|
|
|
137
|
-
|
|
139
|
+
// 子菜单关闭时上级菜单仍打开,需保留其键盘导航焦点。
|
|
140
|
+
function ContextMenuSubContent({
|
|
141
|
+
finalFocus = true,
|
|
142
|
+
...props
|
|
143
|
+
}: React.ComponentProps<typeof ContextMenuContent>) {
|
|
138
144
|
return (
|
|
139
145
|
<ContextMenuContent
|
|
140
146
|
data-slot="context-menu-sub-content"
|
|
147
|
+
finalFocus={finalFocus}
|
|
141
148
|
className="min-w-40"
|
|
142
149
|
side="right"
|
|
143
150
|
{...props}
|
|
@@ -29,6 +29,7 @@ function DropdownMenuContent({
|
|
|
29
29
|
side = 'bottom',
|
|
30
30
|
sideOffset = 4,
|
|
31
31
|
className,
|
|
32
|
+
finalFocus = false,
|
|
32
33
|
...props
|
|
33
34
|
}: MenuPrimitive.Popup.Props &
|
|
34
35
|
Pick<MenuPrimitive.Positioner.Props, 'align' | 'alignOffset' | 'side' | 'sideOffset'>) {
|
|
@@ -43,6 +44,7 @@ function DropdownMenuContent({
|
|
|
43
44
|
>
|
|
44
45
|
<MenuPrimitive.Popup
|
|
45
46
|
data-slot="dropdown-menu-content"
|
|
47
|
+
finalFocus={finalFocus}
|
|
46
48
|
className={cn(l4MenuPopupClassName, className)}
|
|
47
49
|
{...props}
|
|
48
50
|
/>
|
|
@@ -129,17 +131,20 @@ function DropdownMenuSubTrigger({
|
|
|
129
131
|
)
|
|
130
132
|
}
|
|
131
133
|
|
|
134
|
+
// 子菜单关闭时上级菜单仍打开,需保留其键盘导航焦点。
|
|
132
135
|
function DropdownMenuSubContent({
|
|
133
136
|
align = 'start',
|
|
134
137
|
alignOffset = -3,
|
|
135
138
|
side = 'right',
|
|
136
139
|
sideOffset = 0,
|
|
137
140
|
className,
|
|
141
|
+
finalFocus = true,
|
|
138
142
|
...props
|
|
139
143
|
}: React.ComponentProps<typeof DropdownMenuContent>) {
|
|
140
144
|
return (
|
|
141
145
|
<DropdownMenuContent
|
|
142
146
|
data-slot="dropdown-menu-sub-content"
|
|
147
|
+
finalFocus={finalFocus}
|
|
143
148
|
className={cn('w-auto min-w-40', className)}
|
|
144
149
|
align={align}
|
|
145
150
|
alignOffset={alignOffset}
|
|
@@ -20,6 +20,7 @@ function PopoverContent({
|
|
|
20
20
|
alignOffset = 0,
|
|
21
21
|
side = 'bottom',
|
|
22
22
|
sideOffset = 4,
|
|
23
|
+
finalFocus = false,
|
|
23
24
|
...props
|
|
24
25
|
}: PopoverPrimitive.Popup.Props &
|
|
25
26
|
Pick<PopoverPrimitive.Positioner.Props, 'align' | 'alignOffset' | 'side' | 'sideOffset'> & {
|
|
@@ -36,6 +37,7 @@ function PopoverContent({
|
|
|
36
37
|
>
|
|
37
38
|
<PopoverPrimitive.Popup
|
|
38
39
|
data-slot="popover-content"
|
|
40
|
+
finalFocus={finalFocus}
|
|
39
41
|
className={cn(
|
|
40
42
|
'z-50 flex w-80 max-w-[calc(100vw-2rem)] origin-(--transform-origin) flex-col gap-3 rounded-lg border border-border bg-popover p-3 text-sm text-popover-foreground shadow-md outline-hidden duration-100 motion-reduce:animate-none data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95',
|
|
41
43
|
className
|
|
@@ -63,6 +63,7 @@ function SelectContent({
|
|
|
63
63
|
align = 'center',
|
|
64
64
|
alignOffset = 0,
|
|
65
65
|
alignItemWithTrigger = true,
|
|
66
|
+
finalFocus = false,
|
|
66
67
|
...props
|
|
67
68
|
}: SelectPrimitive.Popup.Props &
|
|
68
69
|
Pick<
|
|
@@ -83,6 +84,7 @@ function SelectContent({
|
|
|
83
84
|
>
|
|
84
85
|
<SelectPrimitive.Popup
|
|
85
86
|
data-slot="select-content"
|
|
87
|
+
finalFocus={finalFocus}
|
|
86
88
|
data-align-trigger={alignItemWithTrigger}
|
|
87
89
|
className={cn(
|
|
88
90
|
'relative isolate z-50 max-h-(--available-height) w-(--anchor-width) min-w-36 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-lg bg-popover text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 data-[align-trigger=true]:animate-none data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95',
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { Switch as SwitchPrimitive } from '@base-ui/react/switch'
|
|
4
|
+
import { cn } from '@client/l4_foundation/lib/l4-utils'
|
|
5
|
+
|
|
6
|
+
function Switch({
|
|
7
|
+
className,
|
|
8
|
+
size = 'default',
|
|
9
|
+
...props
|
|
10
|
+
}: SwitchPrimitive.Root.Props & {
|
|
11
|
+
size?: 'sm' | 'default'
|
|
12
|
+
}) {
|
|
13
|
+
return (
|
|
14
|
+
<SwitchPrimitive.Root
|
|
15
|
+
data-slot="switch"
|
|
16
|
+
data-size={size}
|
|
17
|
+
className={cn(
|
|
18
|
+
'peer group/switch relative inline-flex shrink-0 items-center rounded-full border border-transparent transition-all outline-none group-has-[:focus-visible]/field-label:border-transparent group-has-[:focus-visible]/field-label:ring-0 after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 data-[size=default]:h-[18.4px] data-[size=default]:w-[32px] data-[size=sm]:h-[14px] data-[size=sm]:w-[24px] dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 data-checked:bg-primary data-unchecked:bg-input dark:data-unchecked:bg-input/80 data-disabled:cursor-not-allowed data-disabled:opacity-50',
|
|
19
|
+
className
|
|
20
|
+
)}
|
|
21
|
+
{...props}
|
|
22
|
+
>
|
|
23
|
+
<SwitchPrimitive.Thumb
|
|
24
|
+
data-slot="switch-thumb"
|
|
25
|
+
className="pointer-events-none block rounded-full bg-background ring-0 transition-transform group-data-[size=default]/switch:size-4 group-data-[size=sm]/switch:size-3 group-data-[size=default]/switch:data-checked:translate-x-[calc(100%-2px)] group-data-[size=sm]/switch:data-checked:translate-x-[calc(100%-2px)] dark:data-checked:bg-primary-foreground group-data-[size=default]/switch:data-unchecked:translate-x-0 group-data-[size=sm]/switch:data-unchecked:translate-x-0 dark:data-unchecked:bg-foreground"
|
|
26
|
+
/>
|
|
27
|
+
</SwitchPrimitive.Root>
|
|
28
|
+
)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export { Switch }
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { Tabs as TabsPrimitive } from '@base-ui/react/tabs'
|
|
4
|
+
import { cva, type VariantProps } from 'class-variance-authority'
|
|
5
|
+
import { cn } from '@client/l4_foundation/lib/l4-utils'
|
|
6
|
+
|
|
7
|
+
function Tabs({ className, orientation = 'horizontal', ...props }: TabsPrimitive.Root.Props) {
|
|
8
|
+
return (
|
|
9
|
+
<TabsPrimitive.Root
|
|
10
|
+
data-slot="tabs"
|
|
11
|
+
data-orientation={orientation}
|
|
12
|
+
className={cn('group/tabs flex gap-2 data-horizontal:flex-col', className)}
|
|
13
|
+
{...props}
|
|
14
|
+
/>
|
|
15
|
+
)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const tabsListVariants = cva(
|
|
19
|
+
'group/tabs-list inline-flex w-fit items-center justify-center rounded-lg p-[3px] text-muted-foreground group-data-horizontal/tabs:h-8 group-data-vertical/tabs:h-fit group-data-vertical/tabs:flex-col data-[variant=line]:rounded-none',
|
|
20
|
+
{
|
|
21
|
+
variants: {
|
|
22
|
+
variant: {
|
|
23
|
+
default: 'bg-muted',
|
|
24
|
+
line: 'gap-1 bg-transparent'
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
defaultVariants: {
|
|
28
|
+
variant: 'default'
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
function TabsList({
|
|
34
|
+
className,
|
|
35
|
+
variant = 'default',
|
|
36
|
+
...props
|
|
37
|
+
}: TabsPrimitive.List.Props & VariantProps<typeof tabsListVariants>) {
|
|
38
|
+
return (
|
|
39
|
+
<TabsPrimitive.List
|
|
40
|
+
data-slot="tabs-list"
|
|
41
|
+
data-variant={variant}
|
|
42
|
+
className={cn(tabsListVariants({ variant }), className)}
|
|
43
|
+
{...props}
|
|
44
|
+
/>
|
|
45
|
+
)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function TabsTrigger({ className, ...props }: TabsPrimitive.Tab.Props) {
|
|
49
|
+
return (
|
|
50
|
+
<TabsPrimitive.Tab
|
|
51
|
+
data-slot="tabs-trigger"
|
|
52
|
+
className={cn(
|
|
53
|
+
"relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-1.5 py-0.5 text-sm font-medium whitespace-nowrap text-foreground/60 transition-all group-data-vertical/tabs:w-full group-data-vertical/tabs:justify-start hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1 focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50 has-data-[icon=inline-end]:pr-1 has-data-[icon=inline-start]:pl-1 aria-disabled:pointer-events-none aria-disabled:opacity-50 dark:text-muted-foreground dark:hover:text-foreground group-data-[variant=default]/tabs-list:data-active:shadow-sm group-data-[variant=line]/tabs-list:data-active:shadow-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
54
|
+
'group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-active:bg-transparent dark:group-data-[variant=line]/tabs-list:data-active:border-transparent dark:group-data-[variant=line]/tabs-list:data-active:bg-transparent',
|
|
55
|
+
'data-active:bg-background data-active:text-foreground dark:data-active:border-input dark:data-active:bg-input/30 dark:data-active:text-foreground',
|
|
56
|
+
'after:absolute after:bg-foreground after:opacity-0 after:transition-opacity group-data-horizontal/tabs:after:inset-x-0 group-data-horizontal/tabs:after:bottom-[-5px] group-data-horizontal/tabs:after:h-0.5 group-data-vertical/tabs:after:inset-y-0 group-data-vertical/tabs:after:-right-1 group-data-vertical/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-active:after:opacity-100',
|
|
57
|
+
className
|
|
58
|
+
)}
|
|
59
|
+
{...props}
|
|
60
|
+
/>
|
|
61
|
+
)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function TabsContent({ className, ...props }: TabsPrimitive.Panel.Props) {
|
|
65
|
+
return (
|
|
66
|
+
<TabsPrimitive.Panel
|
|
67
|
+
data-slot="tabs-content"
|
|
68
|
+
className={cn('flex-1 text-sm outline-none', className)}
|
|
69
|
+
{...props}
|
|
70
|
+
/>
|
|
71
|
+
)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export { Tabs, TabsList, TabsTrigger, TabsContent, tabsListVariants }
|
|
@@ -35,8 +35,8 @@ export const L2_PLUGIN_MANAGEMENT_MESSAGES = {
|
|
|
35
35
|
title: 'Plugins',
|
|
36
36
|
description: 'Manage plugin packages and local extensions.',
|
|
37
37
|
noPluginDescription: 'No description available',
|
|
38
|
-
checkUpdates: 'Check
|
|
39
|
-
checkingUpdates: '
|
|
38
|
+
checkUpdates: 'Check updates',
|
|
39
|
+
checkingUpdates: 'Checking…',
|
|
40
40
|
restartApply: 'Restart to finish',
|
|
41
41
|
installPlugin: 'Install plugin',
|
|
42
42
|
source: 'Plugin source',
|
|
@@ -135,7 +135,21 @@ export const L2_PLUGIN_MANAGEMENT_MESSAGES = {
|
|
|
135
135
|
loadingFullDetails: 'Loading full capability details',
|
|
136
136
|
installedTab: 'Installed',
|
|
137
137
|
searchPlugins: 'Find plugins',
|
|
138
|
-
directInstall: '
|
|
138
|
+
directInstall: 'Manual install',
|
|
139
|
+
advancedOptions: 'Advanced options',
|
|
140
|
+
capabilityDetails: 'Features and runtime details',
|
|
141
|
+
newVersion: 'New v{{version}}',
|
|
142
|
+
removeNamed: 'Uninstall {{name}}',
|
|
143
|
+
updateAll: 'Update all ({{count}})',
|
|
144
|
+
batchManage: 'Select plugins',
|
|
145
|
+
finishSelection: 'Done',
|
|
146
|
+
selectAll: 'Select all',
|
|
147
|
+
filterStatus: 'Plugin status',
|
|
148
|
+
statusFilter_all: 'All statuses',
|
|
149
|
+
statusFilter_updates: 'Updates available',
|
|
150
|
+
statusFilter_disabled: 'Disabled',
|
|
151
|
+
statusFilter_failed: 'Errors',
|
|
152
|
+
batchWaiting: 'Not submitted. Finish pending operations, then try again.',
|
|
139
153
|
batchInstall: 'Install plugins',
|
|
140
154
|
batchSourcePlaceholder:
|
|
141
155
|
'One npm package per line; a single source can also be a Git URL or local directory',
|
|
@@ -143,7 +157,7 @@ export const L2_PLUGIN_MANAGEMENT_MESSAGES = {
|
|
|
143
157
|
batchLimit: 'Choose up to 32 plugins per batch.',
|
|
144
158
|
batchFailed: 'Could not submit plugin changes',
|
|
145
159
|
sourceBusy: 'This plugin has an operation in progress. Try again when it finishes.',
|
|
146
|
-
selectFiltered: 'Select all
|
|
160
|
+
selectFiltered: 'Select all results',
|
|
147
161
|
selectPlugin: 'Select {{name}}',
|
|
148
162
|
selectedCount: '{{count}} selected',
|
|
149
163
|
clearSelection: 'Clear selection',
|
|
@@ -151,17 +165,17 @@ export const L2_PLUGIN_MANAGEMENT_MESSAGES = {
|
|
|
151
165
|
updateSelected: 'Update selected',
|
|
152
166
|
removeSelected: 'Uninstall selected',
|
|
153
167
|
setChannel: 'Set channel',
|
|
154
|
-
installChannel: '
|
|
155
|
-
defaultChannel: 'Default
|
|
168
|
+
installChannel: 'Version preference',
|
|
169
|
+
defaultChannel: 'Default',
|
|
156
170
|
automaticVersion: 'Default version',
|
|
157
171
|
allChannels: 'All channels',
|
|
158
172
|
filterChannel: 'Filter by channel',
|
|
159
|
-
channelLatest: '
|
|
160
|
-
channelDev: '
|
|
173
|
+
channelLatest: 'Stable',
|
|
174
|
+
channelDev: 'Development',
|
|
161
175
|
followingChannel: 'Channel: {{tag}}',
|
|
162
176
|
targetVersion: 'Target: {{version}}',
|
|
163
177
|
itemCheckFailed: 'Update check failed: {{error}}',
|
|
164
|
-
filterInstalled: '
|
|
178
|
+
filterInstalled: 'Search installed plugins',
|
|
165
179
|
noMatches: 'No matching plugins',
|
|
166
180
|
enabled: 'Enabled',
|
|
167
181
|
disabled: 'Disabled',
|
|
@@ -176,6 +190,7 @@ export const L2_PLUGIN_MANAGEMENT_MESSAGES = {
|
|
|
176
190
|
downloadSource: 'Download source',
|
|
177
191
|
installDownloadSource: 'Download source for this install',
|
|
178
192
|
useDefaultSource: 'Use saved default',
|
|
193
|
+
download_local: 'No override (local configuration)',
|
|
179
194
|
download_auto: 'Automatic',
|
|
180
195
|
download_domestic: 'China mirror',
|
|
181
196
|
download_official: 'Official npm',
|
|
@@ -189,12 +204,12 @@ export const L2_PLUGIN_MANAGEMENT_MESSAGES = {
|
|
|
189
204
|
invalidRegistry:
|
|
190
205
|
'Enter a valid HTTP or HTTPS registry URL without credentials, query or fragment.',
|
|
191
206
|
searchPlaceholder: 'Search plugin name or description',
|
|
192
|
-
searchSource: 'Search
|
|
207
|
+
searchSource: 'Search registry',
|
|
193
208
|
publicNpm: 'Public npm',
|
|
194
209
|
customSearchSource: 'Custom registry',
|
|
195
210
|
searchRegistryUrl: 'Search registry URL',
|
|
196
211
|
pluginKind: 'Plugin type',
|
|
197
|
-
kind_all: 'All',
|
|
212
|
+
kind_all: 'All types',
|
|
198
213
|
kind_desk: 'Pi Desk',
|
|
199
214
|
kind_pi: 'Pi',
|
|
200
215
|
kind_unknown: 'Unverified type',
|
|
@@ -260,8 +275,8 @@ export const L2_PLUGIN_MANAGEMENT_MESSAGES = {
|
|
|
260
275
|
title: '插件',
|
|
261
276
|
description: '管理插件包与本地扩展。',
|
|
262
277
|
noPluginDescription: '暂无说明',
|
|
263
|
-
checkUpdates: '
|
|
264
|
-
checkingUpdates: '
|
|
278
|
+
checkUpdates: '检查更新',
|
|
279
|
+
checkingUpdates: '检查中…',
|
|
265
280
|
restartApply: '重启并完成',
|
|
266
281
|
installPlugin: '安装插件',
|
|
267
282
|
source: '插件来源',
|
|
@@ -357,14 +372,28 @@ export const L2_PLUGIN_MANAGEMENT_MESSAGES = {
|
|
|
357
372
|
loadingFullDetails: '正在读取完整能力详情',
|
|
358
373
|
installedTab: '已安装',
|
|
359
374
|
searchPlugins: '搜索插件',
|
|
360
|
-
directInstall: '
|
|
375
|
+
directInstall: '手动安装',
|
|
376
|
+
advancedOptions: '高级选项',
|
|
377
|
+
capabilityDetails: '功能与运行信息',
|
|
378
|
+
newVersion: '新版本 v{{version}}',
|
|
379
|
+
removeNamed: '卸载 {{name}}',
|
|
380
|
+
updateAll: '全部更新({{count}})',
|
|
381
|
+
batchManage: '批量管理',
|
|
382
|
+
finishSelection: '完成',
|
|
383
|
+
selectAll: '全选',
|
|
384
|
+
filterStatus: '插件状态',
|
|
385
|
+
statusFilter_all: '全部状态',
|
|
386
|
+
statusFilter_updates: '有更新',
|
|
387
|
+
statusFilter_disabled: '已停用',
|
|
388
|
+
statusFilter_failed: '异常',
|
|
389
|
+
batchWaiting: '尚未提交,请完成等待中的操作后重试。',
|
|
361
390
|
batchInstall: '批量安装',
|
|
362
391
|
batchSourcePlaceholder: '每行一个 npm 包名;单项也可填写 Git 地址或本地目录',
|
|
363
392
|
batchNpmOnly: '批量安装时请每行填写一个 npm 包名。',
|
|
364
393
|
batchLimit: '每次批量操作最多选择 32 个插件。',
|
|
365
394
|
batchFailed: '提交插件变更失败',
|
|
366
395
|
sourceBusy: '此插件正在处理其他操作,完成后可重试。',
|
|
367
|
-
selectFiltered: '
|
|
396
|
+
selectFiltered: '全选当前结果',
|
|
368
397
|
selectPlugin: '选择 {{name}}',
|
|
369
398
|
selectedCount: '已选 {{count}} 项',
|
|
370
399
|
clearSelection: '清空选择',
|
|
@@ -372,17 +401,17 @@ export const L2_PLUGIN_MANAGEMENT_MESSAGES = {
|
|
|
372
401
|
updateSelected: '更新所选',
|
|
373
402
|
removeSelected: '卸载所选',
|
|
374
403
|
setChannel: '设置渠道',
|
|
375
|
-
installChannel: '
|
|
376
|
-
defaultChannel: '
|
|
404
|
+
installChannel: '版本偏好',
|
|
405
|
+
defaultChannel: '默认',
|
|
377
406
|
automaticVersion: '默认版本',
|
|
378
407
|
allChannels: '全部渠道',
|
|
379
408
|
filterChannel: '按渠道筛选',
|
|
380
|
-
channelLatest: '
|
|
381
|
-
channelDev: '
|
|
409
|
+
channelLatest: '稳定版',
|
|
410
|
+
channelDev: '开发版',
|
|
382
411
|
followingChannel: '跟随 {{tag}}',
|
|
383
412
|
targetVersion: '目标版本 {{version}}',
|
|
384
413
|
itemCheckFailed: '查询更新失败:{{error}}',
|
|
385
|
-
filterInstalled: '
|
|
414
|
+
filterInstalled: '搜索已安装插件',
|
|
386
415
|
noMatches: '没有匹配的插件',
|
|
387
416
|
enabled: '已启用',
|
|
388
417
|
disabled: '已停用',
|
|
@@ -397,6 +426,7 @@ export const L2_PLUGIN_MANAGEMENT_MESSAGES = {
|
|
|
397
426
|
downloadSource: '下载源',
|
|
398
427
|
installDownloadSource: '本次安装下载源',
|
|
399
428
|
useDefaultSource: '使用已保存的默认设置',
|
|
429
|
+
download_local: '不使用源(本机配置)',
|
|
400
430
|
download_auto: '自动',
|
|
401
431
|
download_domestic: '国内加速',
|
|
402
432
|
download_official: '官方',
|
|
@@ -409,12 +439,12 @@ export const L2_PLUGIN_MANAGEMENT_MESSAGES = {
|
|
|
409
439
|
settingsFailed: '保存或读取下载设置失败',
|
|
410
440
|
invalidRegistry: '请输入有效的 HTTP 或 HTTPS 仓库地址,不包含账号、查询参数或片段。',
|
|
411
441
|
searchPlaceholder: '搜索插件名称或简介',
|
|
412
|
-
searchSource: '
|
|
442
|
+
searchSource: '搜索仓库',
|
|
413
443
|
publicNpm: 'npm 公开仓库',
|
|
414
444
|
customSearchSource: '自定义仓库',
|
|
415
445
|
searchRegistryUrl: '搜索仓库地址',
|
|
416
446
|
pluginKind: '插件类型',
|
|
417
|
-
kind_all: '
|
|
447
|
+
kind_all: '全部类型',
|
|
418
448
|
kind_desk: 'Pi Desk',
|
|
419
449
|
kind_pi: 'Pi',
|
|
420
450
|
kind_unknown: '类型待确认',
|
|
@@ -76,7 +76,7 @@ export const L3_CONVERSATION_LOCALE_MESSAGES = {
|
|
|
76
76
|
mode: 'Mode',
|
|
77
77
|
cwd: 'Project directory',
|
|
78
78
|
agentDir: 'Pi directory',
|
|
79
|
-
|
|
79
|
+
docsDirectory: 'Documentation directory'
|
|
80
80
|
},
|
|
81
81
|
environment: { development: 'Development', production: 'Production' },
|
|
82
82
|
mode: { basic: 'Basic mode', normal: 'Normal mode' },
|
|
@@ -221,7 +221,7 @@ export const L3_CONVERSATION_LOCALE_MESSAGES = {
|
|
|
221
221
|
mode: '运行模式',
|
|
222
222
|
cwd: '项目目录',
|
|
223
223
|
agentDir: 'Pi 目录',
|
|
224
|
-
|
|
224
|
+
docsDirectory: '文档目录'
|
|
225
225
|
},
|
|
226
226
|
environment: { development: '开发环境', production: '正式环境' },
|
|
227
227
|
mode: { basic: '基础模式', normal: '正常模式' },
|