feat(settings): 支持自定义并持久化日志目录

- 将日志目录配置整合到数据目录设置,支持选择、打开、恢复默认与保存
- 持久化日志目录并保留环境变量优先级,目录调整后重启生效
- 通过跨进程锁和原子写入保护数据目录与日志目录配置
- 移除重复标题并互斥目录修改操作,补齐六语言文案
- 补充桌面接口、浏览器模拟及并发回归测试
This commit is contained in:
Syngnat
2026-07-23 11:40:17 +08:00
parent 5a5fbf04fe
commit 97cffa7809
28 changed files with 1459 additions and 38 deletions

View File

@@ -90,6 +90,53 @@ describe('settings center layout', () => {
expect(appSource).toContain("t('app.proxy.test.target_placeholder')");
});
it('keeps log directory controls inside the data-root detail page', () => {
const embeddedDataRootStart = appSource.indexOf("if (activeSettingsCenterPane.key === 'data-root')");
const embeddedDataRootEnd = appSource.indexOf(
"if (activeSettingsCenterPane.key === 'security-update')",
embeddedDataRootStart,
);
const embeddedDataRootSource = appSource.slice(embeddedDataRootStart, embeddedDataRootEnd);
const standaloneDataRootStart = appSource.indexOf('{isDataRootModalOpen && (');
const standaloneDataRootEnd = appSource.indexOf(
'<ConnectionPackagePasswordModal',
standaloneDataRootStart,
);
const standaloneDataRootSource = appSource.slice(standaloneDataRootStart, standaloneDataRootEnd);
const logDirectoryRendererStart = appSource.indexOf('const renderLogDirectorySettings = () => {');
const logDirectoryRendererEnd = appSource.indexOf('\n const {', logDirectoryRendererStart);
const logDirectoryRendererSource = appSource.slice(logDirectoryRendererStart, logDirectoryRendererEnd);
expect(embeddedDataRootStart).toBeGreaterThan(-1);
expect(embeddedDataRootEnd).toBeGreaterThan(embeddedDataRootStart);
expect(standaloneDataRootStart).toBeGreaterThan(-1);
expect(standaloneDataRootEnd).toBeGreaterThan(standaloneDataRootStart);
expect(appSource).toContain('ApplyLogDirectory');
expect(appSource).toContain('OpenLogDirectory');
expect(appSource).toContain('SelectLogDirectory');
expect(appSource).toContain("const [selectedLogDirectoryPath, setSelectedLogDirectoryPath] = useState('');");
expect(appSource).toContain('const directorySettingsApplying = dataRootApplying || logDirectoryApplying;');
expect(appSource).toContain('const handleSelectLogDirectory = useCallback(async () => {');
expect(appSource).toContain('const handleApplyLogDirectory = useCallback(async (useDefaultPath = false) => {');
expect(appSource).toContain('const handleOpenLogDirectory = useCallback(async () => {');
expect(appSource).toContain('const renderLogDirectorySettings = () => {');
expect(appSource).toContain('data-log-directory-settings="true"');
expect(appSource).toContain("dataRootInfo?.logDirectorySource === 'environment'");
expect(appSource).toContain('dataRootInfo?.logDirectoryRestartRequired === true');
expect(appSource).toContain("t('app.data_root.log_directory.environment_hint')");
expect(appSource).toContain("t('app.data_root.log_directory.pending_restart')");
expect(appSource).toContain("t('app.data_root.log_directory.restart_hint')");
expect(logDirectoryRendererSource).not.toContain("t('app.data_root.log_directory.target_directory')");
expect(logDirectoryRendererSource.match(/disabled={!editable \|\| directorySettingsApplying}/g)).toHaveLength(3);
expect(embeddedDataRootSource.match(/disabled={directorySettingsApplying}/g)).toHaveLength(4);
expect(standaloneDataRootSource.match(/disabled={directorySettingsApplying}/g)).toHaveLength(4);
expect(embeddedDataRootSource).toContain('{renderLogDirectorySettings()}');
expect(standaloneDataRootSource).toContain('{renderLogDirectorySettings()}');
expect(appSource).not.toContain("| 'log-directory'");
expect(appSource).not.toContain("key: 'log-directory'");
expect(appSource).not.toContain("handleOpenToolCenterPane('config', 'log-directory')");
});
it('adds close and back-to-settings actions to settings center detail panes', () => {
expect(appSource).toContain('const handleBackFromSettingsCenterPane = useCallback(() => {');
expect(appSource).toContain('const handleCancelSettingsCenterPane = useCallback(() => {');

View File

@@ -219,7 +219,7 @@ import { useAppLogPanelResize } from './hooks/useAppLogPanelResize';
import { useAppSidebarResize } from './hooks/useAppSidebarResize';
import { useAppUtilityStyles } from './hooks/useAppUtilityStyles';
import { useWorkbenchTabs } from './hooks/useWorkbenchTabs';
import { ApplyDataRootDirectory, CancelApplicationQuit, ForceQuitApplication, GetDataRootDirectoryInfo, GetSavedConnections, ListInstalledFontFamilies, OpenDataRootDirectory, SelectDataRootDirectory, SetApplicationBrandIcon, SetMacNativeWindowControls, SetWindowTranslucency } from '../wailsjs/go/app/App';
import { ApplyDataRootDirectory, ApplyLogDirectory, CancelApplicationQuit, ForceQuitApplication, GetDataRootDirectoryInfo, GetSavedConnections, ListInstalledFontFamilies, OpenDataRootDirectory, OpenLogDirectory, SelectDataRootDirectory, SelectLogDirectory, SetApplicationBrandIcon, SetMacNativeWindowControls, SetWindowTranslucency } from '../wailsjs/go/app/App';
import { getAntdLocale } from './i18n/frameworkLocale';
import { useI18n } from './i18n/provider';
import './App.css';
@@ -3069,8 +3069,11 @@ function App() {
const [isDataRootModalOpen, setIsDataRootModalOpen] = useState(false);
const [dataRootInfo, setDataRootInfo] = useState<any>(null);
const [selectedDataRootPath, setSelectedDataRootPath] = useState('');
const [selectedLogDirectoryPath, setSelectedLogDirectoryPath] = useState('');
const [dataRootLoading, setDataRootLoading] = useState(false);
const [dataRootApplying, setDataRootApplying] = useState(false);
const [logDirectoryApplying, setLogDirectoryApplying] = useState(false);
const directorySettingsApplying = dataRootApplying || logDirectoryApplying;
const aiEntryPlacement = resolveAIEntryPlacement();
const legacyAiEdgeHandleAttachment = resolveLegacyAIEdgeHandleAttachment(aiPanelVisible);
@@ -3471,6 +3474,7 @@ function App() {
const data = (res?.data || {}) as any;
setDataRootInfo(data);
setSelectedDataRootPath(String(data.path || ''));
setSelectedLogDirectoryPath(String(data.logDirectory || data.defaultLogDirectory || ''));
} catch (error) {
const errMsg = error instanceof Error ? error.message : String(error || t('common.unknown'));
void message.error(t('app.data_root.message.load_failed_with_error', { error: errMsg }));
@@ -3539,6 +3543,138 @@ function App() {
}
}, [t]);
const handleSelectLogDirectory = useCallback(async () => {
try {
const res = await SelectLogDirectory(
selectedLogDirectoryPath || dataRootInfo?.logDirectory || dataRootInfo?.defaultLogDirectory || '',
);
if (!res?.success) {
if (String(res?.message || '') !== '已取消') {
throw new Error(res?.message || t('common.unknown'));
}
return;
}
const data = (res?.data || {}) as any;
setSelectedLogDirectoryPath(String(data.directory || ''));
} catch (error) {
const errMsg = error instanceof Error ? error.message : String(error || t('common.unknown'));
void message.error(t('app.data_root.log_directory.message.select_failed_with_error', { error: errMsg }));
}
}, [dataRootInfo?.defaultLogDirectory, dataRootInfo?.logDirectory, selectedLogDirectoryPath, t]);
const handleApplyLogDirectory = useCallback(async (useDefaultPath = false) => {
const nextPath = useDefaultPath
? String(dataRootInfo?.defaultLogDirectory || '')
: String(selectedLogDirectoryPath || '').trim();
if (!nextPath) {
void message.warning(t('app.data_root.log_directory.message.select_valid_first'));
return;
}
setLogDirectoryApplying(true);
try {
const res = await ApplyLogDirectory(nextPath);
if (!res?.success) {
throw new Error(res?.message || t('common.unknown'));
}
const data = (res?.data || {}) as any;
setDataRootInfo(data);
setSelectedLogDirectoryPath(String(data.logDirectory || data.defaultLogDirectory || nextPath));
void message.success(res?.message || t('app.data_root.log_directory.message.updated'));
} catch (error) {
const errMsg = error instanceof Error ? error.message : String(error || t('common.unknown'));
void message.error(t('app.data_root.log_directory.message.apply_failed_with_error', { error: errMsg }));
} finally {
setLogDirectoryApplying(false);
}
}, [dataRootInfo?.defaultLogDirectory, selectedLogDirectoryPath, t]);
const handleOpenLogDirectory = useCallback(async () => {
try {
const res = await OpenLogDirectory();
if (!res?.success) {
throw new Error(res?.message || t('common.unknown'));
}
} catch (error) {
const errMsg = error instanceof Error ? error.message : String(error || t('common.unknown'));
void message.error(t('app.data_root.log_directory.message.open_failed_with_error', { error: errMsg }));
}
}, [t]);
const renderLogDirectorySettings = () => {
const editable = dataRootInfo?.logDirectoryEditable !== false;
const managedByEnvironment = dataRootInfo?.logDirectorySource === 'environment';
const restartRequired = dataRootInfo?.logDirectoryRestartRequired === true;
return (
<div style={utilityPanelStyle} data-log-directory-settings="true">
<div style={{ fontWeight: 600 }}>{t('app.data_root.log_directory.title')}</div>
<div style={{ ...utilityMutedTextStyle, marginTop: 4 }}>
{t('app.data_root.log_directory.description')}
</div>
<div style={{ display: 'grid', gap: 10, marginTop: 14 }}>
<Input
readOnly
disabled={!editable}
value={selectedLogDirectoryPath}
placeholder={t('app.data_root.log_directory.placeholder')}
aria-label={t('app.data_root.log_directory.title')}
/>
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 10 }}>
<Button
icon={<FolderOpenOutlined />}
disabled={!editable || directorySettingsApplying}
onClick={() => void handleSelectLogDirectory()}
>
{t('app.data_root.action.select')}
</Button>
<Button onClick={() => void handleOpenLogDirectory()}>
{t('app.data_root.action.open_current')}
</Button>
<Button
disabled={!editable || directorySettingsApplying}
loading={logDirectoryApplying}
onClick={() => void handleApplyLogDirectory(true)}
>
{t('app.data_root.action.restore_default_directory')}
</Button>
<Button
type="primary"
disabled={!editable || directorySettingsApplying}
loading={logDirectoryApplying}
onClick={() => void handleApplyLogDirectory(false)}
>
{t('common.save')}
</Button>
</div>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(240px, 1fr))', gap: 12 }}>
<div>
<div style={{ marginBottom: 6, fontWeight: 500 }}>
{t('app.data_root.log_directory.current_file')}
</div>
<div style={{ ...utilityMutedTextStyle, overflowWrap: 'anywhere' }}>
{dataRootInfo?.logFilePath || '-'}
</div>
</div>
<div>
<div style={{ marginBottom: 6, fontWeight: 500 }}>
{t('app.data_root.log_directory.default_directory')}
</div>
<div style={{ ...utilityMutedTextStyle, overflowWrap: 'anywhere' }}>
{dataRootInfo?.defaultLogDirectory || '-'}
</div>
</div>
</div>
{managedByEnvironment ? (
<Alert type="warning" showIcon message={t('app.data_root.log_directory.environment_hint')} />
) : restartRequired ? (
<Alert type="info" showIcon message={t('app.data_root.log_directory.pending_restart')} />
) : (
<div style={utilityMutedTextStyle}>{t('app.data_root.log_directory.restart_hint')}</div>
)}
</div>
</div>
);
};
const {
handleCloseLogPanel: handleCloseAppLogPanel,
@@ -7877,13 +8013,21 @@ function App() {
placeholder={t('app.data_root.placeholder.select_new_directory')}
/>
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 10 }}>
<Button icon={<FolderOpenOutlined />} onClick={() => void handleSelectDataRoot()}>
<Button
icon={<FolderOpenOutlined />}
disabled={directorySettingsApplying}
onClick={() => void handleSelectDataRoot()}
>
{t('app.data_root.action.select')}
</Button>
<Button onClick={() => void handleOpenDataRoot()}>
{t('app.data_root.action.open_current')}
</Button>
<Button loading={dataRootApplying} onClick={() => void handleApplyDataRoot(false, true)}>
<Button
disabled={directorySettingsApplying}
loading={dataRootApplying}
onClick={() => void handleApplyDataRoot(false, true)}
>
{t('app.data_root.action.restore_default_directory')}
</Button>
</div>
@@ -7892,10 +8036,19 @@ function App() {
<div style={utilityPanelStyle}>
<div style={{ marginBottom: 10, fontWeight: 600 }}>{t('app.data_root.apply_method')}</div>
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 10 }}>
<Button loading={dataRootApplying} onClick={() => void handleApplyDataRoot(false)}>
<Button
disabled={directorySettingsApplying}
loading={dataRootApplying}
onClick={() => void handleApplyDataRoot(false)}
>
{t('app.data_root.action.switch_only')}
</Button>
<Button type="primary" loading={dataRootApplying} onClick={() => void handleApplyDataRoot(true)}>
<Button
type="primary"
disabled={directorySettingsApplying}
loading={dataRootApplying}
onClick={() => void handleApplyDataRoot(true)}
>
{t('app.data_root.action.migrate_and_switch')}
</Button>
</div>
@@ -7903,6 +8056,7 @@ function App() {
{t('app.data_root.restart_hint')}
</div>
</div>
{renderLogDirectorySettings()}
</div>
)}
</Modal>
@@ -8352,13 +8506,21 @@ function App() {
placeholder={t('app.data_root.placeholder.select_new_directory')}
/>
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 10 }}>
<Button icon={<FolderOpenOutlined />} onClick={() => void handleSelectDataRoot()}>
<Button
icon={<FolderOpenOutlined />}
disabled={directorySettingsApplying}
onClick={() => void handleSelectDataRoot()}
>
{t('app.data_root.action.select')}
</Button>
<Button onClick={() => void handleOpenDataRoot()}>
{t('app.data_root.action.open_current')}
</Button>
<Button loading={dataRootApplying} onClick={() => void handleApplyDataRoot(false, true)}>
<Button
disabled={directorySettingsApplying}
loading={dataRootApplying}
onClick={() => void handleApplyDataRoot(false, true)}
>
{t('app.data_root.action.restore_default_directory')}
</Button>
</div>
@@ -8367,10 +8529,19 @@ function App() {
<div style={utilityPanelStyle}>
<div style={{ marginBottom: 10, fontWeight: 600 }}>{t('app.data_root.apply_method')}</div>
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 10 }}>
<Button loading={dataRootApplying} onClick={() => void handleApplyDataRoot(false)}>
<Button
disabled={directorySettingsApplying}
loading={dataRootApplying}
onClick={() => void handleApplyDataRoot(false)}
>
{t('app.data_root.action.switch_only')}
</Button>
<Button type="primary" loading={dataRootApplying} onClick={() => void handleApplyDataRoot(true)}>
<Button
type="primary"
disabled={directorySettingsApplying}
loading={dataRootApplying}
onClick={() => void handleApplyDataRoot(true)}
>
{t('app.data_root.action.migrate_and_switch')}
</Button>
</div>
@@ -8378,6 +8549,7 @@ function App() {
{t('app.data_root.restart_hint')}
</div>
</div>
{renderLogDirectorySettings()}
</div>
)}
</Modal>

View File

@@ -167,6 +167,47 @@ describe("i18n catalog", () => {
expect(catalogs["zh-CN"][devHintKey]).toBe("接收最新的开发版本");
});
it("keeps data-root log directory copy complete across all catalogs", () => {
const logDirectoryKeys = [
"app.data_root.log_directory.backend.dialog.select_directory",
"app.data_root.log_directory.backend.error.desktop_only",
"app.data_root.log_directory.backend.error.directory_unavailable",
"app.data_root.log_directory.backend.error.environment_managed",
"app.data_root.log_directory.backend.error.open_directory_failed",
"app.data_root.log_directory.backend.error.open_directory_unsupported",
"app.data_root.log_directory.backend.error.save_failed",
"app.data_root.log_directory.backend.message.opened",
"app.data_root.log_directory.backend.message.unchanged",
"app.data_root.log_directory.backend.message.updated_restart",
"app.data_root.log_directory.current_file",
"app.data_root.log_directory.default_directory",
"app.data_root.log_directory.description",
"app.data_root.log_directory.environment_hint",
"app.data_root.log_directory.message.apply_failed_with_error",
"app.data_root.log_directory.message.open_failed_with_error",
"app.data_root.log_directory.message.select_failed_with_error",
"app.data_root.log_directory.message.select_valid_first",
"app.data_root.log_directory.message.updated",
"app.data_root.log_directory.pending_restart",
"app.data_root.log_directory.placeholder",
"app.data_root.log_directory.restart_hint",
"app.data_root.log_directory.title",
] as const;
const base = catalogs["en-US"];
for (const language of SUPPORTED_LANGUAGES) {
for (const key of logDirectoryKeys) {
expect(catalogs[language]).toHaveProperty(key);
expect(catalogs[language][key]).toBeTruthy();
expect(getPlaceholders(catalogs[language][key])).toEqual(getPlaceholders(base[key]));
}
}
expect(catalogs["zh-CN"]["app.data_root.log_directory.title"]).toBe("日志目录");
expect(catalogs["zh-CN"]["app.data_root.log_directory.environment_hint"]).toContain("GONAVI_LOG_DIR");
expect(catalogs["en-US"]["app.data_root.log_directory.restart_hint"]).toContain("gonavi.log");
});
it("includes App shell keys required by every supported language", () => {
const appShellKeys = [
"app.tools.title",

View File

@@ -75,6 +75,7 @@ const importMain = async () => {
ImportConnectionsPayload: (raw: string, password?: string) => Promise<unknown>;
ExportConnectionsPackage: (options?: { includeSecrets?: boolean; filePassword?: string }) => Promise<{ success: boolean; message?: string }>;
ApplyDataRootDirectory: (path: string) => Promise<{ success: boolean; message?: string; data?: { path?: string } }>;
ApplyLogDirectory: (path: string) => Promise<{ success: boolean; message?: string; data?: { logDirectory?: string; logDirectoryRestartRequired?: boolean } }>;
SaveQuery: (input: { id?: string; name?: string; sql?: string }) => Promise<{ name: string; sql: string }>;
CheckForUpdates: () => Promise<{ success: boolean; data?: Record<string, unknown> }>;
CheckForUpdatesSilently: () => Promise<{ success: boolean; data?: Record<string, unknown> }>;
@@ -241,6 +242,25 @@ describe('main browser mock', () => {
expect(source).not.toContain("'数据目录已更新'");
});
it('keeps browser mock log directory state available for the data-root page', async () => {
vi.stubGlobal('navigator', {
languages: ['en-US'],
language: 'en-US',
});
const app = await importMain();
const { t } = await import('./i18n');
await expect(app!.ApplyLogDirectory('C:/mock/custom-logs')).resolves.toEqual(expect.objectContaining({
success: true,
message: t('app.data_root.log_directory.message.updated'),
data: expect.objectContaining({
logDirectory: 'C:/mock/custom-logs',
logDirectoryRestartRequired: true,
}),
}));
});
it('localizes browser mock MCP server test messages', async () => {
vi.stubGlobal('navigator', {
languages: ['en-US'],

View File

@@ -142,6 +142,13 @@ if (
driverPath: 'C:/mock/.gonavi/drivers',
isDefaultPath: true,
bootstrapPath: 'C:/mock/.gonavi/storage_root.json',
logDirectory: 'C:/Users/mock/.GoNavi/Logs',
activeLogDirectory: 'C:/Users/mock/.GoNavi/Logs',
logFilePath: 'C:/Users/mock/.GoNavi/Logs/gonavi.log',
defaultLogDirectory: 'C:/Users/mock/.GoNavi/Logs',
logDirectorySource: 'default',
logDirectoryEditable: true,
logDirectoryRestartRequired: false,
};
const upsertMockConnection = (view: any) => {
@@ -543,6 +550,7 @@ if (
OpenDownloadedUpdateDirectory: async () => ({ success: false }),
OpenDriverDownloadDirectory: async (path: string) => ({ success: true, data: { path } }),
OpenDataRootDirectory: async () => ({ success: true }),
OpenLogDirectory: async () => ({ success: true }),
SelectSQLDirectory: async (currentPath: string) => ({ success: false, message: currentPath ? '已取消' : '已取消' }),
ListSQLDirectory: async () => ({ success: true, data: [] }),
ReadSQLFile: async () => ({ success: false, message: '已取消' }),
@@ -648,6 +656,24 @@ if (
};
return { success: true, message: t('app.data_root.message.updated'), data: cloneBrowserMockValue(mockDataRootInfo) };
},
SelectLogDirectory: async (currentPath: string) => ({
success: true,
data: { directory: currentPath || mockDataRootInfo.defaultLogDirectory },
}),
ApplyLogDirectory: async (path: string) => {
const nextPath = String(path || mockDataRootInfo.defaultLogDirectory);
mockDataRootInfo = {
...mockDataRootInfo,
logDirectory: nextPath,
logDirectorySource: nextPath === mockDataRootInfo.defaultLogDirectory ? 'default' : 'custom',
logDirectoryRestartRequired: nextPath !== mockDataRootInfo.activeLogDirectory,
};
return {
success: true,
message: t('app.data_root.log_directory.message.updated'),
data: cloneBrowserMockValue(mockDataRootInfo),
};
},
}
},
aiservice: {

View File

@@ -12,6 +12,8 @@ export function ApplyChanges(arg1:connection.ConnectionConfig,arg2:string,arg3:s
export function ApplyDataRootDirectory(arg1:string,arg2:boolean):Promise<connection.QueryResult>;
export function ApplyLogDirectory(arg1:string):Promise<connection.QueryResult>;
export function BuildSQLAuditExport(arg1:sqlaudit.Filter,arg2:string):Promise<connection.QueryResult>;
export function CancelApplicationQuit():Promise<connection.QueryResult>;
@@ -282,6 +284,8 @@ export function OpenDownloadedUpdateDirectory():Promise<connection.QueryResult>;
export function OpenDriverDownloadDirectory(arg1:string):Promise<connection.QueryResult>;
export function OpenLogDirectory():Promise<connection.QueryResult>;
export function OpenSQLFile():Promise<connection.QueryResult>;
export function PreviewChanges(arg1:connection.ConnectionConfig,arg2:string,arg3:string,arg4:connection.ChangeSet):Promise<connection.QueryResult>;
@@ -406,6 +410,8 @@ export function SelectDriverPackageDirectory(arg1:string):Promise<connection.Que
export function SelectDriverPackageFile(arg1:string):Promise<connection.QueryResult>;
export function SelectLogDirectory(arg1:string):Promise<connection.QueryResult>;
export function SelectSQLDirectory(arg1:string):Promise<connection.QueryResult>;
export function SelectSQLFileForExecution():Promise<connection.QueryResult>;

View File

@@ -10,6 +10,10 @@ export function ApplyDataRootDirectory(arg1, arg2) {
return window['go']['app']['App']['ApplyDataRootDirectory'](arg1, arg2);
}
export function ApplyLogDirectory(arg1) {
return window['go']['app']['App']['ApplyLogDirectory'](arg1);
}
export function BuildSQLAuditExport(arg1, arg2) {
return window['go']['app']['App']['BuildSQLAuditExport'](arg1, arg2);
}
@@ -550,6 +554,10 @@ export function OpenDriverDownloadDirectory(arg1) {
return window['go']['app']['App']['OpenDriverDownloadDirectory'](arg1);
}
export function OpenLogDirectory() {
return window['go']['app']['App']['OpenLogDirectory']();
}
export function OpenSQLFile() {
return window['go']['app']['App']['OpenSQLFile']();
}
@@ -798,6 +806,10 @@ export function SelectDriverPackageFile(arg1) {
return window['go']['app']['App']['SelectDriverPackageFile'](arg1);
}
export function SelectLogDirectory(arg1) {
return window['go']['app']['App']['SelectLogDirectory'](arg1);
}
export function SelectSQLDirectory(arg1) {
return window['go']['app']['App']['SelectSQLDirectory'](arg1);
}