This commit is contained in:
Baobhan Sith
2025-05-01 17:54:08 +08:00
parent 56af869bcc
commit 164cc343d7
5 changed files with 45 additions and 17 deletions
@@ -16,14 +16,15 @@ interface ConnectionBase {
created_at: number;
updated_at: number;
last_connected_at: number | null;
ssh_key_id?: number | null; // +++ Add ssh_key_id here as well +++
}
// ConnectionWithTagsRow implicitly includes 'type' via ConnectionBase
// ConnectionWithTagsRow implicitly includes 'type' and 'ssh_key_id' via ConnectionBase
interface ConnectionWithTagsRow extends ConnectionBase {
tag_ids_str: string | null;
}
// ConnectionWithTags implicitly includes 'type' via ConnectionBase
// ConnectionWithTags implicitly includes 'type' and 'ssh_key_id' via ConnectionBase
export interface ConnectionWithTags extends ConnectionBase {
tag_ids: number[];
}
@@ -60,7 +61,7 @@ interface FullConnectionDbRow extends FullConnectionData {
export const findAllConnectionsWithTags = async (): Promise<ConnectionWithTags[]> => {
const sql = `
SELECT
c.id, c.name, c.type, c.host, c.port, c.username, c.auth_method, c.proxy_id,
c.id, c.name, c.type, c.host, c.port, c.username, c.auth_method, c.proxy_id, c.ssh_key_id, -- +++ Select ssh_key_id +++
c.created_at, c.updated_at, c.last_connected_at,
GROUP_CONCAT(ct.tag_id) as tag_ids_str
FROM connections c
@@ -85,18 +85,29 @@ watch(() => props.connectionToEdit, (newVal) => {
formData.username = newVal.username;
formData.auth_method = newVal.auth_method;
formData.proxy_id = newVal.proxy_id ?? null;
formData.tag_ids = newVal.tag_ids ? [...newVal.tag_ids] : []; // 填充 tag_ids (深拷贝)
// 清空敏感字段
formData.password = '';
formData.private_key = '';
formData.passphrase = '';
} else {
// 添加模式:重置表单
Object.assign(formData, initialFormData);
formData.tag_ids = newVal.tag_ids ? [...newVal.tag_ids] : []; // 填充 tag_ids (深拷贝)
// +++ 填充 selected_ssh_key_id (如果认证方式是 key) +++
if (newVal.auth_method === 'key') {
formData.selected_ssh_key_id = newVal.ssh_key_id ?? null;
} else {
formData.selected_ssh_key_id = null; // 清空,以防之前是 key
}
// 清空敏感字段 (密码和直接输入的密钥)
formData.password = '';
formData.private_key = ''; // 即使是 key 认证,编辑时也不显示旧的直接输入密钥
formData.passphrase = ''; // 同上
} else {
// 添加模式:重置表单
Object.assign(formData, initialFormData);
formData.tag_ids = []; // 确保 tag_ids 也被重置为空数组
formData.selected_ssh_key_id = null; // 确保添加模式下也重置
}
}, { immediate: true });
// 组件挂载时获取代理标签列表
// 组件挂载时获取代理标签和 SSH 密钥列表
onMounted(() => {
proxiesStore.fetchProxies();
tagsStore.fetchTags(); // 获取标签列表
@@ -434,9 +445,9 @@ const testButtonText = computed(() => {
<!-- Direct Key Input Removed -->
<!-- Note for selected key -->
<div v-if="isEditMode && formData.auth_method === 'key' && formData.selected_ssh_key_id">
<!-- <div v-if="isEditMode && formData.auth_method === 'key' && formData.selected_ssh_key_id">
<small class="block text-xs text-text-secondary">{{ t('connections.form.keyUpdateNoteSelected') }}</small>
</div>
</div> -->
</div>
</template>
@@ -129,7 +129,7 @@ const cancelForm = () => {
<button @click="showAddForm"
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 disabled:opacity-50"
:disabled="isLoading">
<i class="fas fa-plus mr-2"></i>{{ t('sshKeys.modal.addKey') }}
<i class="fas fa-plus mr-2" style="color: white;"></i>{{ t('sshKeys.modal.addKey') }} <!-- Use inline style for white color -->
</button>
</div>
@@ -193,13 +193,13 @@ const cancelForm = () => {
<label for="key-private" class="block text-sm font-medium text-text-secondary mb-1">{{ t('sshKeys.modal.privateKey') }}</label>
<textarea id="key-private" v-model="formData.private_key" rows="8" required
class="w-full px-3 py-2 border border-border rounded-md shadow-sm bg-background text-foreground focus:outline-none focus:ring-1 focus:ring-primary focus:border-primary font-mono text-sm"></textarea>
<small v-if="keyToEdit" class="block text-xs text-text-secondary mt-1">{{ t('sshKeys.modal.keyUpdateNote') }}</small>
<!-- <small v-if="keyToEdit" class="block text-xs text-text-secondary mt-1">{{ t('sshKeys.modal.keyUpdateNote') }}</small> -->
</div>
<div>
<label for="key-passphrase" class="block text-sm font-medium text-text-secondary mb-1">{{ t('sshKeys.modal.passphrase') }} ({{ t('connections.form.optional') }})</label>
<input type="password" id="key-passphrase" v-model="formData.passphrase" autocomplete="new-password"
class="w-full px-3 py-2 border border-border rounded-md shadow-sm bg-background text-foreground focus:outline-none focus:ring-1 focus:ring-primary focus:border-primary" />
<small v-if="keyToEdit" class="block text-xs text-text-secondary mt-1">{{ t('sshKeys.modal.passphraseUpdateNote') }}</small>
<!-- <small v-if="keyToEdit" class="block text-xs text-text-secondary mt-1">{{ t('sshKeys.modal.passphraseUpdateNote') }}</small> -->
</div>
<!-- Form Error -->
@@ -35,6 +35,21 @@ watch(selectedKeyId, (newVal) => {
}
});
// Watch for changes in the keys list itself
watch(keys, (newKeys) => {
// If a key ID is selected (from props/v-model)
if (selectedKeyId.value !== null) {
// Check if that ID still exists in the newly loaded/updated list
const keyExists = newKeys.some(key => key.id === selectedKeyId.value);
if (!keyExists) {
// If the selected key ID is no longer valid (e.g., deleted), reset the selection
console.warn(`[SshKeySelector] Selected key ID ${selectedKeyId.value} not found in updated list. Resetting.`);
selectedKeyId.value = null; // This will trigger the watcher above to emit update:modelValue
}
// If the key *does* exist, the v-model binding on <select> should handle selecting it automatically when options render.
}
}, { immediate: false }); // Don't run immediately, only when keys actually change
const openManagementModal = () => {
isManagementModalVisible.value = true;
// Refresh keys list when modal opens, in case keys were added/deleted elsewhere
@@ -12,6 +12,7 @@ export interface ConnectionInfo {
auth_method: 'password' | 'key';
proxy_id?: number | null; // 新增:关联的代理 ID (可选)
tag_ids?: number[]; // 新增:关联的标签 ID 数组 (可选)
ssh_key_id?: number | null; // +++ 新增:关联的 SSH 密钥 ID (可选) +++
created_at: number;
updated_at: number;
last_connected_at: number | null;