feat: 添加“终端右键粘贴”设置
This commit is contained in:
@@ -48,13 +48,9 @@ export const settingsRepository = {
|
|||||||
updated_at = excluded.updated_at`;
|
updated_at = excluded.updated_at`;
|
||||||
const params = [key, value, now, now];
|
const params = [key, value, now, now];
|
||||||
|
|
||||||
// console.log(`[仓库] 尝试设置设置项。键: ${key}, 值: ${value}`);
|
|
||||||
// console.log(`[仓库] 执行 SQL: ${sql},参数: ${JSON.stringify(params)}`);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const db = await getDbInstance();
|
const db = await getDbInstance();
|
||||||
const result = await runDb(db, sql, params);
|
const result = await runDb(db, sql, params);
|
||||||
// console.log(`[仓库] 成功设置键为 ${key} 的设置项。影响行数: ${result.changes}`);
|
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
console.error(`[Repository] 设置设置项 ${key} 时出错:`, err.message);
|
console.error(`[Repository] 设置设置项 ${key} 时出错:`, err.message);
|
||||||
throw new Error(`设置设置项 ${key} 失败`);
|
throw new Error(`设置设置项 ${key} 失败`);
|
||||||
@@ -265,8 +261,9 @@ export const ensureDefaultSettingsExist = async (db: sqlite3.Database): Promise<
|
|||||||
statusMonitorIntervalSeconds: '3',
|
statusMonitorIntervalSeconds: '3',
|
||||||
[SIDEBAR_CONFIG_KEY]: JSON.stringify(defaultSidebarPanesStructure),
|
[SIDEBAR_CONFIG_KEY]: JSON.stringify(defaultSidebarPanesStructure),
|
||||||
[CAPTCHA_CONFIG_KEY]: JSON.stringify(defaultCaptchaSettings),
|
[CAPTCHA_CONFIG_KEY]: JSON.stringify(defaultCaptchaSettings),
|
||||||
timezone: 'UTC', // NEW: 添加时区默认值
|
timezone: 'UTC', // 添加时区默认值
|
||||||
terminalScrollbackLimit: '5000', // NEW: 添加终端回滚行数默认值
|
terminalScrollbackLimit: '5000', // 添加终端回滚行数默认值
|
||||||
|
terminalEnableRightClickPaste: 'true', // 添加终端右键粘贴默认值
|
||||||
};
|
};
|
||||||
const nowSeconds = Math.floor(Date.now() / 1000);
|
const nowSeconds = Math.floor(Date.now() / 1000);
|
||||||
const sqlInsertOrIgnore = `INSERT OR IGNORE INTO settings (key, value, created_at, updated_at) VALUES (?, ?, ?, ?)`;
|
const sqlInsertOrIgnore = `INSERT OR IGNORE INTO settings (key, value, created_at, updated_at) VALUES (?, ?, ?, ?)`;
|
||||||
|
|||||||
@@ -45,15 +45,16 @@ export const settingsController = {
|
|||||||
'fileManagerRowSizeMultiplier', // +++ 添加文件管理器行大小键 +++
|
'fileManagerRowSizeMultiplier', // +++ 添加文件管理器行大小键 +++
|
||||||
'fileManagerColWidths', // +++ 添加文件管理器列宽键 +++
|
'fileManagerColWidths', // +++ 添加文件管理器列宽键 +++
|
||||||
'commandInputSyncTarget', // +++ 添加命令输入同步目标键 +++
|
'commandInputSyncTarget', // +++ 添加命令输入同步目标键 +++
|
||||||
'timezone', // NEW: 添加时区键
|
'timezone', // 添加时区键
|
||||||
'rdpModalWidth', // NEW: 添加 RDP 模态框宽度键
|
'rdpModalWidth', // 添加 RDP 模态框宽度键
|
||||||
'rdpModalHeight', // NEW: 添加 RDP 模态框高度键
|
'rdpModalHeight', // 添加 RDP 模态框高度键
|
||||||
'vncModalWidth', // NEW: 添加 VNC 模态框宽度键
|
'vncModalWidth', // 添加 VNC 模态框宽度键
|
||||||
'vncModalHeight', // NEW: 添加 VNC 模态框高度键
|
'vncModalHeight', // 添加 VNC 模态框高度键
|
||||||
'ipBlacklistEnabled', // <-- 添加 IP 黑名单启用键
|
'ipBlacklistEnabled', // <-- 添加 IP 黑名单启用键
|
||||||
'layoutLocked', // +++ 添加布局锁定键 +++
|
'layoutLocked', // +++ 添加布局锁定键 +++
|
||||||
'terminalScrollbackLimit', // NEW: 添加终端回滚行数键
|
'terminalScrollbackLimit', // 添加终端回滚行数键
|
||||||
'fileManagerShowDeleteConfirmation' // NEW: 添加文件管理器删除确认键
|
'fileManagerShowDeleteConfirmation', // 添加文件管理器删除确认键
|
||||||
|
'terminalEnableRightClickPaste' // 添加终端右键粘贴键
|
||||||
];
|
];
|
||||||
const filteredSettings: Record<string, string> = {};
|
const filteredSettings: Record<string, string> = {};
|
||||||
for (const key in settingsToUpdate) {
|
for (const key in settingsToUpdate) {
|
||||||
@@ -64,7 +65,7 @@ export const settingsController = {
|
|||||||
|
|
||||||
if (Object.keys(filteredSettings).length > 0) {
|
if (Object.keys(filteredSettings).length > 0) {
|
||||||
await settingsService.setMultipleSettings(filteredSettings);
|
await settingsService.setMultipleSettings(filteredSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
const updatedKeys = Object.keys(filteredSettings);
|
const updatedKeys = Object.keys(filteredSettings);
|
||||||
if (updatedKeys.length > 0) {
|
if (updatedKeys.length > 0) {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export interface ClientState { // 导出以便 Service 可以导入
|
|||||||
connectionName?: string; // 添加连接名称字段
|
connectionName?: string; // 添加连接名称字段
|
||||||
sftp?: SFTPWrapper; // 添加 sftp 实例 (由 SftpService 管理)
|
sftp?: SFTPWrapper; // 添加 sftp 实例 (由 SftpService 管理)
|
||||||
statusIntervalId?: NodeJS.Timeout; // 添加状态轮询 ID (由 StatusMonitorService 管理)
|
statusIntervalId?: NodeJS.Timeout; // 添加状态轮询 ID (由 StatusMonitorService 管理)
|
||||||
dockerStatusIntervalId?: NodeJS.Timeout; // NEW: Docker 状态轮询 ID
|
dockerStatusIntervalId?: NodeJS.Timeout; // Docker 状态轮询 ID
|
||||||
ipAddress?: string; // 添加 IP 地址字段
|
ipAddress?: string; // 添加 IP 地址字段
|
||||||
isShellReady?: boolean; // 标记 Shell 是否已准备好处理输入和调整大小
|
isShellReady?: boolean; // 标记 Shell 是否已准备好处理输入和调整大小
|
||||||
isSuspendedByService?: boolean; // 标记此会话是否已被 SshSuspendService 接管
|
isSuspendedByService?: boolean; // 标记此会话是否已被 SshSuspendService 接管
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ watch(searchTerm, (newValue) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// NEW: Watch currentSessionCommandInput and sync searchTerm based on settings
|
// Watch currentSessionCommandInput and sync searchTerm based on settings
|
||||||
watch(currentSessionCommandInput, (newValue) => { // 监听计算属性
|
watch(currentSessionCommandInput, (newValue) => { // 监听计算属性
|
||||||
const target = commandInputSyncTarget.value;
|
const target = commandInputSyncTarget.value;
|
||||||
if (target === 'quickCommands') {
|
if (target === 'quickCommands') {
|
||||||
@@ -213,7 +213,7 @@ const handleCommandInputKeydown = (event: KeyboardEvent) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// NEW: Handle blur event on command input
|
// Handle blur event on command input
|
||||||
const handleCommandInputBlur = () => {
|
const handleCommandInputBlur = () => {
|
||||||
// Reset selection in the target store when input loses focus
|
// Reset selection in the target store when input loses focus
|
||||||
const target = commandInputSyncTarget.value;
|
const target = commandInputSyncTarget.value;
|
||||||
|
|||||||
@@ -47,8 +47,9 @@ const {
|
|||||||
const settingsStore = useSettingsStore(); // +++ 实例化设置 store +++
|
const settingsStore = useSettingsStore(); // +++ 实例化设置 store +++
|
||||||
const {
|
const {
|
||||||
autoCopyOnSelectBoolean,
|
autoCopyOnSelectBoolean,
|
||||||
terminalScrollbackLimitNumber // NEW: Import scrollback limit getter
|
terminalScrollbackLimitNumber, // Import scrollback limit getter
|
||||||
} = storeToRefs(settingsStore); // +++ 获取选中即复制状态 +++
|
terminalEnableRightClickPasteBoolean, // Import right-click paste setting getter
|
||||||
|
} = storeToRefs(settingsStore); // +++ 获取设置状态 +++
|
||||||
|
|
||||||
// 防抖函数
|
// 防抖函数
|
||||||
const debounce = (func: Function, delay: number) => {
|
const debounce = (func: Function, delay: number) => {
|
||||||
@@ -121,7 +122,7 @@ const debouncedSetTerminalFontSize = debounce(async (size: number) => {
|
|||||||
}
|
}
|
||||||
}, 500); // 500ms 防抖延迟,可以调整
|
}, 500); // 500ms 防抖延迟,可以调整
|
||||||
|
|
||||||
// NEW: Helper function to convert setting value to xterm scrollback value
|
// Helper function to convert setting value to xterm scrollback value
|
||||||
const getScrollbackValue = (limit: number): number => {
|
const getScrollbackValue = (limit: number): number => {
|
||||||
if (limit === 0) {
|
if (limit === 0) {
|
||||||
return Infinity; // 0 means unlimited for xterm
|
return Infinity; // 0 means unlimited for xterm
|
||||||
@@ -129,6 +130,36 @@ const getScrollbackValue = (limit: number): number => {
|
|||||||
return Math.max(0, limit); // Ensure non-negative, return the number otherwise
|
return Math.max(0, limit); // Ensure non-negative, return the number otherwise
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// --- 右键粘贴功能 ---
|
||||||
|
const handleContextMenuPaste = async (event: MouseEvent) => {
|
||||||
|
event.preventDefault(); // 阻止默认右键菜单
|
||||||
|
try {
|
||||||
|
const text = await navigator.clipboard.readText();
|
||||||
|
if (text && terminal) {
|
||||||
|
// 将粘贴的文本发送到后端
|
||||||
|
emitWorkspaceEvent('terminal:input', { sessionId: props.sessionId, data: text });
|
||||||
|
console.log('[Terminal] Pasted via Right Click');
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error('[Terminal] Failed to paste via Right Click:', err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const addContextMenuListener = () => {
|
||||||
|
if (terminalRef.value) {
|
||||||
|
terminalRef.value.addEventListener('contextmenu', handleContextMenuPaste);
|
||||||
|
console.log(`[Terminal ${props.sessionId}] Right-click paste listener added.`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const removeContextMenuListener = () => {
|
||||||
|
if (terminalRef.value) {
|
||||||
|
terminalRef.value.removeEventListener('contextmenu', handleContextMenuPaste);
|
||||||
|
console.log(`[Terminal ${props.sessionId}] Right-click paste listener removed.`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// --- 右键粘贴功能结束 ---
|
||||||
|
|
||||||
// 初始化终端
|
// 初始化终端
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (terminalRef.value) {
|
if (terminalRef.value) {
|
||||||
@@ -142,7 +173,7 @@ onMounted(() => {
|
|||||||
allowTransparency: true,
|
allowTransparency: true,
|
||||||
disableStdin: false,
|
disableStdin: false,
|
||||||
convertEol: true,
|
convertEol: true,
|
||||||
scrollback: getScrollbackValue(terminalScrollbackLimitNumber.value), // NEW: Use setting from store
|
scrollback: getScrollbackValue(terminalScrollbackLimitNumber.value), // Use setting from store
|
||||||
scrollOnUserInput: true, // 输入时滚动到底部
|
scrollOnUserInput: true, // 输入时滚动到底部
|
||||||
...props.options, // 合并外部传入的选项
|
...props.options, // 合并外部传入的选项
|
||||||
});
|
});
|
||||||
@@ -402,24 +433,20 @@ onMounted(() => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 根据初始设置添加监听器
|
||||||
// --- 添加右键粘贴功能 ---
|
if (terminalEnableRightClickPasteBoolean.value) {
|
||||||
if (terminalRef.value) {
|
addContextMenuListener();
|
||||||
terminalRef.value.addEventListener('contextmenu', async (event: MouseEvent) => {
|
|
||||||
event.preventDefault(); // 阻止默认右键菜单
|
|
||||||
try {
|
|
||||||
const text = await navigator.clipboard.readText();
|
|
||||||
if (text && terminal) {
|
|
||||||
// 将粘贴的文本发送到后端
|
|
||||||
emitWorkspaceEvent('terminal:input', { sessionId: props.sessionId, data: text });
|
|
||||||
console.log('[Terminal] Pasted via Right Click');
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.error('[Terminal] Failed to paste via Right Click:', err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 监听设置变化
|
||||||
|
watch(terminalEnableRightClickPasteBoolean, (newValue) => {
|
||||||
|
if (newValue) {
|
||||||
|
addContextMenuListener();
|
||||||
|
} else {
|
||||||
|
removeContextMenuListener();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
// 重新添加鼠标滚轮缩放功能
|
// 重新添加鼠标滚轮缩放功能
|
||||||
if (terminalRef.value) {
|
if (terminalRef.value) {
|
||||||
@@ -506,11 +533,14 @@ onBeforeUnmount(() => {
|
|||||||
selectionListenerDisposable.dispose();
|
selectionListenerDisposable.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (terminalRef.value) {
|
|
||||||
|
// 确保在卸载时移除右键监听器
|
||||||
}
|
removeContextMenuListener();
|
||||||
});
|
|
||||||
|
if (terminalRef.value) {
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
// 暴露 write 方法给父组件 (可选)
|
// 暴露 write 方法给父组件 (可选)
|
||||||
const write = (data: string | Uint8Array) => {
|
const write = (data: string | Uint8Array) => {
|
||||||
terminal?.write(data);
|
terminal?.write(data);
|
||||||
|
|||||||
@@ -79,7 +79,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<hr class="border-border/50"> <!-- NEW: Separator -->
|
<hr class="border-border/50">
|
||||||
<!-- Command Input Sync Target -->
|
<!-- Command Input Sync Target -->
|
||||||
<div class="settings-section-content">
|
<div class="settings-section-content">
|
||||||
<h3 class="text-base font-semibold text-foreground mb-3">{{ $t('settings.commandInputSync.title', '命令输入同步') }}</h3>
|
<h3 class="text-base font-semibold text-foreground mb-3">{{ $t('settings.commandInputSync.title', '命令输入同步') }}</h3>
|
||||||
@@ -104,7 +104,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<hr class="border-border/50"> <!-- NEW: Separator -->
|
<hr class="border-border/50">
|
||||||
<!-- Show Connection Tags -->
|
<!-- Show Connection Tags -->
|
||||||
<div class="settings-section-content">
|
<div class="settings-section-content">
|
||||||
<h3 class="text-base font-semibold text-foreground mb-3">{{ $t('settings.workspace.showConnectionTagsTitle', '显示连接标签') }}</h3>
|
<h3 class="text-base font-semibold text-foreground mb-3">{{ $t('settings.workspace.showConnectionTagsTitle', '显示连接标签') }}</h3>
|
||||||
@@ -124,7 +124,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<hr class="border-border/50"> <!-- NEW: Separator -->
|
<hr class="border-border/50">
|
||||||
<!-- Show Quick Command Tags -->
|
<!-- Show Quick Command Tags -->
|
||||||
<div class="settings-section-content">
|
<div class="settings-section-content">
|
||||||
<h3 class="text-base font-semibold text-foreground mb-3">{{ $t('settings.workspace.showQuickCommandTagsTitle', '显示快捷指令标签') }}</h3>
|
<h3 class="text-base font-semibold text-foreground mb-3">{{ $t('settings.workspace.showQuickCommandTagsTitle', '显示快捷指令标签') }}</h3>
|
||||||
@@ -144,7 +144,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<hr class="border-border/50"> <!-- NEW: Separator -->
|
<hr class="border-border/50">
|
||||||
<!-- Terminal Scrollback Limit -->
|
<!-- Terminal Scrollback Limit -->
|
||||||
<div class="settings-section-content">
|
<div class="settings-section-content">
|
||||||
<h3 class="text-base font-semibold text-foreground mb-3">{{ t('settings.terminalScrollback.title', '终端回滚行数') }}</h3>
|
<h3 class="text-base font-semibold text-foreground mb-3">{{ t('settings.terminalScrollback.title', '终端回滚行数') }}</h3>
|
||||||
@@ -164,7 +164,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<hr class="border-border/50"> <!-- NEW: Separator -->
|
<hr class="border-border/50">
|
||||||
<!-- File Manager Delete Confirmation -->
|
<!-- File Manager Delete Confirmation -->
|
||||||
<div class="settings-section-content">
|
<div class="settings-section-content">
|
||||||
<h3 class="text-base font-semibold text-foreground mb-3">{{ $t('settings.workspace.fileManagerDeleteConfirmTitle', '文件管理器删除确认') }}</h3>
|
<h3 class="text-base font-semibold text-foreground mb-3">{{ $t('settings.workspace.fileManagerDeleteConfirmTitle', '文件管理器删除确认') }}</h3>
|
||||||
@@ -183,6 +183,26 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
<hr class="border-border/50">
|
||||||
|
<!-- Terminal Right Click Paste -->
|
||||||
|
<div class="settings-section-content">
|
||||||
|
<h3 class="text-base font-semibold text-foreground mb-3">{{ $t('settings.workspace.terminalRightClickPasteTitle', '终端右键粘贴') }}</h3>
|
||||||
|
<form @submit.prevent="handleUpdateTerminalRightClickPasteSetting" class="space-y-4">
|
||||||
|
<div class="flex items-center">
|
||||||
|
<input type="checkbox" id="terminalEnableRightClickPaste" v-model="terminalEnableRightClickPasteLocal"
|
||||||
|
class="h-4 w-4 rounded border-border text-primary focus:ring-primary mr-2 cursor-pointer">
|
||||||
|
<label for="terminalEnableRightClickPaste" class="text-sm text-foreground cursor-pointer select-none">{{ $t('settings.workspace.terminalEnableRightClickPasteLabel', '启用终端右键粘贴') }}</label>
|
||||||
|
</div>
|
||||||
|
<p class="text-xs text-text-secondary mt-1">{{ $t('settings.workspace.terminalEnableRightClickPasteDescription', '允许在终端区域内使用鼠标右键粘贴剪贴板内容。') }}</p>
|
||||||
|
<div class="flex items-center justify-between pt-2">
|
||||||
|
<button type="submit"
|
||||||
|
class="px-4 py-2 bg-button text-button-text rounded-md shadow-sm hover:bg-button-hover focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary transition duration-150 ease-in-out text-sm font-medium">
|
||||||
|
{{ $t('common.save') }}
|
||||||
|
</button>
|
||||||
|
<p v-if="terminalEnableRightClickPasteMessage" :class="['text-sm', terminalEnableRightClickPasteSuccess ? 'text-success' : 'text-error']">{{ terminalEnableRightClickPasteMessage }}</p>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -243,6 +263,11 @@ const {
|
|||||||
fileManagerShowDeleteConfirmationMessage,
|
fileManagerShowDeleteConfirmationMessage,
|
||||||
fileManagerShowDeleteConfirmationSuccess,
|
fileManagerShowDeleteConfirmationSuccess,
|
||||||
handleUpdateFileManagerDeleteConfirmation,
|
handleUpdateFileManagerDeleteConfirmation,
|
||||||
|
terminalEnableRightClickPasteLocal, // NEW
|
||||||
|
terminalEnableRightClickPasteLoading, // NEW (Not used in template, but available)
|
||||||
|
terminalEnableRightClickPasteMessage, // NEW
|
||||||
|
terminalEnableRightClickPasteSuccess, // NEW
|
||||||
|
handleUpdateTerminalRightClickPasteSetting, // NEW
|
||||||
} = useWorkspaceSettings();
|
} = useWorkspaceSettings();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ export function useWorkspaceSettings() {
|
|||||||
showQuickCommandTagsBoolean,
|
showQuickCommandTagsBoolean,
|
||||||
terminalScrollbackLimitNumber,
|
terminalScrollbackLimitNumber,
|
||||||
fileManagerShowDeleteConfirmationBoolean,
|
fileManagerShowDeleteConfirmationBoolean,
|
||||||
|
terminalEnableRightClickPasteBoolean, // NEW
|
||||||
} = storeToRefs(settingsStore);
|
} = storeToRefs(settingsStore);
|
||||||
|
|
||||||
// --- Popup Editor ---
|
// --- Popup Editor ---
|
||||||
@@ -236,6 +237,30 @@ export function useWorkspaceSettings() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// --- Terminal Right Click Paste ---
|
||||||
|
const terminalEnableRightClickPasteLocal = ref(true);
|
||||||
|
const terminalEnableRightClickPasteLoading = ref(false);
|
||||||
|
const terminalEnableRightClickPasteMessage = ref('');
|
||||||
|
const terminalEnableRightClickPasteSuccess = ref(false);
|
||||||
|
|
||||||
|
const handleUpdateTerminalRightClickPasteSetting = async () => {
|
||||||
|
terminalEnableRightClickPasteLoading.value = true;
|
||||||
|
terminalEnableRightClickPasteMessage.value = '';
|
||||||
|
terminalEnableRightClickPasteSuccess.value = false;
|
||||||
|
try {
|
||||||
|
const valueToSave = terminalEnableRightClickPasteLocal.value ? 'true' : 'false';
|
||||||
|
await settingsStore.updateSetting('terminalEnableRightClickPaste', valueToSave);
|
||||||
|
terminalEnableRightClickPasteMessage.value = t('settings.workspace.terminalRightClickPasteSuccess', '终端右键粘贴设置已保存。');
|
||||||
|
terminalEnableRightClickPasteSuccess.value = true;
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error('更新终端右键粘贴设置失败:', error);
|
||||||
|
terminalEnableRightClickPasteMessage.value = error.message || t('settings.workspace.terminalRightClickPasteError', '保存终端右键粘贴设置失败。');
|
||||||
|
terminalEnableRightClickPasteSuccess.value = false;
|
||||||
|
} finally {
|
||||||
|
terminalEnableRightClickPasteLoading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Watchers to sync local state with store state
|
// Watchers to sync local state with store state
|
||||||
watch(showPopupFileEditorBoolean, (newValue) => { popupEditorEnabled.value = newValue; }, { immediate: true });
|
watch(showPopupFileEditorBoolean, (newValue) => { popupEditorEnabled.value = newValue; }, { immediate: true });
|
||||||
watch(shareFileEditorTabsBoolean, (newValue) => { shareTabsEnabled.value = newValue; }, { immediate: true });
|
watch(shareFileEditorTabsBoolean, (newValue) => { shareTabsEnabled.value = newValue; }, { immediate: true });
|
||||||
@@ -246,6 +271,7 @@ export function useWorkspaceSettings() {
|
|||||||
watch(showQuickCommandTagsBoolean, (newValue) => { showQuickCommandTagsLocal.value = newValue; }, { immediate: true });
|
watch(showQuickCommandTagsBoolean, (newValue) => { showQuickCommandTagsLocal.value = newValue; }, { immediate: true });
|
||||||
watch(terminalScrollbackLimitNumber, (newValue) => { terminalScrollbackLimitLocal.value = newValue; }, { immediate: true });
|
watch(terminalScrollbackLimitNumber, (newValue) => { terminalScrollbackLimitLocal.value = newValue; }, { immediate: true });
|
||||||
watch(fileManagerShowDeleteConfirmationBoolean, (newValue) => { fileManagerShowDeleteConfirmationLocal.value = newValue; }, { immediate: true });
|
watch(fileManagerShowDeleteConfirmationBoolean, (newValue) => { fileManagerShowDeleteConfirmationLocal.value = newValue; }, { immediate: true });
|
||||||
|
watch(terminalEnableRightClickPasteBoolean, (newValue) => { terminalEnableRightClickPasteLocal.value = newValue; }, { immediate: true }); // NEW
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -302,5 +328,11 @@ export function useWorkspaceSettings() {
|
|||||||
fileManagerShowDeleteConfirmationMessage,
|
fileManagerShowDeleteConfirmationMessage,
|
||||||
fileManagerShowDeleteConfirmationSuccess,
|
fileManagerShowDeleteConfirmationSuccess,
|
||||||
handleUpdateFileManagerDeleteConfirmation,
|
handleUpdateFileManagerDeleteConfirmation,
|
||||||
|
|
||||||
|
terminalEnableRightClickPasteLocal, // NEW
|
||||||
|
terminalEnableRightClickPasteLoading, // NEW
|
||||||
|
terminalEnableRightClickPasteMessage, // NEW
|
||||||
|
terminalEnableRightClickPasteSuccess, // NEW
|
||||||
|
handleUpdateTerminalRightClickPasteSetting, // NEW
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -62,10 +62,10 @@ interface AuthState {
|
|||||||
total: number;
|
total: number;
|
||||||
};
|
};
|
||||||
needsSetup: boolean; // 是否需要初始设置
|
needsSetup: boolean; // 是否需要初始设置
|
||||||
publicCaptchaConfig: PublicCaptchaConfig | null; // NEW: Public CAPTCHA config
|
publicCaptchaConfig: PublicCaptchaConfig | null; // Public CAPTCHA config
|
||||||
passkeys: PasskeyInfo[] | null; // NEW: Store for user's passkeys
|
passkeys: PasskeyInfo[] | null; // Store for user's passkeys
|
||||||
passkeysLoading: boolean; // NEW: Loading state for passkeys
|
passkeysLoading: boolean; // Loading state for passkeys
|
||||||
hasPasskeysAvailable: boolean; // NEW: Indicates if passkeys are available for login
|
hasPasskeysAvailable: boolean; // Indicates if passkeys are available for login
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useAuthStore = defineStore('auth', {
|
export const useAuthStore = defineStore('auth', {
|
||||||
@@ -77,7 +77,7 @@ export const useAuthStore = defineStore('auth', {
|
|||||||
loginRequires2FA: false, // 初始为不需要
|
loginRequires2FA: false, // 初始为不需要
|
||||||
ipBlacklist: { entries: [], total: 0 }, // 初始化黑名单状态
|
ipBlacklist: { entries: [], total: 0 }, // 初始化黑名单状态
|
||||||
needsSetup: false, // 初始假设不需要设置
|
needsSetup: false, // 初始假设不需要设置
|
||||||
publicCaptchaConfig: null, // NEW: Initialize CAPTCHA config as null
|
publicCaptchaConfig: null, // Initialize CAPTCHA config as null
|
||||||
passkeys: null, // Initialize passkeys as null
|
passkeys: null, // Initialize passkeys as null
|
||||||
passkeysLoading: false, // Initialize passkeysLoading as false
|
passkeysLoading: false, // Initialize passkeysLoading as false
|
||||||
hasPasskeysAvailable: false, // Initialize as false
|
hasPasskeysAvailable: false, // Initialize as false
|
||||||
@@ -322,7 +322,7 @@ export const useAuthStore = defineStore('auth', {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// NEW: 获取公共 CAPTCHA 配置 (修改为从 /settings/captcha 获取)
|
// 获取公共 CAPTCHA 配置 (修改为从 /settings/captcha 获取)
|
||||||
async fetchCaptchaConfig() {
|
async fetchCaptchaConfig() {
|
||||||
console.log('[AuthStore] fetchCaptchaConfig called. Forcing refetch.'); // 更新日志,表明强制刷新
|
console.log('[AuthStore] fetchCaptchaConfig called. Forcing refetch.'); // 更新日志,表明强制刷新
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export const useCommandHistoryStore = defineStore('commandHistory', () => {
|
|||||||
const isLoading = ref(false);
|
const isLoading = ref(false);
|
||||||
const error = ref<string | null>(null);
|
const error = ref<string | null>(null);
|
||||||
const uiNotificationsStore = useUiNotificationsStore();
|
const uiNotificationsStore = useUiNotificationsStore();
|
||||||
const selectedIndex = ref<number>(-1); // NEW: Index of the selected command in the filtered list
|
const selectedIndex = ref<number>(-1); // Index of the selected command in the filtered list
|
||||||
|
|
||||||
// --- Getters ---
|
// --- Getters ---
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ export const useCommandHistoryStore = defineStore('commandHistory', () => {
|
|||||||
|
|
||||||
// --- Actions ---
|
// --- Actions ---
|
||||||
|
|
||||||
// NEW: Action to select the next command in the filtered list
|
// Action to select the next command in the filtered list
|
||||||
const selectNextCommand = () => {
|
const selectNextCommand = () => {
|
||||||
const history = filteredHistory.value;
|
const history = filteredHistory.value;
|
||||||
if (history.length === 0) {
|
if (history.length === 0) {
|
||||||
@@ -48,7 +48,7 @@ export const useCommandHistoryStore = defineStore('commandHistory', () => {
|
|||||||
selectedIndex.value = (selectedIndex.value + 1) % history.length;
|
selectedIndex.value = (selectedIndex.value + 1) % history.length;
|
||||||
};
|
};
|
||||||
|
|
||||||
// NEW: Action to select the previous command in the filtered list
|
// Action to select the previous command in the filtered list
|
||||||
const selectPreviousCommand = () => {
|
const selectPreviousCommand = () => {
|
||||||
const history = filteredHistory.value;
|
const history = filteredHistory.value;
|
||||||
if (history.length === 0) {
|
if (history.length === 0) {
|
||||||
@@ -110,7 +110,7 @@ export const useCommandHistoryStore = defineStore('commandHistory', () => {
|
|||||||
|
|
||||||
// 添加命令到历史记录 (由 CommandInputBar 调用, 添加后清除缓存)
|
// 添加命令到历史记录 (由 CommandInputBar 调用, 添加后清除缓存)
|
||||||
const addCommand = async (command: string) => {
|
const addCommand = async (command: string) => {
|
||||||
// NEW: Filter out Ctrl+C signal (\x03) from being added to history
|
// Filter out Ctrl+C signal (\x03) from being added to history
|
||||||
if (command === '\x03') {
|
if (command === '\x03') {
|
||||||
console.log('[CmdHistoryStore] Ignoring Ctrl+C signal for history.');
|
console.log('[CmdHistoryStore] Ignoring Ctrl+C signal for history.');
|
||||||
return;
|
return;
|
||||||
@@ -172,7 +172,7 @@ export const useCommandHistoryStore = defineStore('commandHistory', () => {
|
|||||||
selectedIndex.value = -1; // Reset selection when search term changes
|
selectedIndex.value = -1; // Reset selection when search term changes
|
||||||
};
|
};
|
||||||
|
|
||||||
// NEW: Action to reset the selection (Moved before return)
|
// Action to reset the selection (Moved before return)
|
||||||
const resetSelection = () => {
|
const resetSelection = () => {
|
||||||
selectedIndex.value = -1;
|
selectedIndex.value = -1;
|
||||||
};
|
};
|
||||||
@@ -183,14 +183,14 @@ export const useCommandHistoryStore = defineStore('commandHistory', () => {
|
|||||||
isLoading,
|
isLoading,
|
||||||
error,
|
error,
|
||||||
filteredHistory,
|
filteredHistory,
|
||||||
selectedIndex, // NEW: Expose selected index
|
selectedIndex, // Expose selected index
|
||||||
fetchHistory,
|
fetchHistory,
|
||||||
addCommand, // 导出 addCommand
|
addCommand, // 导出 addCommand
|
||||||
deleteCommand,
|
deleteCommand,
|
||||||
clearAllHistory,
|
clearAllHistory,
|
||||||
setSearchTerm,
|
setSearchTerm,
|
||||||
selectNextCommand, // NEW: Expose action
|
selectNextCommand, // Expose action
|
||||||
selectPreviousCommand, // NEW: Expose action
|
selectPreviousCommand, // Expose action
|
||||||
resetSelection, // Ensure resetSelection is exported
|
resetSelection, // Ensure resetSelection is exported
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -398,7 +398,7 @@ export const useQuickCommandsStore = defineStore('quickCommands', () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// NEW: Action to reset the selection
|
// Action to reset the selection
|
||||||
const resetSelection = () => {
|
const resetSelection = () => {
|
||||||
selectedIndex.value = -1;
|
selectedIndex.value = -1;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -39,27 +39,28 @@ interface SettingsState {
|
|||||||
shareFileEditorTabs?: string; // 'true' or 'false'
|
shareFileEditorTabs?: string; // 'true' or 'false'
|
||||||
ipWhitelistEnabled?: string; // 添加 IP 白名单启用状态 'true' or 'false'
|
ipWhitelistEnabled?: string; // 添加 IP 白名单启用状态 'true' or 'false'
|
||||||
autoCopyOnSelect?: string; // 'true' or 'false' - 终端选中自动复制
|
autoCopyOnSelect?: string; // 'true' or 'false' - 终端选中自动复制
|
||||||
dockerStatusIntervalSeconds?: string; // NEW: Docker 状态刷新间隔 (秒)
|
dockerStatusIntervalSeconds?: string; // Docker 状态刷新间隔 (秒)
|
||||||
dockerDefaultExpand?: string; // NEW: Docker 默认展开详情 'true' or 'false'
|
dockerDefaultExpand?: string; // Docker 默认展开详情 'true' or 'false'
|
||||||
statusMonitorIntervalSeconds?: string; // NEW: 状态监控轮询间隔 (秒)
|
statusMonitorIntervalSeconds?: string; // 状态监控轮询间隔 (秒)
|
||||||
workspaceSidebarPersistent?: string; // NEW: 工作区侧边栏是否固定 'true' or 'false'
|
workspaceSidebarPersistent?: string; // 工作区侧边栏是否固定 'true' or 'false'
|
||||||
sidebarPaneWidths?: string; // NEW: 存储各侧边栏组件宽度的 JSON 字符串
|
sidebarPaneWidths?: string; // 存储各侧边栏组件宽度的 JSON 字符串
|
||||||
fileManagerRowSizeMultiplier?: string; // NEW: 文件管理器行大小乘数 (e.g., '1.0')
|
fileManagerRowSizeMultiplier?: string; // 文件管理器行大小乘数 (e.g., '1.0')
|
||||||
fileManagerColWidths?: string; // NEW: 文件管理器列宽 JSON 字符串 (e.g., '{"name": 300, "size": 100}')
|
fileManagerColWidths?: string; // 文件管理器列宽 JSON 字符串 (e.g., '{"name": 300, "size": 100}')
|
||||||
commandInputSyncTarget?: 'quickCommands' | 'commandHistory' | 'none'; // NEW: 命令输入同步目标
|
commandInputSyncTarget?: 'quickCommands' | 'commandHistory' | 'none'; // 命令输入同步目标
|
||||||
timezone?: string; // NEW: 时区设置 (e.g., 'Asia/Shanghai', 'UTC')
|
timezone?: string; // 时区设置 (e.g., 'Asia/Shanghai', 'UTC')
|
||||||
rdpModalWidth?: string; // NEW: RDP 模态框宽度
|
rdpModalWidth?: string; // RDP 模态框宽度
|
||||||
rdpModalHeight?: string; // NEW: RDP 模态框高度
|
rdpModalHeight?: string; // RDP 模态框高度
|
||||||
vncModalWidth?: string; // NEW: VNC 模态框宽度
|
vncModalWidth?: string; // VNC 模态框宽度
|
||||||
vncModalHeight?: string; // NEW: VNC 模态框高度
|
vncModalHeight?: string; // VNC 模态框高度
|
||||||
ipBlacklistEnabled?: string;
|
ipBlacklistEnabled?: string;
|
||||||
dashboardSortBy?: SortField;
|
dashboardSortBy?: SortField;
|
||||||
dashboardSortOrder?: SortOrder;
|
dashboardSortOrder?: SortOrder;
|
||||||
showConnectionTags?: string; // 'true' or 'false'
|
showConnectionTags?: string; // 'true' or 'false'
|
||||||
showQuickCommandTags?: string; // 'true' or 'false'
|
showQuickCommandTags?: string; // 'true' or 'false'
|
||||||
layoutLocked?: string; // 'true' or 'false' - NEW: 布局锁定状态
|
layoutLocked?: string; // 'true' or 'false' - NEW: 布局锁定状态
|
||||||
terminalScrollbackLimit?: string; // NEW: 终端回滚行数上限 (e.g., '5000', '0' for unlimited)
|
terminalScrollbackLimit?: string; // 终端回滚行数上限 (e.g., '5000', '0' for unlimited)
|
||||||
fileManagerShowDeleteConfirmation?: string; // NEW: 'true' or 'false' - 文件管理器删除确认提示
|
fileManagerShowDeleteConfirmation?: string; // 'true' or 'false' - 文件管理器删除确认提示
|
||||||
|
terminalEnableRightClickPaste?: string; // 'true' or 'false' - 终端右键粘贴
|
||||||
[key: string]: string | undefined;
|
[key: string]: string | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,9 +70,9 @@ export const useSettingsStore = defineStore('settings', () => {
|
|||||||
|
|
||||||
// --- State ---
|
// --- State ---
|
||||||
const settings = ref<Partial<SettingsState>>({}); // 通用设置状态
|
const settings = ref<Partial<SettingsState>>({}); // 通用设置状态
|
||||||
const parsedSidebarPaneWidths = ref<Record<string, string>>({}); // NEW: 解析后的侧边栏宽度对象
|
const parsedSidebarPaneWidths = ref<Record<string, string>>({}); // 解析后的侧边栏宽度对象
|
||||||
const parsedFileManagerColWidths = ref<Record<string, number>>({}); // NEW: 解析后的文件管理器列宽对象
|
const parsedFileManagerColWidths = ref<Record<string, number>>({}); // 解析后的文件管理器列宽对象
|
||||||
const captchaSettings = ref<CaptchaSettings | null>(null); // NEW: CAPTCHA 设置状态
|
const captchaSettings = ref<CaptchaSettings | null>(null); // CAPTCHA 设置状态
|
||||||
const isLoading = ref(false);
|
const isLoading = ref(false);
|
||||||
const error = ref<string | null>(null);
|
const error = ref<string | null>(null);
|
||||||
// 移除外观相关状态: isStyleCustomizerVisible, currentUiTheme, currentXtermTheme
|
// 移除外观相关状态: isStyleCustomizerVisible, currentUiTheme, currentXtermTheme
|
||||||
@@ -127,7 +128,7 @@ export const useSettingsStore = defineStore('settings', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// NEW: IP Blacklist enabled default
|
// IP Blacklist enabled default
|
||||||
if (settings.value.ipBlacklistEnabled === undefined) {
|
if (settings.value.ipBlacklistEnabled === undefined) {
|
||||||
settings.value.ipBlacklistEnabled = 'true'; // 默认启用 IP 黑名单
|
settings.value.ipBlacklistEnabled = 'true'; // 默认启用 IP 黑名单
|
||||||
}
|
}
|
||||||
@@ -135,22 +136,22 @@ export const useSettingsStore = defineStore('settings', () => {
|
|||||||
if (settings.value.autoCopyOnSelect === undefined) {
|
if (settings.value.autoCopyOnSelect === undefined) {
|
||||||
settings.value.autoCopyOnSelect = 'false'; // 默认禁用选中即复制
|
settings.value.autoCopyOnSelect = 'false'; // 默认禁用选中即复制
|
||||||
}
|
}
|
||||||
// NEW: Docker setting defaults
|
// Docker setting defaults
|
||||||
if (settings.value.dockerStatusIntervalSeconds === undefined) {
|
if (settings.value.dockerStatusIntervalSeconds === undefined) {
|
||||||
settings.value.dockerStatusIntervalSeconds = '2'; // 默认 2 秒
|
settings.value.dockerStatusIntervalSeconds = '2'; // 默认 2 秒
|
||||||
}
|
}
|
||||||
if (settings.value.dockerDefaultExpand === undefined) {
|
if (settings.value.dockerDefaultExpand === undefined) {
|
||||||
settings.value.dockerDefaultExpand = 'false'; // 默认不展开
|
settings.value.dockerDefaultExpand = 'false'; // 默认不展开
|
||||||
}
|
}
|
||||||
// NEW: Status Monitor interval default
|
// Status Monitor interval default
|
||||||
if (settings.value.statusMonitorIntervalSeconds === undefined) {
|
if (settings.value.statusMonitorIntervalSeconds === undefined) {
|
||||||
settings.value.statusMonitorIntervalSeconds = '3'; // 默认 3 秒
|
settings.value.statusMonitorIntervalSeconds = '3'; // 默认 3 秒
|
||||||
}
|
}
|
||||||
// NEW: Workspace sidebar persistent default
|
// Workspace sidebar persistent default
|
||||||
if (settings.value.workspaceSidebarPersistent === undefined) {
|
if (settings.value.workspaceSidebarPersistent === undefined) {
|
||||||
settings.value.workspaceSidebarPersistent = 'false'; // 默认不固定
|
settings.value.workspaceSidebarPersistent = 'false'; // 默认不固定
|
||||||
}
|
}
|
||||||
// NEW: Load and parse sidebar pane widths
|
// Load and parse sidebar pane widths
|
||||||
const defaultPaneWidth = '350px';
|
const defaultPaneWidth = '350px';
|
||||||
// +++ Ensure PaneName type is available or define it here +++
|
// +++ Ensure PaneName type is available or define it here +++
|
||||||
const knownPanes: PaneName[] = ['connections', 'fileManager', 'editor', 'statusMonitor', 'commandHistory', 'quickCommands', 'dockerManager']; // Add all possible sidebar panes
|
const knownPanes: PaneName[] = ['connections', 'fileManager', 'editor', 'statusMonitor', 'commandHistory', 'quickCommands', 'dockerManager']; // Add all possible sidebar panes
|
||||||
@@ -178,7 +179,7 @@ export const useSettingsStore = defineStore('settings', () => {
|
|||||||
// await updateSetting('sidebarPaneWidths', JSON.stringify(finalWidths));
|
// await updateSetting('sidebarPaneWidths', JSON.stringify(finalWidths));
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// NEW: Load and parse file manager layout settings
|
// Load and parse file manager layout settings
|
||||||
const defaultFileManagerRowMultiplier = '1.0';
|
const defaultFileManagerRowMultiplier = '1.0';
|
||||||
const defaultFileManagerColWidths = { type: 50, name: 300, size: 100, permissions: 120, modified: 180 };
|
const defaultFileManagerColWidths = { type: 50, name: 300, size: 100, permissions: 120, modified: 180 };
|
||||||
|
|
||||||
@@ -237,22 +238,22 @@ export const useSettingsStore = defineStore('settings', () => {
|
|||||||
// await updateSetting('fileManagerColWidths', finalFmWidthsString);
|
// await updateSetting('fileManagerColWidths', finalFmWidthsString);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// NEW: Command Input Sync Target default
|
// Command Input Sync Target default
|
||||||
if (settings.value.commandInputSyncTarget === undefined) {
|
if (settings.value.commandInputSyncTarget === undefined) {
|
||||||
settings.value.commandInputSyncTarget = 'none'; // 默认不同步
|
settings.value.commandInputSyncTarget = 'none'; // 默认不同步
|
||||||
}
|
}
|
||||||
// NEW: Timezone default
|
// Timezone default
|
||||||
if (settings.value.timezone === undefined) {
|
if (settings.value.timezone === undefined) {
|
||||||
settings.value.timezone = 'UTC'; // 默认 UTC
|
settings.value.timezone = 'UTC'; // 默认 UTC
|
||||||
}
|
}
|
||||||
// NEW: RDP Modal Size defaults
|
// RDP Modal Size defaults
|
||||||
if (settings.value.rdpModalWidth === undefined) {
|
if (settings.value.rdpModalWidth === undefined) {
|
||||||
settings.value.rdpModalWidth = '1064'; // 默认宽度 (1024 + 40 padding)
|
settings.value.rdpModalWidth = '1064'; // 默认宽度 (1024 + 40 padding)
|
||||||
}
|
}
|
||||||
if (settings.value.rdpModalHeight === undefined) {
|
if (settings.value.rdpModalHeight === undefined) {
|
||||||
settings.value.rdpModalHeight = '858';
|
settings.value.rdpModalHeight = '858';
|
||||||
}
|
}
|
||||||
// NEW: VNC Modal Size defaults
|
// VNC Modal Size defaults
|
||||||
if (settings.value.vncModalWidth === undefined) {
|
if (settings.value.vncModalWidth === undefined) {
|
||||||
settings.value.vncModalWidth = '1024'; // 默认宽度
|
settings.value.vncModalWidth = '1024'; // 默认宽度
|
||||||
}
|
}
|
||||||
@@ -267,30 +268,38 @@ export const useSettingsStore = defineStore('settings', () => {
|
|||||||
settings.value.dashboardSortOrder = 'desc';
|
settings.value.dashboardSortOrder = 'desc';
|
||||||
}
|
}
|
||||||
|
|
||||||
// NEW: Tag visibility defaults
|
// Tag visibility defaults
|
||||||
if (settings.value.showConnectionTags === undefined) {
|
if (settings.value.showConnectionTags === undefined) {
|
||||||
settings.value.showConnectionTags = 'true'; // 默认显示
|
settings.value.showConnectionTags = 'true'; // 默认显示
|
||||||
}
|
}
|
||||||
if (settings.value.showQuickCommandTags === undefined) {
|
if (settings.value.showQuickCommandTags === undefined) {
|
||||||
settings.value.showQuickCommandTags = 'true'; // 默认显示
|
settings.value.showQuickCommandTags = 'true'; // 默认显示
|
||||||
} // +++ Add missing closing brace +++
|
} // +++ Add missing closing brace +++
|
||||||
// NEW: Layout locked default - Only set if not provided by backend
|
// Layout locked default - Only set if not provided by backend
|
||||||
if (settings.value.layoutLocked === undefined) {
|
if (settings.value.layoutLocked === undefined) {
|
||||||
settings.value.layoutLocked = 'false'; // 默认不锁定
|
settings.value.layoutLocked = 'false'; // 默认不锁定
|
||||||
console.log('[SettingsStore] layoutLocked not found in fetched settings, set to default: false');
|
console.log('[SettingsStore] layoutLocked not found in fetched settings, set to default: false');
|
||||||
} else {
|
} else {
|
||||||
console.log(`[SettingsStore] layoutLocked found in fetched settings: ${settings.value.layoutLocked}`);
|
console.log(`[SettingsStore] layoutLocked found in fetched settings: ${settings.value.layoutLocked}`);
|
||||||
}
|
}
|
||||||
// NEW: Terminal scrollback limit default
|
// Terminal scrollback limit default
|
||||||
if (settings.value.terminalScrollbackLimit === undefined) {
|
if (settings.value.terminalScrollbackLimit === undefined) {
|
||||||
settings.value.terminalScrollbackLimit = '5000'; // 默认 5000 行
|
settings.value.terminalScrollbackLimit = '5000'; // 默认 5000 行
|
||||||
console.log(`[SettingsStore] terminalScrollbackLimit not found, set to default: ${settings.value.terminalScrollbackLimit}`);
|
console.log(`[SettingsStore] terminalScrollbackLimit not found, set to default: ${settings.value.terminalScrollbackLimit}`);
|
||||||
}
|
}
|
||||||
// NEW: File Manager Delete Confirmation default
|
// File Manager Delete Confirmation default
|
||||||
if (settings.value.fileManagerShowDeleteConfirmation === undefined) {
|
if (settings.value.fileManagerShowDeleteConfirmation === undefined) {
|
||||||
settings.value.fileManagerShowDeleteConfirmation = 'true'; // 默认显示删除确认
|
settings.value.fileManagerShowDeleteConfirmation = 'true'; // 默认显示删除确认
|
||||||
console.log(`[SettingsStore] fileManagerShowDeleteConfirmation not found, set to default: ${settings.value.fileManagerShowDeleteConfirmation}`);
|
console.log(`[SettingsStore] fileManagerShowDeleteConfirmation not found, set to default: ${settings.value.fileManagerShowDeleteConfirmation}`);
|
||||||
}
|
}
|
||||||
|
// Terminal Right Click Paste default
|
||||||
|
// --- 添加日志:打印从后端获取的原始值 ---
|
||||||
|
console.log(`[SettingsStore DEBUG] Raw terminalEnableRightClickPaste from backend: '${settings.value.terminalEnableRightClickPaste}' (type: ${typeof settings.value.terminalEnableRightClickPaste})`);
|
||||||
|
// --- 日志结束 ---
|
||||||
|
if (settings.value.terminalEnableRightClickPaste === undefined) {
|
||||||
|
settings.value.terminalEnableRightClickPaste = 'true'; // 默认启用右键粘贴
|
||||||
|
console.log(`[SettingsStore] terminalEnableRightClickPaste not found, set to default: ${settings.value.terminalEnableRightClickPaste}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// --- 语言设置 ---
|
// --- 语言设置 ---
|
||||||
@@ -370,11 +379,11 @@ export const useSettingsStore = defineStore('settings', () => {
|
|||||||
'fileManagerRowSizeMultiplier', // +++ 添加文件管理器行大小键 +++
|
'fileManagerRowSizeMultiplier', // +++ 添加文件管理器行大小键 +++
|
||||||
'fileManagerColWidths', // +++ 添加文件管理器列宽键 +++
|
'fileManagerColWidths', // +++ 添加文件管理器列宽键 +++
|
||||||
'commandInputSyncTarget', // +++ 添加命令输入同步目标键 +++
|
'commandInputSyncTarget', // +++ 添加命令输入同步目标键 +++
|
||||||
'timezone', // NEW: 添加时区键
|
'timezone', // 添加时区键
|
||||||
'rdpModalWidth', // NEW: 添加 RDP 模态框宽度键
|
'rdpModalWidth', // 添加 RDP 模态框宽度键
|
||||||
'rdpModalHeight', // NEW: 添加 RDP 模态框高度键
|
'rdpModalHeight', // 添加 RDP 模态框高度键
|
||||||
'vncModalWidth', // NEW: 添加 VNC 模态框宽度键
|
'vncModalWidth', // 添加 VNC 模态框宽度键
|
||||||
'vncModalHeight', // NEW: 添加 VNC 模态框高度键
|
'vncModalHeight', // 添加 VNC 模态框高度键
|
||||||
'ipBlacklistEnabled',
|
'ipBlacklistEnabled',
|
||||||
'dashboardSortBy',
|
'dashboardSortBy',
|
||||||
'dashboardSortOrder',
|
'dashboardSortOrder',
|
||||||
@@ -382,7 +391,8 @@ export const useSettingsStore = defineStore('settings', () => {
|
|||||||
'showQuickCommandTags', // NEW
|
'showQuickCommandTags', // NEW
|
||||||
'layoutLocked', // NEW
|
'layoutLocked', // NEW
|
||||||
'terminalScrollbackLimit', // NEW
|
'terminalScrollbackLimit', // NEW
|
||||||
'fileManagerShowDeleteConfirmation' // NEW
|
'fileManagerShowDeleteConfirmation', // NEW
|
||||||
|
'terminalEnableRightClickPaste' // NEW
|
||||||
];
|
];
|
||||||
if (!allowedKeys.includes(key)) {
|
if (!allowedKeys.includes(key)) {
|
||||||
console.error(`[SettingsStore] 尝试更新不允许的设置键: ${key}`);
|
console.error(`[SettingsStore] 尝试更新不允许的设置键: ${key}`);
|
||||||
@@ -405,6 +415,11 @@ export const useSettingsStore = defineStore('settings', () => {
|
|||||||
console.log(`[SettingsStore] Attempting to update boolean setting via specific endpoint - Key: ${key}, Value: ${value}, Endpoint: ${endpoint}`);
|
console.log(`[SettingsStore] Attempting to update boolean setting via specific endpoint - Key: ${key}, Value: ${value}, Endpoint: ${endpoint}`);
|
||||||
apiPromise = apiClient.put(endpoint, { enabled: value });
|
apiPromise = apiClient.put(endpoint, { enabled: value });
|
||||||
} else if (typeof value === 'string') {
|
} else if (typeof value === 'string') {
|
||||||
|
// --- 添加针对 terminalEnableRightClickPaste 的特定日志 ---
|
||||||
|
if (key === 'terminalEnableRightClickPaste') {
|
||||||
|
console.log(`[SettingsStore DEBUG] Updating terminalEnableRightClickPaste. Value type: ${typeof value}, Value: '${value}'`);
|
||||||
|
}
|
||||||
|
// --- 日志结束 ---
|
||||||
console.log(`[SettingsStore] Attempting to update general setting - Key: ${key}, Value: ${value}`);
|
console.log(`[SettingsStore] Attempting to update general setting - Key: ${key}, Value: ${value}`);
|
||||||
const payload = { [key]: value };
|
const payload = { [key]: value };
|
||||||
console.log('[SettingsStore] Sending PUT request to /settings with payload:', payload);
|
console.log('[SettingsStore] Sending PUT request to /settings with payload:', payload);
|
||||||
@@ -459,11 +474,11 @@ export const useSettingsStore = defineStore('settings', () => {
|
|||||||
'fileManagerRowSizeMultiplier', // +++ 添加文件管理器行大小键 +++
|
'fileManagerRowSizeMultiplier', // +++ 添加文件管理器行大小键 +++
|
||||||
'fileManagerColWidths', // +++ 添加文件管理器列宽键 +++
|
'fileManagerColWidths', // +++ 添加文件管理器列宽键 +++
|
||||||
'commandInputSyncTarget', // +++ 添加命令输入同步目标键 +++
|
'commandInputSyncTarget', // +++ 添加命令输入同步目标键 +++
|
||||||
'timezone', // NEW: 添加时区键
|
'timezone', // 添加时区键
|
||||||
'rdpModalWidth', // NEW: 添加 RDP 模态框宽度键
|
'rdpModalWidth', // 添加 RDP 模态框宽度键
|
||||||
'rdpModalHeight', // NEW: 添加 RDP 模态框高度键
|
'rdpModalHeight', // 添加 RDP 模态框高度键
|
||||||
'vncModalWidth', // NEW: 添加 VNC 模态框宽度键
|
'vncModalWidth', // 添加 VNC 模态框宽度键
|
||||||
'vncModalHeight', // NEW: 添加 VNC 模态框高度键
|
'vncModalHeight', // 添加 VNC 模态框高度键
|
||||||
'ipBlacklistEnabled',
|
'ipBlacklistEnabled',
|
||||||
'dashboardSortBy',
|
'dashboardSortBy',
|
||||||
'dashboardSortOrder',
|
'dashboardSortOrder',
|
||||||
@@ -471,7 +486,8 @@ export const useSettingsStore = defineStore('settings', () => {
|
|||||||
'showQuickCommandTags', // NEW
|
'showQuickCommandTags', // NEW
|
||||||
'layoutLocked', // NEW
|
'layoutLocked', // NEW
|
||||||
'terminalScrollbackLimit', // NEW
|
'terminalScrollbackLimit', // NEW
|
||||||
'fileManagerShowDeleteConfirmation' // NEW
|
'fileManagerShowDeleteConfirmation', // NEW
|
||||||
|
'terminalEnableRightClickPaste' // NEW
|
||||||
];
|
];
|
||||||
const filteredUpdates: Partial<SettingsState> = {};
|
const filteredUpdates: Partial<SettingsState> = {};
|
||||||
let languageUpdate: string | undefined = undefined;
|
let languageUpdate: string | undefined = undefined;
|
||||||
@@ -667,12 +683,12 @@ export const useSettingsStore = defineStore('settings', () => {
|
|||||||
return settings.value.autoCopyOnSelect === 'true';
|
return settings.value.autoCopyOnSelect === 'true';
|
||||||
});
|
});
|
||||||
|
|
||||||
// NEW: Getter for workspace sidebar persistent setting, returning boolean
|
// Getter for workspace sidebar persistent setting, returning boolean
|
||||||
const workspaceSidebarPersistentBoolean = computed(() => {
|
const workspaceSidebarPersistentBoolean = computed(() => {
|
||||||
return settings.value.workspaceSidebarPersistent === 'true';
|
return settings.value.workspaceSidebarPersistent === 'true';
|
||||||
});
|
});
|
||||||
|
|
||||||
// NEW: Getter to get width for a specific sidebar pane
|
// Getter to get width for a specific sidebar pane
|
||||||
const getSidebarPaneWidth = computed(() => (paneName: PaneName | null): string => {
|
const getSidebarPaneWidth = computed(() => (paneName: PaneName | null): string => {
|
||||||
const defaultWidth = '350px';
|
const defaultWidth = '350px';
|
||||||
if (!paneName) return defaultWidth;
|
if (!paneName) return defaultWidth;
|
||||||
@@ -681,30 +697,30 @@ export const useSettingsStore = defineStore('settings', () => {
|
|||||||
return widths[paneName] || defaultWidth;
|
return widths[paneName] || defaultWidth;
|
||||||
});
|
});
|
||||||
|
|
||||||
// NEW: Getter for Docker default expand setting, returning boolean
|
// Getter for Docker default expand setting, returning boolean
|
||||||
const dockerDefaultExpandBoolean = computed(() => {
|
const dockerDefaultExpandBoolean = computed(() => {
|
||||||
return settings.value.dockerDefaultExpand === 'true';
|
return settings.value.dockerDefaultExpand === 'true';
|
||||||
});
|
});
|
||||||
|
|
||||||
// NEW: Getter for Status Monitor interval, returning number
|
// Getter for Status Monitor interval, returning number
|
||||||
const statusMonitorIntervalSecondsNumber = computed(() => {
|
const statusMonitorIntervalSecondsNumber = computed(() => {
|
||||||
const val = parseInt(settings.value.statusMonitorIntervalSeconds || '3', 10);
|
const val = parseInt(settings.value.statusMonitorIntervalSeconds || '3', 10);
|
||||||
return isNaN(val) || val <= 0 ? 3 : val; // Fallback to 3 if invalid
|
return isNaN(val) || val <= 0 ? 3 : val; // Fallback to 3 if invalid
|
||||||
});
|
});
|
||||||
|
|
||||||
// NEW: Getter for File Manager row size multiplier, returning number
|
// Getter for File Manager row size multiplier, returning number
|
||||||
const fileManagerRowSizeMultiplierNumber = computed(() => {
|
const fileManagerRowSizeMultiplierNumber = computed(() => {
|
||||||
const val = parseFloat(settings.value.fileManagerRowSizeMultiplier || '1.0');
|
const val = parseFloat(settings.value.fileManagerRowSizeMultiplier || '1.0');
|
||||||
return isNaN(val) || val <= 0 ? 1.0 : val; // Fallback to 1.0 if invalid
|
return isNaN(val) || val <= 0 ? 1.0 : val; // Fallback to 1.0 if invalid
|
||||||
});
|
});
|
||||||
|
|
||||||
// NEW: Getter for File Manager column widths, returning object
|
// Getter for File Manager column widths, returning object
|
||||||
const fileManagerColWidthsObject = computed(() => {
|
const fileManagerColWidthsObject = computed(() => {
|
||||||
// Return the reactive ref directly, which is updated during load and save
|
// Return the reactive ref directly, which is updated during load and save
|
||||||
return parsedFileManagerColWidths.value;
|
return parsedFileManagerColWidths.value;
|
||||||
});
|
});
|
||||||
|
|
||||||
// NEW: Getter for command input sync target
|
// Getter for command input sync target
|
||||||
const commandInputSyncTarget = computed(() => {
|
const commandInputSyncTarget = computed(() => {
|
||||||
const target = settings.value.commandInputSyncTarget;
|
const target = settings.value.commandInputSyncTarget;
|
||||||
if (target === 'quickCommands' || target === 'commandHistory') {
|
if (target === 'quickCommands' || target === 'commandHistory') {
|
||||||
@@ -713,7 +729,7 @@ export const useSettingsStore = defineStore('settings', () => {
|
|||||||
return 'none'; // Default to 'none' if invalid or not set
|
return 'none'; // Default to 'none' if invalid or not set
|
||||||
});
|
});
|
||||||
|
|
||||||
// NEW: Getter for timezone setting
|
// Getter for timezone setting
|
||||||
const timezone = computed(() => settings.value.timezone || 'UTC');
|
const timezone = computed(() => settings.value.timezone || 'UTC');
|
||||||
|
|
||||||
const dashboardSortBy = computed((): SortField => {
|
const dashboardSortBy = computed((): SortField => {
|
||||||
@@ -733,7 +749,7 @@ export const useSettingsStore = defineStore('settings', () => {
|
|||||||
const recaptchaSiteKey = computed(() => captchaSettings.value?.recaptchaSiteKey ?? '');
|
const recaptchaSiteKey = computed(() => captchaSettings.value?.recaptchaSiteKey ?? '');
|
||||||
// DO NOT expose secret keys via getters
|
// DO NOT expose secret keys via getters
|
||||||
|
|
||||||
// NEW: Getters for tag visibility
|
// Getters for tag visibility
|
||||||
const showConnectionTagsBoolean = computed(() => {
|
const showConnectionTagsBoolean = computed(() => {
|
||||||
return settings.value.showConnectionTags !== 'false'; // Default to true
|
return settings.value.showConnectionTags !== 'false'; // Default to true
|
||||||
});
|
});
|
||||||
@@ -741,12 +757,12 @@ export const useSettingsStore = defineStore('settings', () => {
|
|||||||
return settings.value.showQuickCommandTags !== 'false'; // Default to true
|
return settings.value.showQuickCommandTags !== 'false'; // Default to true
|
||||||
});
|
});
|
||||||
|
|
||||||
// NEW: Getter for layout locked status
|
// Getter for layout locked status
|
||||||
const layoutLockedBoolean = computed(() => {
|
const layoutLockedBoolean = computed(() => {
|
||||||
return settings.value.layoutLocked === 'true';
|
return settings.value.layoutLocked === 'true';
|
||||||
});
|
});
|
||||||
|
|
||||||
// NEW: Getter for terminal scrollback limit, returning number (0 means Infinity for xterm)
|
// Getter for terminal scrollback limit, returning number (0 means Infinity for xterm)
|
||||||
const terminalScrollbackLimitNumber = computed(() => {
|
const terminalScrollbackLimitNumber = computed(() => {
|
||||||
const valStr = settings.value.terminalScrollbackLimit;
|
const valStr = settings.value.terminalScrollbackLimit;
|
||||||
if (valStr === null || valStr === undefined || valStr.trim() === '') {
|
if (valStr === null || valStr === undefined || valStr.trim() === '') {
|
||||||
@@ -759,10 +775,15 @@ export const useSettingsStore = defineStore('settings', () => {
|
|||||||
return val; // Return 0 if it's 0, or the positive number
|
return val; // Return 0 if it's 0, or the positive number
|
||||||
});
|
});
|
||||||
|
|
||||||
// NEW: Getter for File Manager delete confirmation, returning boolean
|
// Getter for File Manager delete confirmation, returning boolean
|
||||||
const fileManagerShowDeleteConfirmationBoolean = computed(() => {
|
const fileManagerShowDeleteConfirmationBoolean = computed(() => {
|
||||||
return settings.value.fileManagerShowDeleteConfirmation !== 'false'; // Default to true
|
return settings.value.fileManagerShowDeleteConfirmation !== 'false'; // Default to true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Getter for Terminal Right Click Paste, returning boolean
|
||||||
|
const terminalEnableRightClickPasteBoolean = computed(() => {
|
||||||
|
return settings.value.terminalEnableRightClickPaste !== 'false'; // Default to true
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
settings, // 只包含通用设置
|
settings, // 只包含通用设置
|
||||||
@@ -799,12 +820,13 @@ export const useSettingsStore = defineStore('settings', () => {
|
|||||||
dashboardSortBy,
|
dashboardSortBy,
|
||||||
dashboardSortOrder,
|
dashboardSortOrder,
|
||||||
saveDashboardSortPreference,
|
saveDashboardSortPreference,
|
||||||
// NEW: Expose tag visibility getters
|
// Expose tag visibility getters
|
||||||
showConnectionTagsBoolean,
|
showConnectionTagsBoolean,
|
||||||
showQuickCommandTagsBoolean,
|
showQuickCommandTagsBoolean,
|
||||||
// NEW: Expose layout locked getter
|
// Expose layout locked getter
|
||||||
layoutLockedBoolean,
|
layoutLockedBoolean,
|
||||||
terminalScrollbackLimitNumber, // NEW: Expose terminal scrollback limit getter
|
terminalScrollbackLimitNumber, // Expose terminal scrollback limit getter
|
||||||
fileManagerShowDeleteConfirmationBoolean, // NEW: Expose file manager delete confirmation getter
|
fileManagerShowDeleteConfirmationBoolean, // Expose file manager delete confirmation getter
|
||||||
|
terminalEnableRightClickPasteBoolean, // Expose terminal right click paste getter
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -19,9 +19,9 @@ const credentials = reactive({
|
|||||||
});
|
});
|
||||||
const twoFactorToken = ref(''); // 用于存储 2FA 验证码
|
const twoFactorToken = ref(''); // 用于存储 2FA 验证码
|
||||||
const rememberMe = ref(false); // 记住我状态,默认为 false
|
const rememberMe = ref(false); // 记住我状态,默认为 false
|
||||||
const captchaToken = ref<string | null>(null); // NEW: Store CAPTCHA token
|
const captchaToken = ref<string | null>(null); // Store CAPTCHA token
|
||||||
const captchaError = ref<string | null>(null); // NEW: Store CAPTCHA specific error
|
const captchaError = ref<string | null>(null); // Store CAPTCHA specific error
|
||||||
const hcaptchaWidget = ref<InstanceType<typeof VueHcaptcha> | null>(null); // NEW: Ref for hCaptcha component instance
|
const hcaptchaWidget = ref<InstanceType<typeof VueHcaptcha> | null>(null); // Ref for hCaptcha component instance
|
||||||
const recaptchaWidget = ref<InstanceType<typeof VueRecaptcha> | null>(null); // 更新 Ref 类型以匹配新导入
|
const recaptchaWidget = ref<InstanceType<typeof VueRecaptcha> | null>(null); // 更新 Ref 类型以匹配新导入
|
||||||
|
|
||||||
// --- reCAPTCHA v3 Initialization ---
|
// --- reCAPTCHA v3 Initialization ---
|
||||||
|
|||||||
Reference in New Issue
Block a user