Enhances property edit dialog with error handling and loading states

- Displays error messages when save operations fail
- Shows loading spinner during save attempts
- Improves UX with loading state indicators
- Updates translations for save-related strings in multiple languages
This commit is contained in:
yangdx
2025-05-11 12:35:51 +08:00
parent d5b9318553
commit fd5f61f166
6 changed files with 409 additions and 370 deletions

View File

@@ -33,6 +33,8 @@ const PropertyEditDialog = ({
}: PropertyEditDialogProps) => { }: PropertyEditDialogProps) => {
const { t } = useTranslation() const { t } = useTranslation()
const [value, setValue] = useState('') const [value, setValue] = useState('')
// Add error state to display save failure messages
const [error, setError] = useState<string | null>(null)
// Initialize value when dialog opens // Initialize value when dialog opens
useEffect(() => { useEffect(() => {
@@ -82,10 +84,20 @@ const PropertyEditDialog = ({
} }
}; };
const handleSave = () => { const handleSave = async () => {
if (value.trim() !== '') { if (value.trim() !== '') {
onSave(value) // Clear previous error messages
setError(null)
try {
await onSave(value)
onClose() onClose()
} catch (error) {
console.error('Save error:', error)
// Set error message to state for UI display
setError(typeof error === 'object' && error !== null
? (error as Error).message || t('common.saveFailed')
: t('common.saveFailed'))
}
} }
} }
@@ -103,6 +115,13 @@ const PropertyEditDialog = ({
</DialogDescription> </DialogDescription>
</DialogHeader> </DialogHeader>
{/* Display error message if save fails */}
{error && (
<div className="bg-destructive/15 text-destructive px-4 py-2 rounded-md text-sm mt-2">
{error}
</div>
)}
{/* Multi-line text input using textarea */} {/* Multi-line text input using textarea */}
<div className="grid gap-4 py-4"> <div className="grid gap-4 py-4">
{(() => { {(() => {
@@ -141,7 +160,19 @@ const PropertyEditDialog = ({
onClick={handleSave} onClick={handleSave}
disabled={isSubmitting} disabled={isSubmitting}
> >
{t('common.save')} {isSubmitting ? (
<>
<span className="mr-2">
<svg className="animate-spin h-4 w-4" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
</span>
{t('common.saving')}
</>
) : (
t('common.save')
)}
</Button> </Button>
</DialogFooter> </DialogFooter>
</DialogContent> </DialogContent>

View File

@@ -34,7 +34,9 @@
}, },
"common": { "common": {
"cancel": "إلغاء", "cancel": "إلغاء",
"save": "حفظ" "save": "حفظ",
"saving": "جارٍ الحفظ...",
"saveFailed": "فشل الحفظ"
}, },
"documentPanel": { "documentPanel": {
"clearDocuments": { "clearDocuments": {

View File

@@ -34,7 +34,9 @@
}, },
"common": { "common": {
"cancel": "Cancel", "cancel": "Cancel",
"save": "Save" "save": "Save",
"saving": "Saving...",
"saveFailed": "Save failed"
}, },
"documentPanel": { "documentPanel": {
"clearDocuments": { "clearDocuments": {

View File

@@ -34,7 +34,9 @@
}, },
"common": { "common": {
"cancel": "Annuler", "cancel": "Annuler",
"save": "Sauvegarder" "save": "Sauvegarder",
"saving": "Sauvegarde en cours...",
"saveFailed": "Échec de la sauvegarde"
}, },
"documentPanel": { "documentPanel": {
"clearDocuments": { "clearDocuments": {

View File

@@ -34,7 +34,9 @@
}, },
"common": { "common": {
"cancel": "取消", "cancel": "取消",
"save": "保存" "save": "保存",
"saving": "保存中...",
"saveFailed": "保存失败"
}, },
"documentPanel": { "documentPanel": {
"clearDocuments": { "clearDocuments": {

View File

@@ -34,7 +34,9 @@
}, },
"common": { "common": {
"cancel": "取消", "cancel": "取消",
"save": "儲存" "save": "儲存",
"saving": "儲存中...",
"saveFailed": "儲存失敗"
}, },
"documentPanel": { "documentPanel": {
"clearDocuments": { "clearDocuments": {
@@ -340,17 +342,15 @@
"historyTurns": "歷史輪次", "historyTurns": "歷史輪次",
"historyTurnsTooltip": "回應上下文中考慮的完整對話輪次(使用者-助手對)數量", "historyTurnsTooltip": "回應上下文中考慮的完整對話輪次(使用者-助手對)數量",
"historyTurnsPlaceholder": "歷史輪次數", "historyTurnsPlaceholder": "歷史輪次數",
"hlKeywords": "進階關鍵字",
"hlKeywordsTooltip": "檢索中優先考慮的進階關鍵字清單。用逗號分隔",
"hlkeywordsPlaceHolder": "輸入關鍵字",
"llKeywords": "基礎關鍵字",
"llKeywordsTooltip": "用於細化檢索重點的基礎關鍵字清單。用逗號分隔",
"onlyNeedContext": "僅需上下文", "onlyNeedContext": "僅需上下文",
"onlyNeedContextTooltip": "如果為True僅回傳檢索到的上下文而不產生回應", "onlyNeedContextTooltip": "如果為True僅回傳檢索到的上下文而不產生回應",
"onlyNeedPrompt": "僅需提示", "onlyNeedPrompt": "僅需提示",
"onlyNeedPromptTooltip": "如果為True僅回傳產生的提示而不產生回應", "onlyNeedPromptTooltip": "如果為True僅回傳產生的提示而不產生回應",
"streamResponse": "串流回應", "streamResponse": "串流回應",
"streamResponseTooltip": "如果為True啟用即時串流輸出回應" "streamResponseTooltip": "如果為True啟用即時串流輸出回應",
"userPrompt": "用戶提示詞",
"userPromptTooltip": "向LLM提供額外的響應要求與查詢內容無關僅用於處理輸出。",
"userPromptPlaceholder": "輸入自定義提示詞(可選)"
} }
}, },
"apiSite": { "apiSite": {