Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions core/http/react-ui/e2e/model-editor-back-nav.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ test.describe('Model Editor — Back navigation', () => {
await mockEditorEndpoints(page)
})

test('Back returns to Manage with a "Back to Manage" caption', async ({ page }) => {
test('Back returns to Manage with a "Back to System" caption', async ({ page }) => {
await page.goto('/app/manage')
await expect(page.locator('.table')).toBeVisible({ timeout: 10_000 })

Expand All @@ -55,7 +55,7 @@ test.describe('Model Editor — Back navigation', () => {
await page.getByRole('menuitem', { name: 'Edit configuration' }).click()

await expect(page).toHaveURL(/\/app\/model-editor\//)
const back = page.getByRole('button', { name: /Back to Manage/ })
const back = page.getByRole('button', { name: /Back to System/ })
await expect(back).toBeVisible({ timeout: 10_000 })

await back.click()
Expand Down Expand Up @@ -89,6 +89,6 @@ test.describe('Model Editor — Back navigation', () => {

test('falls back to "Back to Manage" on a direct visit with no origin state', async ({ page }) => {
await page.goto('/app/model-editor/mock-model')
await expect(page.getByRole('button', { name: /Back to Manage/ })).toBeVisible({ timeout: 10_000 })
await expect(page.getByRole('button', { name: /Back to System/ })).toBeVisible({ timeout: 10_000 })
})
})
3 changes: 2 additions & 1 deletion core/http/react-ui/public/locales/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@
"type": "Type",
"value": "Value",
"search": "Search...",
"selectPlaceholder": "Select an option..."
"selectPlaceholder": "Select an option...",
"noMatch": "No matches"
},
"time": {
"now": "now",
Expand Down
38 changes: 38 additions & 0 deletions core/http/react-ui/public/locales/en/modelEditor.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"title": {
"add": "Add Model",
"edit": "Model Editor"
},
"subtitle": {
"chooseModelType": "Choose a model type to get started",
"newModel": "New model"
},
"actions": {
"backTo": "Back to {{page}}",
"system": "System",
"templates": "Templates",
"createModel": "Create Model",
"saveChanges": "Save Changes",
"saving": "Saving...",
"saved": "Saved",
"switchWarning": "Save or discard changes before switching tabs.",
"discardAndSwitch": "Discard & Switch"
},
"tabs": {
"interactive": "Interactive",
"yaml": "YAML",
"yamlDescription": "Edit the YAML directly. The model name must be set in the YAML for create to work."
},
"forms": {
"modelName": {
"label": "Model Name",
"placeholder": "my-model-name",
"hint": "Use letters, numbers, hyphens, underscores, and dots only."
},
"empty": {
"nav": "Use the search bar above to add fields",
"title": "No fields configured",
"text": "Use the search bar above to find and add configuration fields."
}
}
}
7 changes: 7 additions & 0 deletions core/http/react-ui/public/locales/en/models.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"title": "Install Models",
"subtitle": "Browse and install AI models from the gallery",
"models": "Models",
"stats": {
"available": "Available",
"installed": "Installed"
Expand Down Expand Up @@ -89,5 +90,11 @@
"loadFailed": "Failed to load models: {{message}}",
"installFailed": "Failed to install: {{message}}",
"deleteFailed": "Failed to delete: {{message}}"
},
"selector": {
"loading": "Loading models...",
"selectModel": "Select model...",
"searchPlaceholder": "Search models...",
"noModels": "No models available"
}
}
5 changes: 3 additions & 2 deletions core/http/react-ui/public/locales/id/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@
"type": "Tipe",
"value": "Nilai",
"search": "Cari...",
"selectPlaceholder": "Pilih opsi..."
"selectPlaceholder": "Pilih opsi...",
"noMatch": "Tidak ada yang cocok"
},
"time": {
"now": "baru saja",
Expand All @@ -106,4 +107,4 @@
"gigabytes": "GB",
"terabytes": "TB"
}
}
}
4 changes: 2 additions & 2 deletions core/http/react-ui/public/locales/id/importModel.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"title": "Impor Model Baru",
"subtitle": {
"simple": "Import model dari URI — deteksi otomatis memilih backend.",
"simple": "Impor model dari URI — deteksi otomatis memilih backend.",
"powerYaml": "Tulis konfigurasi YAML lengkap untuk model.",
"powerPrefs": "Preferensi impor tingkat lanjut."
},
Expand Down Expand Up @@ -139,4 +139,4 @@
"local": "File konfigurasi YAML lokal"
}
}
}
}
38 changes: 38 additions & 0 deletions core/http/react-ui/public/locales/id/modelEditor.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"title": {
"add": "Tambah Model",
"edit": "Editor Model"
},
"subtitle": {
"chooseModelType": "Pilih tipe model untuk memulai",
"newModel": "Model baru"
},
"actions": {
"backTo": "Kembali ke {{page}}",
"system": "Sistem",
"templates": "Templat",
"createModel": "Buat Model",
"saveChanges": "Simpan Perubahan",
"saving": "Menyimpan...",
"saved": "Tersimpan",
"switchWarning": "Simpan atau buang perubahan sebelum beralih tab.",
"discardAndSwitch": "Buang & Beralih"
},
"tabs": {
"interactive": "Interaktif",
"yaml": "YAML",
"yamlDescription": "Edit YAML secara langsung. Nama model harus diatur di YAML agar pembuatan berhasil."
},
"forms": {
"modelName": {
"label": "Nama Model",
"placeholder": "nama-model-saya",
"hint": "Gunakan huruf, angka, tanda hubung, garis bawah, dan titik saja."
},
"empty": {
"nav": "Gunakan kolom pencarian di atas untuk menambahkan field",
"title": "Tidak ada field yang dikonfigurasi",
"text": "Gunakan kolom pencarian di atas untuk menemukan dan menambahkan field konfigurasi."
}
}
}
9 changes: 8 additions & 1 deletion core/http/react-ui/public/locales/id/models.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"title": "Instal Model",
"subtitle": "Telusuri dan instal model AI dari galeri",
"models": "Model",
"stats": {
"available": "Tersedia",
"installed": "Terinstal"
Expand Down Expand Up @@ -89,5 +90,11 @@
"loadFailed": "Gagal memuat model: {{message}}",
"installFailed": "Gagal menginstal: {{message}}",
"deleteFailed": "Gagal menghapus: {{message}}"
},
"selector": {
"loading": "Memuat model...",
"selectModel": "Pilih model...",
"searchPlaceholder": "Cari model...",
"noModels": "Model tidak tersedia"
}
}
}
6 changes: 4 additions & 2 deletions core/http/react-ui/src/components/ModelSelector.jsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { useEffect, useMemo } from 'react'
import { useModels } from '../hooks/useModels'
import SearchableSelect from './SearchableSelect'
import { useTranslation } from 'react-i18next'

export default function ModelSelector({
value, onChange, capability, className = '',
options: externalOptions, loading: externalLoading,
disabled: externalDisabled, searchPlaceholder, style,
}) {
const { t } = useTranslation('models')
// Skip capability fetch when external options are provided (capability will be undefined)
const { models: hookModels, loading: hookLoading } = useModels(externalOptions ? undefined : capability)

Expand All @@ -28,8 +30,8 @@ export default function ModelSelector({
value={value || ''}
onChange={onChange}
options={modelNames}
placeholder={isLoading ? 'Loading models...' : (modelNames.length === 0 ? 'No models available' : 'Select model...')}
searchPlaceholder={searchPlaceholder || 'Search models...'}
placeholder={isLoading ? t('selector.loading') : (modelNames.length === 0 ? t('selector.noModels') : t('selector.selectModel'))}
searchPlaceholder={searchPlaceholder || t('selector.searchPlaceholder')}
disabled={isDisabled}
className={className}
style={style}
Expand Down
4 changes: 3 additions & 1 deletion core/http/react-ui/src/components/SearchableSelect.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { useState, useEffect, useRef, useMemo } from 'react'
import { useTranslation } from 'react-i18next'

export default function SearchableSelect({
value, onChange, options, placeholder = 'Select...',
allOption, searchPlaceholder = 'Search...',
disabled = false, style, className = '',
}) {
const { t } = useTranslation('common')
const [open, setOpen] = useState(false)
const [query, setQuery] = useState('')
const [focusIndex, setFocusIndex] = useState(-1)
Expand Down Expand Up @@ -226,7 +228,7 @@ export default function SearchableSelect({
})}
{filtered.length === 0 && !allOption && (
<div style={{ padding: '6px 10px', fontSize: '0.8125rem', color: 'var(--color-text-muted)', fontStyle: 'italic' }}>
No matches
{t('forms.noMatch')}
</div>
)}
</div>
Expand Down
2 changes: 1 addition & 1 deletion core/http/react-ui/src/pages/Manage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -675,7 +675,7 @@ export default function Manage() {
onClick: () => handleTogglePinned(model.id, model.pinned),
disabled: pinningModels.has(model.id) || !!model.disabled },
{ key: 'edit', icon: 'fa-pen-to-square', label: 'Edit configuration',
onClick: () => navigate(`/app/model-editor/${encodeURIComponent(model.id)}`, { state: fromState(location, 'Manage') }) },
onClick: () => navigate(`/app/model-editor/${encodeURIComponent(model.id)}`, { state: fromState(location, t('manage.title')) }) },
{ key: 'logs', icon: 'fa-terminal', label: 'Backend logs',
onClick: () => navigate(`/app/backend-logs/${encodeURIComponent(model.id)}`) },
{ divider: true },
Expand Down
Loading
Loading