mirror of
https://github.com/AstrBotDevs/AstrBot.git
synced 2026-10-16 15:06:04 +08:00
feat: add desktop workspace directory picker
This commit is contained in:
@@ -13,7 +13,20 @@
|
||||
<v-select v-model="form.workspace_type" :items="workspaceTypeItems" item-title="label" item-value="value"
|
||||
:label="tm('project.workspace.type')" variant="outlined" hide-details class="mb-3" />
|
||||
<v-text-field v-if="form.workspace_type === 'custom'" v-model="form.workspace_path"
|
||||
:label="tm('project.workspace.path')" variant="outlined" hide-details class="mb-1" />
|
||||
:label="tm('project.workspace.path')" variant="outlined" hide-details class="mb-1">
|
||||
<template #append-inner>
|
||||
<v-btn
|
||||
v-if="canPickWorkspaceDirectory"
|
||||
:aria-label="tm('project.workspace.selectPath')"
|
||||
:loading="pickingWorkspaceDirectory"
|
||||
:disabled="props.saving"
|
||||
icon="mdi-folder-open-outline"
|
||||
size="small"
|
||||
variant="text"
|
||||
@click.stop="handlePickWorkspaceDirectory"
|
||||
/>
|
||||
</template>
|
||||
</v-text-field>
|
||||
<v-alert
|
||||
v-if="props.errorMessage"
|
||||
class="mt-3"
|
||||
@@ -36,6 +49,7 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { useI18n, useModuleI18n } from '@/i18n/composables';
|
||||
import { getDesktopRuntimeInfo } from '@/utils/desktopRuntime';
|
||||
|
||||
export type WorkspaceType = 'session' | 'project' | 'custom';
|
||||
|
||||
@@ -83,6 +97,8 @@ const { tm } = useModuleI18n('features/chat');
|
||||
|
||||
const isOpen = ref(props.modelValue);
|
||||
const isEditing = ref(false);
|
||||
const canPickWorkspaceDirectory = ref(false);
|
||||
const pickingWorkspaceDirectory = ref(false);
|
||||
const form = ref<ProjectFormData>({
|
||||
emoji: '📁',
|
||||
title: '',
|
||||
@@ -101,8 +117,9 @@ const canSave = computed(() => {
|
||||
return form.value.workspace_path.trim().length > 0;
|
||||
});
|
||||
|
||||
watch(() => props.modelValue, (newVal) => {
|
||||
watch(() => props.modelValue, async (newVal) => {
|
||||
isOpen.value = newVal;
|
||||
canPickWorkspaceDirectory.value = false;
|
||||
if (newVal) {
|
||||
if (props.project) {
|
||||
isEditing.value = true;
|
||||
@@ -123,6 +140,10 @@ watch(() => props.modelValue, (newVal) => {
|
||||
workspace_path: ''
|
||||
};
|
||||
}
|
||||
|
||||
const runtimeInfo = await getDesktopRuntimeInfo();
|
||||
canPickWorkspaceDirectory.value = runtimeInfo.isDesktopRuntime &&
|
||||
typeof runtimeInfo.bridge?.pickDirectory === 'function';
|
||||
}
|
||||
});
|
||||
|
||||
@@ -141,6 +162,25 @@ function handleCancel() {
|
||||
emit('update:modelValue', false);
|
||||
}
|
||||
|
||||
async function handlePickWorkspaceDirectory() {
|
||||
const pickDirectory = window.astrbotDesktop?.pickDirectory;
|
||||
if (!canPickWorkspaceDirectory.value || !pickDirectory || pickingWorkspaceDirectory.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
pickingWorkspaceDirectory.value = true;
|
||||
try {
|
||||
const selectedPath = await pickDirectory(form.value.workspace_path || null);
|
||||
if (selectedPath) {
|
||||
form.value.workspace_path = selectedPath;
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('[chat-project] Failed to pick workspace directory.', error);
|
||||
} finally {
|
||||
pickingWorkspaceDirectory.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function handleSave() {
|
||||
if (!canSave.value) {
|
||||
return;
|
||||
|
||||
@@ -170,7 +170,8 @@
|
||||
"session": "Per-session workspace",
|
||||
"project": "Shared project workspace",
|
||||
"custom": "Custom path",
|
||||
"path": "Workspace path"
|
||||
"path": "Workspace path",
|
||||
"selectPath": "Select folder"
|
||||
},
|
||||
"loadingSessions": "Loading conversations...",
|
||||
"noSessions": "No conversations in this project",
|
||||
|
||||
@@ -170,7 +170,8 @@
|
||||
"session": "セッションごとに分離",
|
||||
"project": "プロジェクト共有ワークスペース",
|
||||
"custom": "カスタムパス",
|
||||
"path": "ワークスペースのパス"
|
||||
"path": "ワークスペースのパス",
|
||||
"selectPath": "フォルダーを選択"
|
||||
},
|
||||
"loadingSessions": "会話を読み込み中…",
|
||||
"noSessions": "このプロジェクトには会話がありません",
|
||||
|
||||
@@ -170,7 +170,8 @@
|
||||
"session": "Отдельно для каждого чата",
|
||||
"project": "Общая область проекта",
|
||||
"custom": "Пользовательский путь",
|
||||
"path": "Путь рабочей области"
|
||||
"path": "Путь рабочей области",
|
||||
"selectPath": "Выбрать папку"
|
||||
},
|
||||
"loadingSessions": "Загрузка диалогов...",
|
||||
"noSessions": "В этом проекте пока нет диалогов",
|
||||
|
||||
@@ -170,7 +170,8 @@
|
||||
"session": "按会话分开",
|
||||
"project": "项目共享工作区",
|
||||
"custom": "自定义路径",
|
||||
"path": "工作区路径"
|
||||
"path": "工作区路径",
|
||||
"selectPath": "选择文件夹"
|
||||
},
|
||||
"loadingSessions": "加载对话中...",
|
||||
"noSessions": "该项目暂无对话",
|
||||
|
||||
+1
@@ -46,6 +46,7 @@ declare global {
|
||||
ok: boolean;
|
||||
reason: string | null;
|
||||
}>;
|
||||
pickDirectory?: (defaultPath?: string | null) => Promise<string | null>;
|
||||
onTrayRestartBackend?: (callback: () => void) => () => void;
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user