✨ feat(sync): multi-language sync wizard, backend locale support, and conflict modal UX improvements
Frontend (web)
- ModelsActions.jsx
- Replace “Sync Official” with “Sync” and open a new two-step SyncWizard.
- Pass selected locale through to preview, sync, and overwrite flows.
- Keep conflict resolution flow; inject locale into overwrite submission.
- New: models/modals/SyncWizardModal.jsx
- Two-step wizard: (1) method selection (config-sync disabled for now), (2) language selection (en/zh/ja).
- Horizontal, centered Radio cards; returns { option, locale } via onConfirm.
- UpstreamConflictModal.jsx
- Add search input (model fuzzy search) and native pagination.
- Column header checkbox now only applies to rows in the current filtered result.
- Fix “Cannot access ‘filteredDataSource’ before initialization”.
- Refactor with useMemo/useCallback; extract helpers to remove duplicated logic:
- getPresentRowsForField, getHeaderState, applyHeaderChange
- Minor code cleanups and stability improvements.
- i18n (en.json)
- Add strings for the sync wizard and related actions (Sync, Sync Wizard, Select method/source/language, etc.).
- Adjust minor translations.
Hooks
- useModelsData.jsx
- Extend previewUpstreamDiff, syncUpstream, applyUpstreamOverwrite to accept options with locale.
- Send locale via query/body accordingly.
Backend (Go)
- controller/model_sync.go
- Accept locale from query/body and resolve i18n upstream URLs.
- Add SYNC_UPSTREAM_BASE for upstream base override (default: https://basellm.github.io/llm-metadata).
- Make HTTP timeouts/retries/limits configurable:
- SYNC_HTTP_TIMEOUT_SECONDS, SYNC_HTTP_RETRY, SYNC_HTTP_MAX_MB
- Add ETag-based caching and support both envelope and pure array JSON formats.
- Concurrently fetch vendors and models; improve error responses with locale and source URLs.
- Include source meta (locale, models_url, vendors_url) in success payloads.
Notes
- No breaking changes expected.
- Lint passes for touched files.
This commit is contained in:
@@ -166,10 +166,13 @@ export const useModelsData = () => {
|
||||
};
|
||||
|
||||
// Sync upstream models/vendors for missing models only
|
||||
const syncUpstream = async () => {
|
||||
const syncUpstream = async (opts = {}) => {
|
||||
const locale = opts?.locale;
|
||||
setSyncing(true);
|
||||
try {
|
||||
const res = await API.post('/api/models/sync_upstream');
|
||||
const body = {};
|
||||
if (locale) body.locale = locale;
|
||||
const res = await API.post('/api/models/sync_upstream', body);
|
||||
const { success, message, data } = res.data || {};
|
||||
if (success) {
|
||||
const createdModels = data?.created_models || 0;
|
||||
@@ -192,10 +195,12 @@ export const useModelsData = () => {
|
||||
};
|
||||
|
||||
// Preview upstream differences
|
||||
const previewUpstreamDiff = async () => {
|
||||
const previewUpstreamDiff = async (opts = {}) => {
|
||||
const locale = opts?.locale;
|
||||
setPreviewing(true);
|
||||
try {
|
||||
const res = await API.get('/api/models/sync_upstream/preview');
|
||||
const url = `/api/models/sync_upstream/preview${locale ? `?locale=${locale}` : ''}`;
|
||||
const res = await API.get(url);
|
||||
const { success, message, data } = res.data || {};
|
||||
if (success) {
|
||||
return data || { missing: [], conflicts: [] };
|
||||
@@ -211,10 +216,15 @@ export const useModelsData = () => {
|
||||
};
|
||||
|
||||
// Apply selected overwrite
|
||||
const applyUpstreamOverwrite = async (overwrite = []) => {
|
||||
const applyUpstreamOverwrite = async (payloadOrArray = []) => {
|
||||
const isArray = Array.isArray(payloadOrArray);
|
||||
const overwrite = isArray ? payloadOrArray : payloadOrArray.overwrite || [];
|
||||
const locale = isArray ? undefined : payloadOrArray.locale;
|
||||
setSyncing(true);
|
||||
try {
|
||||
const res = await API.post('/api/models/sync_upstream', { overwrite });
|
||||
const body = { overwrite };
|
||||
if (locale) body.locale = locale;
|
||||
const res = await API.post('/api/models/sync_upstream', body);
|
||||
const { success, message, data } = res.data || {};
|
||||
if (success) {
|
||||
const createdModels = data?.created_models || 0;
|
||||
|
||||
Reference in New Issue
Block a user