@nextclaw/ui 0.15.1 → 0.15.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +51 -0
- package/dist/assets/{api-b1R9VdeH.js → api-iNBpppzj.js} +3 -3
- package/dist/assets/{appearance-settings-page-D2O9pch9.js → appearance-settings-page-DMffQFR3.js} +1 -1
- package/dist/assets/{book-open-B77lQ2Tg.js → book-open-C3mJGwiy.js} +1 -1
- package/dist/assets/channels-list-page-CCtp0BRS.js +8 -0
- package/dist/assets/chat-page-H5a0dWvO.js +1 -0
- package/dist/assets/config-split-page-CrOJgB-Y.js +1 -0
- package/dist/assets/{confirm-dialog-C-NXSioX.js → confirm-dialog-Chv50USy.js} +2 -2
- package/dist/assets/{desktop-update-config-usHpXugP.js → desktop-update-config-KzTuXRf_.js} +1 -1
- package/dist/assets/{dist-jdGmbb6w.js → dist-BunzmC4B.js} +1 -1
- package/dist/assets/{dist-YtoqU-AT.js → dist-ChmGwvtK.js} +1 -1
- package/dist/assets/doc-browser-DNRL4Zvd.js +1 -0
- package/dist/assets/doc-browser-Dg0pmkOg.js +1 -0
- package/dist/assets/doc-browser-context-BHY-0FSD.js +1 -0
- package/dist/assets/{es2015-bNpL2LKy.js → es2015-DQZ5JWwK.js} +1 -1
- package/dist/assets/{external-link-BM6fk8q-.js → external-link-CU0kzzIP.js} +1 -1
- package/dist/assets/form-actions-BvCp_0lS.js +1 -0
- package/dist/assets/{i18n-provider-CntWolRA.js → i18n-provider-Cu8XyZb_.js} +1 -1
- package/dist/assets/index-CzfBdvK1.css +1 -0
- package/dist/assets/index-DGqHne1Q.js +104 -0
- package/dist/assets/loader-circle-CDSFuzmk.js +1 -0
- package/dist/assets/mcp-marketplace-page-BeEQK0DL.js +9 -0
- package/dist/assets/mcp-marketplace-page-D6idOTLp.js +1 -0
- package/dist/assets/model-config-page-bNNo-XyG.js +1 -0
- package/dist/assets/plus-D4DsdLN-.js +1 -0
- package/dist/assets/{provider-scoped-model-input-Cm_a4GHf.js → provider-scoped-model-input-IlgQCsoT.js} +1 -1
- package/dist/assets/providers-config-page-wLo6CAJw.js +1 -0
- package/dist/assets/{react-BN8uzPnp.js → react-BPIsQIlO.js} +1 -1
- package/dist/assets/{refresh-cw-BpVcFPmJ.js → refresh-cw-CILd1vAP.js} +1 -1
- package/dist/assets/remote-uKEYp7AR.js +1 -0
- package/dist/assets/rotate-cw-wPFPg1kH.js +1 -0
- package/dist/assets/runtime-config-page-DDn1sP4G.js +1 -0
- package/dist/assets/{save-BpFW5fpk.js → save-ByJqcPTP.js} +1 -1
- package/dist/assets/{search-D0uO7enf.js → search-DVIV6pfD.js} +1 -1
- package/dist/assets/search-config-page-B-Cf4iiB.js +1 -0
- package/dist/assets/secrets-config-page-DPKsY8Iw.js +3 -0
- package/dist/assets/security-config-e9SSBlKr.js +1 -0
- package/dist/assets/{select-Bh-CrA4p.js → select-BdgczSNw.js} +1 -1
- package/dist/assets/{setting-row-BJfCHRcb.js → setting-row-BkTVUTKx.js} +1 -1
- package/dist/assets/{settings-2-Blzi1vr6.js → settings-2-CH5shGg_.js} +1 -1
- package/dist/assets/{side-dock-ZdaSrQVB.js → side-dock-BsBvcJ9i.js} +2 -2
- package/dist/assets/{skeleton-BLlEzebZ.js → skeleton-DeX1FKw7.js} +1 -1
- package/dist/assets/switch-Cv8Ekb3x.js +1 -0
- package/dist/assets/{tag-chip-CzGihiQx.js → tag-chip-RB9uKcoC.js} +1 -1
- package/dist/assets/{tooltip-CdcrBjrC.js → tooltip-oQlEN-l6.js} +1 -1
- package/dist/assets/{use-config-CVPgsBmU.js → use-config-l3W7y8Qz.js} +1 -1
- package/dist/assets/{use-confirm-dialog-CSeBk9SF.js → use-confirm-dialog-BAxaVOJI.js} +1 -1
- package/dist/assets/x-BBMffEN0.js +1 -0
- package/dist/index.html +38 -30
- package/index.html +12 -4
- package/package.json +9 -9
- package/src/app/components/layout/__tests__/sidebar.layout.test.tsx +29 -1
- package/src/app/components/layout/sidebar-items.tsx +46 -7
- package/src/app/components/layout/sidebar-rail.styles.ts +2 -2
- package/src/app/components/layout/sidebar.tsx +84 -62
- package/src/app/configs/app-navigation.config.ts +49 -0
- package/src/app/styles/design-system.css +99 -4
- package/src/features/channels/components/config/channel-form.tsx +14 -11
- package/src/features/chat/components/conversation/__tests__/chat-conversation-header-section.test.tsx +40 -0
- package/src/features/chat/components/conversation/chat-conversation-header-section.tsx +3 -1
- package/src/features/chat/components/conversation/chat-conversation-panel.tsx +1 -1
- package/src/features/chat/components/layout/__tests__/chat-sidebar-toolbar.test.tsx +48 -0
- package/src/features/chat/components/layout/__tests__/chat-sidebar-utility-menu.test.tsx +55 -0
- package/src/features/chat/components/layout/chat-sidebar-desktop-layout.tsx +0 -3
- package/src/features/chat/components/layout/chat-sidebar-toolbar.tsx +3 -4
- package/src/features/chat/components/layout/chat-sidebar-utility-menu.tsx +30 -31
- package/src/features/chat/components/layout/chat-sidebar.tsx +21 -7
- package/src/features/chat/features/conversation/components/session-conversation-input.tsx +2 -1
- package/src/features/chat/features/conversation/components/session-queued-input-rows.tsx +1 -1
- package/src/features/chat/features/message/components/__tests__/chat-inline-panel-app-card.test.tsx +22 -1
- package/src/features/chat/features/message/components/__tests__/chat-message-list.container.test.tsx +62 -1
- package/src/features/chat/features/message/components/chat-inline-panel-app-card.tsx +10 -5
- package/src/features/chat/features/message/components/chat-message-list.container.tsx +47 -1
- package/src/features/chat/features/message/utils/__tests__/chat-message-process-summary.utils.test.ts +11 -1
- package/src/features/chat/features/message/utils/__tests__/chat-message-texts.utils.test.ts +23 -0
- package/src/features/chat/features/message/utils/chat-inline-panel-app-card.utils.ts +0 -11
- package/src/features/chat/features/message/utils/chat-message-process-summary.utils.ts +5 -0
- package/src/features/chat/features/message/utils/chat-message-texts.utils.ts +138 -0
- package/src/features/chat/features/session/components/__tests__/chat-sidebar-project-groups.test.tsx +116 -0
- package/src/features/chat/features/session/components/chat-sidebar-project-groups.tsx +108 -46
- package/src/features/chat/features/session/components/chat-sidebar-session-entry.tsx +6 -0
- package/src/features/chat/features/session/components/chat-sidebar-session-item.tsx +48 -24
- package/src/features/chat/features/session/components/chat-sidebar-session-list.tsx +0 -3
- package/src/features/chat/features/session/components/session-header/chat-session-header-actions.tsx +0 -4
- package/src/features/chat/features/session/components/session-header/chat-session-title-switcher.tsx +2 -2
- package/src/features/chat/features/session/utils/chat-sidebar-session-groups.utils.ts +25 -3
- package/src/features/chat/features/welcome/components/chat-welcome-capability-grid.tsx +9 -4
- package/src/features/chat/features/welcome/components/chat-welcome-project-picker.tsx +1 -1
- package/src/features/chat/features/welcome/components/chat-welcome-session-type-picker.tsx +1 -1
- package/src/features/chat/features/welcome/components/chat-welcome.tsx +0 -5
- package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-file-preview.test.tsx +226 -56
- package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-panel-content.test.tsx +1 -0
- package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-panel.test.tsx +144 -0
- package/src/features/chat/features/workspace/components/chat-session-workspace-directory-browser.tsx +99 -0
- package/src/features/chat/features/workspace/components/chat-session-workspace-file-breadcrumb-browser.tsx +2 -2
- package/src/features/chat/features/workspace/components/chat-session-workspace-file-breadcrumbs.tsx +4 -2
- package/src/features/chat/features/workspace/components/chat-session-workspace-file-preview.tsx +232 -21
- package/src/features/chat/features/workspace/components/chat-session-workspace-panel-content.tsx +3 -0
- package/src/features/chat/features/workspace/components/chat-session-workspace-panel-nav.tsx +44 -1
- package/src/features/chat/features/workspace/components/chat-session-workspace-panel.tsx +45 -3
- package/src/features/chat/features/workspace/utils/chat-workspace-file-tab-persistence.utils.ts +4 -0
- package/src/features/chat/managers/__tests__/chat-session-list.manager.test.ts +33 -2
- package/src/features/chat/managers/chat-session-list.manager.ts +32 -0
- package/src/features/chat/managers/chat-thread.manager.ts +2 -0
- package/src/features/chat/stores/chat-session-list.store.ts +28 -5
- package/src/features/chat/stores/chat-thread.store.ts +3 -0
- package/src/features/cron/components/cron-config.tsx +63 -80
- package/src/features/marketplace/components/detail-doc/__tests__/marketplace-detail-doc.test.tsx +44 -6
- package/src/features/marketplace/components/marketplace-detail-doc.tsx +8 -4
- package/src/features/marketplace/components/marketplace-page-parts.tsx +1 -1
- package/src/features/marketplace/components/mcp/mcp-marketplace-page.tsx +5 -12
- package/src/features/marketplace/hooks/use-marketplace-detail-doc-entry.ts +84 -0
- package/src/features/panel-apps/components/panel-app-list-item.tsx +6 -6
- package/src/features/panel-apps/components/panel-apps-list.tsx +2 -2
- package/src/features/panel-apps/index.ts +1 -0
- package/src/features/panel-apps/utils/panel-app-doc-browser.utils.tsx +2 -10
- package/src/features/panel-apps/utils/panel-app-iframe.utils.ts +6 -0
- package/src/features/pwa/managers/__tests__/pwa-shell-theme.manager.test.ts +11 -3
- package/src/features/pwa/managers/pwa-shell-theme.manager.ts +3 -1
- package/src/features/right-panel-resources/components/right-panel-resource-home-page.tsx +1 -1
- package/src/features/service-apps/components/service-apps-panel.tsx +145 -35
- package/src/features/settings/components/config/provider-auth-section.tsx +1 -1
- package/src/features/settings/components/config/provider-form.tsx +11 -8
- package/src/features/settings/components/config/provider-models-section.tsx +7 -7
- package/src/features/settings/components/config/provider-pill-selector.tsx +1 -1
- package/src/features/settings/components/config/secrets-config-form.tsx +5 -4
- package/src/features/settings/pages/model-config-page.tsx +26 -25
- package/src/features/settings/pages/providers-config-page.tsx +10 -13
- package/src/features/settings/pages/search-config-page.tsx +8 -5
- package/src/features/side-dock/components/side-dock.tsx +3 -3
- package/src/features/system-status/components/config/runtime-config-editor.tsx +5 -4
- package/src/index.css +257 -13
- package/src/shared/components/actions/action-link.tsx +1 -1
- package/src/shared/components/config-split-page.tsx +6 -6
- package/src/shared/components/doc-browser/__tests__/doc-browser-url.utils.test.ts +73 -0
- package/src/shared/components/doc-browser/__tests__/doc-browser.test.tsx +48 -0
- package/src/shared/components/doc-browser/doc-browser-context.tsx +4 -0
- package/src/shared/components/doc-browser/doc-browser-panel-parts.tsx +6 -2
- package/src/shared/components/doc-browser/doc-browser-renderer.types.ts +2 -1
- package/src/shared/components/doc-browser/doc-browser-tab-strip.tsx +10 -10
- package/src/shared/components/doc-browser/doc-browser.tsx +6 -4
- package/src/shared/components/doc-browser/utils/doc-browser-url.utils.ts +62 -4
- package/src/shared/components/resizable-right-panel/__tests__/resizable-right-panel.test.tsx +18 -0
- package/src/shared/components/resizable-right-panel/resizable-right-panel.tsx +28 -3
- package/src/shared/components/ui/actions/__tests__/icon-action-button.test.tsx +36 -0
- package/src/shared/components/ui/actions/form-actions.tsx +25 -0
- package/src/shared/components/ui/actions/icon-action-button.tsx +25 -2
- package/src/shared/components/ui/button.tsx +1 -1
- package/src/shared/components/ui/card.tsx +12 -4
- package/src/shared/components/ui/dialog.tsx +1 -1
- package/src/shared/components/ui/input.tsx +1 -1
- package/src/shared/components/ui/select.tsx +1 -1
- package/src/shared/components/ui/switch.tsx +1 -1
- package/src/shared/components/ui/tab-strip/compact-tab-strip.tsx +2 -1
- package/src/shared/components/ui/tabs.tsx +1 -1
- package/src/shared/components/ui/textarea.tsx +1 -1
- package/src/shared/hooks/use-server-path-browse.ts +26 -4
- package/src/shared/hooks/use-server-path-read.ts +11 -1
- package/src/shared/lib/api/utils/server-path.utils.ts +1 -0
- package/src/shared/lib/i18n/locales/en-US/chat.json +99 -0
- package/src/shared/lib/i18n/locales/en-US/core.json +3 -0
- package/src/shared/lib/i18n/locales/en-US/doc-browser.json +5 -0
- package/src/shared/lib/i18n/locales/zh-CN/chat.json +99 -0
- package/src/shared/lib/i18n/locales/zh-CN/core.json +3 -0
- package/src/shared/lib/i18n/locales/zh-CN/doc-browser.json +5 -0
- package/src/shared/lib/session-project/workspace-file-breadcrumb.utils.ts +9 -5
- package/src/shared/lib/theme/index.test.ts +21 -0
- package/src/shared/lib/theme/index.ts +6 -4
- package/src/vite-env.d.ts +2 -0
- package/dist/assets/channels-list-page-DcsIQc6A.js +0 -8
- package/dist/assets/chat-page-CZ7WxPir.js +0 -1
- package/dist/assets/config-split-page-BWQ6_Raq.js +0 -1
- package/dist/assets/doc-browser-B_Tf9n70.js +0 -1
- package/dist/assets/doc-browser-BdZPFOVa.js +0 -1
- package/dist/assets/doc-browser-context-DwokemUn.js +0 -1
- package/dist/assets/index-BIcEw90u.js +0 -104
- package/dist/assets/index-BiNSTKTU.css +0 -1
- package/dist/assets/loader-circle-MBgNSVIH.js +0 -1
- package/dist/assets/mcp-marketplace-page-CLmUstLN.js +0 -9
- package/dist/assets/mcp-marketplace-page-rZkmWPMy.js +0 -1
- package/dist/assets/model-config-page-Di0ySJD2.js +0 -1
- package/dist/assets/plus-vDqW5Kxp.js +0 -1
- package/dist/assets/providers-config-page-BAf2W0MV.js +0 -1
- package/dist/assets/remote-CLQ0IBM8.js +0 -1
- package/dist/assets/rotate-cw-CvNBv7_w.js +0 -1
- package/dist/assets/runtime-config-page-CflvvoDc.js +0 -1
- package/dist/assets/search-config-page-D0klFUXd.js +0 -1
- package/dist/assets/secrets-config-page-dVZ631Wp.js +0 -3
- package/dist/assets/security-config-C5gnlkuj.js +0 -1
- package/dist/assets/switch-CFLJFNSd.js +0 -1
- package/dist/assets/x-BF2KQ--V.js +0 -1
- /package/dist/assets/{config-hints-fGnUjDe9.js → config-hints-C_iP1zl_.js} +0 -0
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { useState, useRef, useCallback, useEffect } from 'react';
|
|
2
2
|
import {
|
|
3
|
-
DOCS_DEFAULT_BASE_URL,
|
|
4
3
|
DOC_BROWSER_HOME_TAB_KIND,
|
|
4
|
+
getDefaultDocsUrl,
|
|
5
|
+
getDocsUrl,
|
|
5
6
|
type DocBrowserDockControls,
|
|
6
7
|
type DocBrowserDockState,
|
|
7
8
|
type DocBrowserTab,
|
|
@@ -137,11 +138,11 @@ function useDocBrowserAddressBar({
|
|
|
137
138
|
const input = urlInput.trim();
|
|
138
139
|
if (!input) return;
|
|
139
140
|
if (isDocsTab && input.startsWith('/')) {
|
|
140
|
-
navigate(
|
|
141
|
+
navigate(getDocsUrl(input));
|
|
141
142
|
} else if (isDocsTab && input.startsWith('http')) {
|
|
142
143
|
navigate(input);
|
|
143
144
|
} else if (isDocsTab) {
|
|
144
|
-
navigate(
|
|
145
|
+
navigate(getDocsUrl(`/${input}`));
|
|
145
146
|
} else {
|
|
146
147
|
navigate(resolveContentUrlInput(input, currentUrl));
|
|
147
148
|
}
|
|
@@ -180,7 +181,7 @@ export function DocBrowser({ customTabRenderers = {}, displayMode = 'desktop', d
|
|
|
180
181
|
const [floatRect, setFloatRect] = useState<FloatingPanelRect>(createInitialFloatingPanelRect);
|
|
181
182
|
const [floatInteraction, setFloatInteraction] = useState<FloatingPanelInteraction | null>(null);
|
|
182
183
|
const iframeRef = useRef<HTMLIFrameElement>(null);
|
|
183
|
-
const currentUrl = currentTab?.currentUrl ??
|
|
184
|
+
const currentUrl = currentTab?.currentUrl ?? getDefaultDocsUrl();
|
|
184
185
|
const navVersion = currentTab?.navVersion ?? 0;
|
|
185
186
|
const iframeInstanceId = `${activeTabId}:${navVersion}:${iframeReloadVersion}`;
|
|
186
187
|
const pendingParentDocsUrlRef = useRef<string | null>(null);
|
|
@@ -374,6 +375,7 @@ export function DocBrowser({ customTabRenderers = {}, displayMode = 'desktop', d
|
|
|
374
375
|
iframeSandbox={iframeSandbox}
|
|
375
376
|
isDragging={floatInteraction?.kind === 'drag'}
|
|
376
377
|
isResizing={floatInteraction?.kind === 'resize'}
|
|
378
|
+
onIframePointerOver={customRenderer?.onIframePointerOver}
|
|
377
379
|
/>
|
|
378
380
|
|
|
379
381
|
<DocBrowserExternalLink currentUrl={currentUrl} isVisible={isDocsTab || isContentTab} />
|
|
@@ -2,15 +2,19 @@ import { getLanguage, type I18nLanguage } from '@/shared/lib/i18n';
|
|
|
2
2
|
import type { DocBrowserTabKind } from '@/shared/components/doc-browser/types/doc-browser.types';
|
|
3
3
|
|
|
4
4
|
const DOCS_PRIMARY_DOMAIN = 'docs.nextclaw.io';
|
|
5
|
+
const DOCS_MAINLAND_DOMAIN = 'docs.nextclaw.net';
|
|
5
6
|
const DOCS_PAGES_DEV = 'nextclaw-docs.pages.dev';
|
|
6
7
|
const DOCS_HOSTS = new Set([
|
|
7
8
|
DOCS_PRIMARY_DOMAIN,
|
|
8
9
|
`www.${DOCS_PRIMARY_DOMAIN}`,
|
|
10
|
+
DOCS_MAINLAND_DOMAIN,
|
|
11
|
+
`www.${DOCS_MAINLAND_DOMAIN}`,
|
|
9
12
|
DOCS_PAGES_DEV,
|
|
10
13
|
`www.${DOCS_PAGES_DEV}`,
|
|
11
14
|
]);
|
|
12
15
|
|
|
13
16
|
export const DOCS_DEFAULT_BASE_URL = `https://${DOCS_PRIMARY_DOMAIN}`;
|
|
17
|
+
export const DOCS_MAINLAND_BASE_URL = `https://${DOCS_MAINLAND_DOMAIN}`;
|
|
14
18
|
export const DOC_BROWSER_HOME_TAB_KIND = 'home';
|
|
15
19
|
export const DOC_BROWSER_HOME_URL = 'nextclaw://new-tab';
|
|
16
20
|
const DOCS_DEFAULT_GUIDE_PATH = '/guide/getting-started';
|
|
@@ -33,19 +37,68 @@ function ensureLocalizedDocsPath(pathname: string, locale: 'en' | 'zh'): string
|
|
|
33
37
|
return `/${locale}${normalized}`;
|
|
34
38
|
}
|
|
35
39
|
|
|
40
|
+
function normalizeDocsBaseUrl(value?: string): string | undefined {
|
|
41
|
+
const raw = value?.trim();
|
|
42
|
+
if (!raw) {
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
return new URL(raw).origin;
|
|
48
|
+
} catch {
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function getBrowserTimeZone(): string {
|
|
54
|
+
try {
|
|
55
|
+
return Intl.DateTimeFormat().resolvedOptions().timeZone ?? '';
|
|
56
|
+
} catch {
|
|
57
|
+
return '';
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function isAbsoluteUrl(value: string): boolean {
|
|
62
|
+
return /^[a-z][a-z\d+.-]*:/i.test(value.trim());
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function isLikelyMainlandDocsAudience(): boolean {
|
|
66
|
+
return getLanguage() === 'zh' || getBrowserTimeZone() === 'Asia/Shanghai';
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function getDocsBaseUrl(): string {
|
|
70
|
+
const configuredBaseUrl = normalizeDocsBaseUrl(import.meta.env.VITE_NEXTCLAW_DOCS_BASE_URL);
|
|
71
|
+
if (configuredBaseUrl) {
|
|
72
|
+
return configuredBaseUrl;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (isLikelyMainlandDocsAudience()) {
|
|
76
|
+
return normalizeDocsBaseUrl(import.meta.env.VITE_NEXTCLAW_DOCS_CN_BASE_URL) ?? DOCS_MAINLAND_BASE_URL;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return DOCS_DEFAULT_BASE_URL;
|
|
80
|
+
}
|
|
81
|
+
|
|
36
82
|
function resolveLocalizedDocsUrl(url: string): string {
|
|
37
83
|
const locale = toDocsLocale(getLanguage());
|
|
84
|
+
const docsBaseUrl = getDocsBaseUrl();
|
|
38
85
|
|
|
39
86
|
try {
|
|
40
|
-
const parsed = new URL(url,
|
|
41
|
-
|
|
87
|
+
const parsed = new URL(url, docsBaseUrl);
|
|
88
|
+
const docsBase = new URL(docsBaseUrl);
|
|
89
|
+
const shouldResolveAsDocs = !isAbsoluteUrl(url)
|
|
90
|
+
|| DOCS_HOSTS.has(parsed.hostname)
|
|
91
|
+
|| parsed.origin === docsBase.origin;
|
|
92
|
+
if (!shouldResolveAsDocs) {
|
|
42
93
|
return parsed.toString();
|
|
43
94
|
}
|
|
44
95
|
|
|
96
|
+
parsed.protocol = docsBase.protocol;
|
|
97
|
+
parsed.host = docsBase.host;
|
|
45
98
|
parsed.pathname = ensureLocalizedDocsPath(parsed.pathname, locale);
|
|
46
99
|
return parsed.toString();
|
|
47
100
|
} catch {
|
|
48
|
-
return new URL(`/${locale}${DOCS_DEFAULT_GUIDE_PATH}`,
|
|
101
|
+
return new URL(`/${locale}${DOCS_DEFAULT_GUIDE_PATH}`, docsBaseUrl).toString();
|
|
49
102
|
}
|
|
50
103
|
}
|
|
51
104
|
|
|
@@ -53,6 +106,10 @@ export function getDefaultDocsUrl(): string {
|
|
|
53
106
|
return resolveLocalizedDocsUrl(DOCS_DEFAULT_GUIDE_PATH);
|
|
54
107
|
}
|
|
55
108
|
|
|
109
|
+
export function getDocsUrl(pathOrUrl: string): string {
|
|
110
|
+
return resolveLocalizedDocsUrl(pathOrUrl);
|
|
111
|
+
}
|
|
112
|
+
|
|
56
113
|
export function normalizeDocUrl(url: string): string {
|
|
57
114
|
try {
|
|
58
115
|
return new URL(url).pathname.replace(/\.html$/, '').replace(/\/$/, '');
|
|
@@ -78,7 +135,8 @@ export function inferTabTitle(url: string, kind: DocBrowserTabKind, fallback = '
|
|
|
78
135
|
|
|
79
136
|
export function isDocsUrl(url: string): boolean {
|
|
80
137
|
try {
|
|
81
|
-
const
|
|
138
|
+
const fallbackOrigin = typeof window !== 'undefined' ? window.location.origin : DOCS_DEFAULT_BASE_URL;
|
|
139
|
+
const parsed = new URL(url, fallbackOrigin);
|
|
82
140
|
return DOCS_HOSTS.has(parsed.hostname);
|
|
83
141
|
} catch {
|
|
84
142
|
return false;
|
package/src/shared/components/resizable-right-panel/__tests__/resizable-right-panel.test.tsx
CHANGED
|
@@ -63,4 +63,22 @@ describe("ResizableRightPanel", () => {
|
|
|
63
63
|
).toBeNull();
|
|
64
64
|
expect(screen.getByTestId("right-panel").className).toContain("fixed");
|
|
65
65
|
});
|
|
66
|
+
|
|
67
|
+
it("can scope overlay positioning to its container", () => {
|
|
68
|
+
render(
|
|
69
|
+
<ResizableRightPanel
|
|
70
|
+
data-testid="right-panel"
|
|
71
|
+
overlay
|
|
72
|
+
overlayScope="container"
|
|
73
|
+
>
|
|
74
|
+
Content
|
|
75
|
+
</ResizableRightPanel>,
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
expect(
|
|
79
|
+
screen.queryByTestId("resizable-right-panel-handle"),
|
|
80
|
+
).toBeNull();
|
|
81
|
+
expect(screen.getByTestId("right-panel").className).toContain("absolute");
|
|
82
|
+
expect(screen.getByTestId("right-panel").className).not.toContain("fixed");
|
|
83
|
+
});
|
|
66
84
|
});
|
|
@@ -1,12 +1,33 @@
|
|
|
1
1
|
import { useRef, useState, type ComponentPropsWithoutRef } from "react";
|
|
2
2
|
import { cn } from "@/shared/lib/utils";
|
|
3
3
|
|
|
4
|
-
type ResizableRightPanelProps = ComponentPropsWithoutRef<"aside"> & {
|
|
4
|
+
type ResizableRightPanelProps = ComponentPropsWithoutRef<"aside"> & {
|
|
5
|
+
defaultWidth?: number;
|
|
6
|
+
minWidth?: number;
|
|
7
|
+
maxWidth?: number;
|
|
8
|
+
overlay?: boolean;
|
|
9
|
+
overlayScope?: "viewport" | "container";
|
|
10
|
+
};
|
|
5
11
|
|
|
6
|
-
export function ResizableRightPanel({
|
|
12
|
+
export function ResizableRightPanel({
|
|
13
|
+
children,
|
|
14
|
+
className,
|
|
15
|
+
style,
|
|
16
|
+
defaultWidth = 420,
|
|
17
|
+
minWidth = 320,
|
|
18
|
+
maxWidth = 860,
|
|
19
|
+
overlay = false,
|
|
20
|
+
overlayScope = "viewport",
|
|
21
|
+
...props
|
|
22
|
+
}: ResizableRightPanelProps) {
|
|
7
23
|
const resizeRef = useRef<{ startX: number; startWidth: number } | null>(null);
|
|
8
24
|
const [isResizing, setIsResizing] = useState(false);
|
|
9
25
|
const [width, setWidth] = useState(defaultWidth);
|
|
26
|
+
const overlayClassName = overlay
|
|
27
|
+
? overlayScope === "container"
|
|
28
|
+
? "absolute inset-0 z-30"
|
|
29
|
+
: "fixed inset-0 z-40"
|
|
30
|
+
: "border-l border-border";
|
|
10
31
|
|
|
11
32
|
const onResizeStart = (event: React.PointerEvent<HTMLDivElement>) => {
|
|
12
33
|
if (overlay) return;
|
|
@@ -36,7 +57,11 @@ export function ResizableRightPanel({ children, className, style, defaultWidth =
|
|
|
36
57
|
return (
|
|
37
58
|
<aside
|
|
38
59
|
{...props}
|
|
39
|
-
className={cn(
|
|
60
|
+
className={cn(
|
|
61
|
+
"relative flex h-full min-h-0 shrink-0 overflow-hidden bg-card text-card-foreground",
|
|
62
|
+
overlayClassName,
|
|
63
|
+
className,
|
|
64
|
+
)}
|
|
40
65
|
style={overlay ? style : { ...style, width }}
|
|
41
66
|
>
|
|
42
67
|
{!overlay ? (
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { render, screen } from '@testing-library/react';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
import { IconActionButton } from '@/shared/components/ui/actions/icon-action-button';
|
|
4
|
+
|
|
5
|
+
describe('IconActionButton', () => {
|
|
6
|
+
it('applies compact size and strong tone classes for nested hover surfaces', () => {
|
|
7
|
+
render(
|
|
8
|
+
<IconActionButton
|
|
9
|
+
size="sm"
|
|
10
|
+
tone="strong"
|
|
11
|
+
icon={<span data-testid="icon" />}
|
|
12
|
+
label="Pin"
|
|
13
|
+
/>,
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
const button = screen.getByRole('button', { name: 'Pin' });
|
|
17
|
+
expect(button.className).toContain('h-6');
|
|
18
|
+
expect(button.className).toContain('w-6');
|
|
19
|
+
expect(button.className).toContain('p-1');
|
|
20
|
+
expect(button.className).toContain('hover:bg-black/10');
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('defaults to medium size and soft accent hover', () => {
|
|
24
|
+
render(
|
|
25
|
+
<IconActionButton
|
|
26
|
+
icon={<span data-testid="icon" />}
|
|
27
|
+
label="More"
|
|
28
|
+
/>,
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
const button = screen.getByRole('button', { name: 'More' });
|
|
32
|
+
expect(button.className).toContain('h-7');
|
|
33
|
+
expect(button.className).toContain('w-7');
|
|
34
|
+
expect(button.className).toContain('hover:bg-accent');
|
|
35
|
+
});
|
|
36
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { HTMLAttributes } from 'react';
|
|
2
|
+
import { cn } from '@/shared/lib/utils';
|
|
3
|
+
|
|
4
|
+
type FormActionsProps = HTMLAttributes<HTMLDivElement> & {
|
|
5
|
+
align?: 'start' | 'end' | 'between';
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export function FormActions({
|
|
9
|
+
align = 'end',
|
|
10
|
+
className,
|
|
11
|
+
...props
|
|
12
|
+
}: FormActionsProps) {
|
|
13
|
+
return (
|
|
14
|
+
<div
|
|
15
|
+
className={cn(
|
|
16
|
+
'flex flex-wrap items-center gap-2',
|
|
17
|
+
align === 'start' && 'justify-start',
|
|
18
|
+
align === 'end' && 'justify-end',
|
|
19
|
+
align === 'between' && 'justify-between',
|
|
20
|
+
className,
|
|
21
|
+
)}
|
|
22
|
+
{...props}
|
|
23
|
+
/>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
@@ -7,16 +7,35 @@ import {
|
|
|
7
7
|
} from '@/shared/components/ui/tooltip';
|
|
8
8
|
import { cn } from '@/shared/lib/utils';
|
|
9
9
|
|
|
10
|
+
type IconActionButtonSize = 'sm' | 'md' | 'lg';
|
|
11
|
+
type IconActionButtonTone = 'default' | 'strong';
|
|
12
|
+
|
|
10
13
|
type IconActionButtonProps = Omit<
|
|
11
14
|
React.ButtonHTMLAttributes<HTMLButtonElement>,
|
|
12
15
|
'children' | 'type'
|
|
13
16
|
> & {
|
|
14
17
|
icon: React.ReactNode;
|
|
15
18
|
label: string;
|
|
19
|
+
size?: IconActionButtonSize;
|
|
20
|
+
/** default: soft accent hover. strong: denser gray hover for nested hover surfaces. */
|
|
21
|
+
tone?: IconActionButtonTone;
|
|
16
22
|
tooltip?: string | false | null;
|
|
17
23
|
tooltipSide?: 'top' | 'right' | 'bottom' | 'left';
|
|
18
24
|
};
|
|
19
25
|
|
|
26
|
+
const SIZE_CLASS: Record<IconActionButtonSize, string> = {
|
|
27
|
+
sm: 'h-6 w-6 rounded-md p-1',
|
|
28
|
+
md: 'h-7 w-7 rounded-md p-1.5',
|
|
29
|
+
lg: 'h-8 w-8 rounded-lg p-1.5',
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const TONE_CLASS: Record<IconActionButtonTone, string> = {
|
|
33
|
+
default:
|
|
34
|
+
'text-muted-foreground hover:bg-accent hover:text-accent-foreground disabled:text-muted-foreground/45 disabled:hover:bg-transparent disabled:hover:text-muted-foreground/45',
|
|
35
|
+
strong:
|
|
36
|
+
'text-muted-foreground hover:bg-black/10 hover:text-foreground disabled:text-muted-foreground/45 disabled:hover:bg-transparent disabled:hover:text-muted-foreground/45',
|
|
37
|
+
};
|
|
38
|
+
|
|
20
39
|
const IconActionButton = React.forwardRef<HTMLButtonElement, IconActionButtonProps>(
|
|
21
40
|
(
|
|
22
41
|
{
|
|
@@ -24,6 +43,8 @@ const IconActionButton = React.forwardRef<HTMLButtonElement, IconActionButtonPro
|
|
|
24
43
|
disabled = false,
|
|
25
44
|
icon,
|
|
26
45
|
label,
|
|
46
|
+
size = 'md',
|
|
47
|
+
tone = 'default',
|
|
27
48
|
tooltip,
|
|
28
49
|
tooltipSide = 'bottom',
|
|
29
50
|
...buttonProps
|
|
@@ -38,8 +59,9 @@ const IconActionButton = React.forwardRef<HTMLButtonElement, IconActionButtonPro
|
|
|
38
59
|
disabled={disabled}
|
|
39
60
|
aria-label={label}
|
|
40
61
|
className={cn(
|
|
41
|
-
'inline-flex
|
|
42
|
-
|
|
62
|
+
'inline-flex shrink-0 items-center justify-center transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border disabled:cursor-not-allowed',
|
|
63
|
+
SIZE_CLASS[size],
|
|
64
|
+
TONE_CLASS[tone],
|
|
43
65
|
className
|
|
44
66
|
)}
|
|
45
67
|
>
|
|
@@ -63,3 +85,4 @@ const IconActionButton = React.forwardRef<HTMLButtonElement, IconActionButtonPro
|
|
|
63
85
|
IconActionButton.displayName = 'IconActionButton';
|
|
64
86
|
|
|
65
87
|
export { IconActionButton };
|
|
88
|
+
export type { IconActionButtonProps, IconActionButtonSize, IconActionButtonTone };
|
|
@@ -3,7 +3,7 @@ import { cva, type VariantProps } from 'class-variance-authority';
|
|
|
3
3
|
import { cn } from '@/shared/lib/utils';
|
|
4
4
|
|
|
5
5
|
const buttonVariants = cva(
|
|
6
|
-
'inline-flex items-center justify-center whitespace-nowrap rounded-full text-sm font-medium ring-offset-background transition-colors duration-fast focus-visible:outline-none focus-visible:ring-
|
|
6
|
+
'inline-flex items-center justify-center whitespace-nowrap rounded-full text-sm font-medium ring-offset-background transition-colors duration-fast focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border disabled:pointer-events-none disabled:opacity-50',
|
|
7
7
|
{
|
|
8
8
|
variants: {
|
|
9
9
|
variant: {
|
|
@@ -3,13 +3,21 @@ import { cn } from '@/shared/lib/utils';
|
|
|
3
3
|
|
|
4
4
|
const Card = React.forwardRef<
|
|
5
5
|
HTMLDivElement,
|
|
6
|
-
React.HTMLAttributes<HTMLDivElement> & {
|
|
7
|
-
|
|
6
|
+
React.HTMLAttributes<HTMLDivElement> & {
|
|
7
|
+
hover?: boolean;
|
|
8
|
+
/** Flat settings-style surface: light border, no shadow. */
|
|
9
|
+
surface?: 'raised' | 'flat';
|
|
10
|
+
}
|
|
11
|
+
>(({ className, hover = true, surface = 'raised', ...props }, ref) => (
|
|
8
12
|
<div
|
|
9
13
|
ref={ref}
|
|
10
14
|
className={cn(
|
|
11
|
-
'rounded-2xl border
|
|
12
|
-
|
|
15
|
+
'rounded-2xl border bg-card text-card-foreground transition-colors duration-base',
|
|
16
|
+
surface === 'raised'
|
|
17
|
+
? 'border-border shadow-card'
|
|
18
|
+
: 'border-border/75 shadow-none',
|
|
19
|
+
hover && surface === 'raised' && 'hover:border-primary/25 hover:shadow-card-hover',
|
|
20
|
+
hover && surface === 'flat' && 'hover:bg-muted/40',
|
|
13
21
|
className
|
|
14
22
|
)}
|
|
15
23
|
{...props}
|
|
@@ -42,7 +42,7 @@ const DialogContent = React.forwardRef<
|
|
|
42
42
|
{...props}
|
|
43
43
|
>
|
|
44
44
|
{children}
|
|
45
|
-
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-lg p-1 opacity-70
|
|
45
|
+
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-lg p-1 opacity-70 transition-all duration-fast hover:bg-accent hover:text-accent-foreground hover:opacity-100 focus:outline-none focus-visible:ring-1 focus-visible:ring-border disabled:pointer-events-none">
|
|
46
46
|
<X className="h-4 w-4 text-muted-foreground" />
|
|
47
47
|
<span className="sr-only">Close</span>
|
|
48
48
|
</DialogPrimitive.Close>
|
|
@@ -9,7 +9,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|
|
9
9
|
<input
|
|
10
10
|
type={type}
|
|
11
11
|
className={cn(
|
|
12
|
-
'flex h-9 w-full rounded-xl border border-border bg-card px-3.5 py-2 text-sm text-foreground file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground/55 placeholder:font-normal focus:outline-none focus:ring-
|
|
12
|
+
'flex h-9 w-full rounded-xl border border-border/75 bg-card px-3.5 py-2 text-sm text-foreground file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground/55 placeholder:font-normal transition-colors focus:outline-none focus:ring-0 focus:border-border disabled:cursor-not-allowed disabled:opacity-50',
|
|
13
13
|
className
|
|
14
14
|
)}
|
|
15
15
|
ref={ref}
|
|
@@ -25,7 +25,7 @@ const SelectTrigger = React.forwardRef<
|
|
|
25
25
|
<SelectPrimitive.Trigger
|
|
26
26
|
ref={ref}
|
|
27
27
|
className={cn(
|
|
28
|
-
"flex h-9 w-full items-center justify-between whitespace-nowrap rounded-xl border border-border bg-card px-3 py-2 text-sm text-foreground
|
|
28
|
+
"flex h-9 w-full items-center justify-between whitespace-nowrap rounded-xl border border-border/75 bg-card px-3 py-2 text-sm text-foreground ring-offset-background placeholder:text-muted-foreground transition-colors focus:outline-none focus:ring-0 focus:border-border disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
|
|
29
29
|
className
|
|
30
30
|
)}
|
|
31
31
|
{...props}
|
|
@@ -17,7 +17,7 @@ const Switch = React.forwardRef<HTMLButtonElement, SwitchProps>(
|
|
|
17
17
|
data-state={checked ? 'checked' : 'unchecked'}
|
|
18
18
|
ref={ref}
|
|
19
19
|
className={cn(
|
|
20
|
-
'switch-track peer inline-flex h-[22px] w-10 shrink-0 cursor-pointer items-center rounded-full border-2 transition-colors duration-fast focus-visible:outline-none focus-visible:ring-
|
|
20
|
+
'switch-track peer inline-flex h-[22px] w-10 shrink-0 cursor-pointer items-center rounded-full border-2 transition-colors duration-fast focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border disabled:cursor-not-allowed disabled:opacity-50',
|
|
21
21
|
checked ? 'border-primary/70 bg-primary' : 'border-border/60 bg-muted hover:bg-accent',
|
|
22
22
|
className
|
|
23
23
|
)}
|
|
@@ -147,11 +147,12 @@ function CompactTabItem({
|
|
|
147
147
|
<CompactTabLabelButton tab={tab} labelClassName={labelClassName} />
|
|
148
148
|
{tab.onClose && tab.closePlacement !== "leading-hover" ? (
|
|
149
149
|
<IconActionButton
|
|
150
|
+
size="sm"
|
|
151
|
+
tone="strong"
|
|
150
152
|
icon={<X className="h-3 w-3" />}
|
|
151
153
|
label={tab.closeLabel ?? ""}
|
|
152
154
|
tooltip={tab.closeLabel ?? null}
|
|
153
155
|
onClick={(event) => closeCompactTab(event, tab.onClose!)}
|
|
154
|
-
className="h-5 w-5 rounded p-0.5 hover:bg-black/10"
|
|
155
156
|
/>
|
|
156
157
|
) : null}
|
|
157
158
|
</div>
|
|
@@ -64,7 +64,7 @@ export function TabsTrigger({ value, children, className }: TabsTriggerProps) {
|
|
|
64
64
|
aria-pressed={isActive}
|
|
65
65
|
data-state={isActive ? 'active' : 'inactive'}
|
|
66
66
|
className={cn(
|
|
67
|
-
'inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-[13px] font-medium
|
|
67
|
+
'inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-[13px] font-medium transition-all duration-fast focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border disabled:pointer-events-none disabled:opacity-50',
|
|
68
68
|
isActive
|
|
69
69
|
? 'bg-card text-foreground shadow-sm'
|
|
70
70
|
: 'text-muted-foreground hover:bg-accent hover:text-accent-foreground',
|
|
@@ -7,7 +7,7 @@ export const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
|
|
|
7
7
|
({ className, ...props }, ref) => (
|
|
8
8
|
<textarea
|
|
9
9
|
className={cn(
|
|
10
|
-
"flex min-h-28 w-full rounded-xl border border-border bg-card px-3.5 py-2.5 text-sm text-foreground placeholder:text-muted-foreground/55 placeholder:font-normal focus:outline-none focus:ring-
|
|
10
|
+
"flex min-h-28 w-full rounded-xl border border-border/75 bg-card px-3.5 py-2.5 text-sm text-foreground placeholder:text-muted-foreground/55 placeholder:font-normal transition-colors focus:outline-none focus:ring-0 focus:border-border disabled:cursor-not-allowed disabled:opacity-50",
|
|
11
11
|
className,
|
|
12
12
|
)}
|
|
13
13
|
ref={ref}
|
|
@@ -1,19 +1,41 @@
|
|
|
1
1
|
import { useQuery } from '@tanstack/react-query';
|
|
2
2
|
import { fetchServerPathBrowse } from '@/shared/lib/api';
|
|
3
3
|
|
|
4
|
+
export function buildServerPathBrowseQueryKey(params: {
|
|
5
|
+
path?: string | null;
|
|
6
|
+
basePath?: string | null;
|
|
7
|
+
includeFiles?: boolean;
|
|
8
|
+
}) {
|
|
9
|
+
return [
|
|
10
|
+
'server-path-browse',
|
|
11
|
+
params.path?.trim() ?? '',
|
|
12
|
+
params.basePath?.trim() ?? '',
|
|
13
|
+
params.includeFiles ?? false,
|
|
14
|
+
] as const;
|
|
15
|
+
}
|
|
16
|
+
|
|
4
17
|
export function useServerPathBrowse(params: {
|
|
5
18
|
path?: string | null;
|
|
19
|
+
basePath?: string | null;
|
|
6
20
|
includeFiles?: boolean;
|
|
7
21
|
enabled?: boolean;
|
|
8
22
|
}) {
|
|
23
|
+
const { basePath, enabled, includeFiles, path } = params;
|
|
24
|
+
const normalizedPath = path?.trim() ?? '';
|
|
25
|
+
const normalizedBasePath = basePath?.trim() ?? '';
|
|
9
26
|
return useQuery({
|
|
10
|
-
queryKey:
|
|
27
|
+
queryKey: buildServerPathBrowseQueryKey({
|
|
28
|
+
path: normalizedPath,
|
|
29
|
+
basePath: normalizedBasePath,
|
|
30
|
+
includeFiles,
|
|
31
|
+
}),
|
|
11
32
|
queryFn: () =>
|
|
12
33
|
fetchServerPathBrowse({
|
|
13
|
-
path:
|
|
14
|
-
|
|
34
|
+
path: normalizedPath,
|
|
35
|
+
basePath: normalizedBasePath,
|
|
36
|
+
includeFiles,
|
|
15
37
|
}),
|
|
16
|
-
enabled:
|
|
38
|
+
enabled: enabled ?? true,
|
|
17
39
|
staleTime: 0,
|
|
18
40
|
});
|
|
19
41
|
}
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { useQuery } from '@tanstack/react-query';
|
|
2
2
|
import { fetchServerPathRead } from '@/shared/lib/api';
|
|
3
3
|
|
|
4
|
+
export function buildServerPathReadQueryKey(params: {
|
|
5
|
+
path?: string | null;
|
|
6
|
+
basePath?: string | null;
|
|
7
|
+
}) {
|
|
8
|
+
return ['server-path-read', params.path?.trim() ?? '', params.basePath ?? null] as const;
|
|
9
|
+
}
|
|
10
|
+
|
|
4
11
|
export function useServerPathRead(params: {
|
|
5
12
|
path?: string | null;
|
|
6
13
|
basePath?: string | null;
|
|
@@ -8,7 +15,10 @@ export function useServerPathRead(params: {
|
|
|
8
15
|
}) {
|
|
9
16
|
const normalizedPath = params.path?.trim() ?? '';
|
|
10
17
|
return useQuery({
|
|
11
|
-
queryKey:
|
|
18
|
+
queryKey: buildServerPathReadQueryKey({
|
|
19
|
+
path: normalizedPath,
|
|
20
|
+
basePath: params.basePath,
|
|
21
|
+
}),
|
|
12
22
|
queryFn: () =>
|
|
13
23
|
fetchServerPathRead({
|
|
14
24
|
path: normalizedPath,
|
|
@@ -17,6 +17,7 @@ function encodeServerPathSegments(path: string): string {
|
|
|
17
17
|
|
|
18
18
|
export async function fetchServerPathBrowse(params?: {
|
|
19
19
|
path?: string | null;
|
|
20
|
+
basePath?: string | null;
|
|
20
21
|
includeFiles?: boolean;
|
|
21
22
|
}): Promise<ServerPathBrowseView> {
|
|
22
23
|
return await nextclawClient.serverPaths.browse(params);
|