fix: user need to select project first to load the conversation list

This commit is contained in:
pionxzh
2026-03-01 22:36:56 +08:00
parent e927de3658
commit 9ce72c0f05
10 changed files with 52 additions and 25 deletions

View File

@@ -42,5 +42,6 @@
"Select Project": "Select Project",
"(no project)": "(no project)",
"Export All Limit": "Export All Limit",
"Export All Limit Description": "Set the maximum number of conversations to load in the 'Export All' dialog."
"Export All Limit Description": "Set the maximum number of conversations to load in the 'Export All' dialog.",
"Select a source to load conversations": "Select a project above to load conversations."
}

View File

@@ -42,5 +42,6 @@
"Select Project": "Seleccionar proyecto",
"(no project)": "(sin proyecto)",
"Export All Limit": "Límite de Exportar Todos",
"Export All Limit Description": "Establece el número máximo de conversaciones a cargar en el diálogo 'Exportar Todos'."
"Export All Limit Description": "Establece el número máximo de conversaciones a cargar en el diálogo 'Exportar Todos'.",
"Select a source to load conversations": "Selecciona un proyecto arriba para cargar conversaciones."
}

View File

@@ -42,5 +42,6 @@
"Select Project": "Sélectionner un projet",
"(no project)": "(aucun projet)",
"Export All Limit": "Limite d'Exportation Multiple",
"Export All Limit Description": "Définit le nombre maximal de conversations à charger dans la boîte de dialogue 'Tout exporter'."
"Export All Limit Description": "Définit le nombre maximal de conversations à charger dans la boîte de dialogue 'Tout exporter'.",
"Select a source to load conversations": "Sélectionnez un projet ci-dessus pour charger les conversations."
}

View File

@@ -42,5 +42,6 @@
"Select Project": "Pilih Proyek",
"(no project)": "(tidak ada proyek)",
"Export All Limit": "Batas Ekspor Semua",
"Export All Limit Description": "Atur jumlah maksimum percakapan yang akan dimuat dalam dialog 'Ekspor Semua'."
"Export All Limit Description": "Atur jumlah maksimum percakapan yang akan dimuat dalam dialog 'Ekspor Semua'.",
"Select a source to load conversations": "Pilih proyek di atas untuk memuat percakapan."
}

View File

@@ -42,5 +42,6 @@
"Select Project": "プロジェクトを選択",
"(no project)": "(プロジェクトなし)",
"Export All Limit": "すべてエクスポートの上限",
"Export All Limit Description": "「すべてエクスポート」ダイアログで読み込む会話の最大数を設定します。"
"Export All Limit Description": "「すべてエクスポート」ダイアログで読み込む会話の最大数を設定します。",
"Select a source to load conversations": "上からプロジェクトを選択して会話を読み込んでください。"
}

View File

@@ -42,5 +42,6 @@
"Select Project": "Выберите проект",
"(no project)": "(нет проекта)",
"Export All Limit": "Лимит экспорта всех",
"Export All Limit Description": "Установите максимальное количество бесед для загрузки в диалоге 'Экспортировать все'."
"Export All Limit Description": "Установите максимальное количество бесед для загрузки в диалоге 'Экспортировать все'.",
"Select a source to load conversations": "Выберите проект выше, чтобы загрузить беседы."
}

View File

@@ -42,5 +42,6 @@
"Select Project": "Proje Seç",
"(no project)": "(proje yok)",
"Export All Limit": "Tümünü Dışa Aktarma Limiti",
"Export All Limit Description": "'Tümünü Dışa Aktar' iletişim kutusunda yüklenecek maksimum konuşma sayısını ayarlayın."
"Export All Limit Description": "'Tümünü Dışa Aktar' iletişim kutusunda yüklenecek maksimum konuşma sayısını ayarlayın.",
"Select a source to load conversations": "Konuşmaları yüklemek için yukarıdan bir proje seçin."
}

View File

@@ -42,5 +42,6 @@
"Select Project": "选择项目",
"(no project)": "(无项目)",
"Export All Limit": "批量导出上限",
"Export All Limit Description": "设置“批量导出”对话框中加载的最大对话数量。"
"Export All Limit Description": "设置“批量导出”对话框中加载的最大对话数量。",
"Select a source to load conversations": "请在上方选择一个项目以加载对话。"
}

View File

@@ -42,5 +42,6 @@
"Select Project": "選擇專案",
"(no project)": "(無專案)",
"Export All Limit": "批量匯出上限",
"Export All Limit Description": "設定「批量匯出」對話方塊中載入的最大對話數量。"
"Export All Limit Description": "設定「批量匯出」對話方塊中載入的最大對話數量。",
"Select a source to load conversations": "請在上方選擇一個專案以載入對話。"
}

View File

@@ -7,7 +7,7 @@ import { exportAllToJson, exportAllToOfficialJson } from '../exporter/json'
import { exportAllToMarkdown } from '../exporter/markdown'
import { RequestQueue } from '../utils/queue'
import { CheckBox } from './CheckBox'
import { IconCross, IconUpload } from './Icons'
import { IconCross, IconLoading, IconUpload } from './Icons'
import { useSettingContext } from './SettingContext'
import type { ApiConversationItem, ApiConversationWithId, ApiProjectInfo } from '../api'
import type { FC } from '../type'
@@ -15,7 +15,7 @@ import type { ChangeEvent } from 'preact/compat'
interface ProjectSelectProps {
projects: ApiProjectInfo[]
selected: ApiProjectInfo | null
selected: ApiProjectInfo | null | undefined
setSelected: (selected: ApiProjectInfo | null) => void
disabled: boolean
}
@@ -23,19 +23,24 @@ interface ProjectSelectProps {
const ProjectSelect: FC<ProjectSelectProps> = ({ projects, selected, setSelected, disabled }) => {
const { t } = useTranslation()
const value = selected === undefined ? '__unselected__' : (selected?.id || '')
return (
<div className="flex items-center text-gray-600 dark:text-gray-300 flex justify-between mb-3">
{t('Select Project')}
<select
disabled={disabled}
className="Select"
value={selected?.id || ''}
value={value}
onChange={(e) => {
const projectId = e.currentTarget.value
const project = projects.find(p => p.id === projectId)
setSelected(project || null)
}}
>
{selected === undefined && (
<option value="__unselected__" disabled>{t('Select Project')}...</option>
)}
<option value="">{t('(no project)')}</option>
{projects.map(project => (
<option key={project.id} value={project.id}>{project.display.name}</option>
@@ -75,6 +80,12 @@ const ConversationSelect: FC<ConversationSelectProps> = ({
setSelected(checked ? conversations : [])
}}
/>
{loading && conversations.length > 0 && (
<span className="flex items-center gap-1 text-sm text-gray-500 dark:text-gray-400">
<IconLoading className="w-3 h-3" />
{t('Loading')}... ({conversations.length})
</span>
)}
</div>
<ul className="SelectList">
{loading && conversations.length === 0 && <li className="SelectItem">{t('Loading')}...</li>}
@@ -94,9 +105,6 @@ const ConversationSelect: FC<ConversationSelectProps> = ({
/>
</li>
))}
{loading && conversations.length > 0 && (
<li className="SelectItem" style={{ opacity: 0.5, fontStyle: 'italic' }}>{t('Loading')}...</li>
)}
</ul>
</>
)
@@ -129,7 +137,7 @@ const DialogContent: FC<DialogContentProps> = ({ format }) => {
const [loading, setLoading] = useState(false)
const [error, setError] = useState('')
const [processing, setProcessing] = useState(false)
const [selectedProject, setSelectedProject] = useState<ApiProjectInfo | null>(null)
const [selectedProject, setSelectedProject] = useState<ApiProjectInfo | null | undefined>(undefined)
const [selected, setSelected] = useState<ApiConversationItem[]>([])
const [exportType, setExportType] = useState(exportAllOptions[0].label)
@@ -297,10 +305,12 @@ const DialogContent: FC<DialogContentProps> = ({ format }) => {
}, [])
useEffect(() => {
if (selectedProject === undefined) return
setSelected([])
setApiConversations([])
setLoading(true)
fetchAllConversations(
selectedProject?.id,
selectedProject?.id ?? null,
exportAllLimit,
batch => setApiConversations(prev => [...prev, ...batch]),
)
@@ -335,6 +345,13 @@ const DialogContent: FC<DialogContentProps> = ({ format }) => {
</div>
)}
<ProjectSelect projects={projects} selected={selectedProject} setSelected={setSelectedProject} disabled={processing} />
{selectedProject === undefined
? (
<div className="SelectList flex items-center justify-center text-gray-400 dark:text-gray-500 text-sm">
{t('Select a source to load conversations')}
</div>
)
: (
<ConversationSelect
conversations={conversations}
selected={selected}
@@ -343,6 +360,7 @@ const DialogContent: FC<DialogContentProps> = ({ format }) => {
loading={loading}
error={error}
/>
)}
<div className="flex mt-6" style={{ justifyContent: 'space-between' }}>
<select className="Select" disabled={processing} value={exportType} onChange={e => setExportType(e.currentTarget.value)}>
{exportAllOptions.map(({ label }) => (