✨ feat: Improve models UX and robustness: add JSONEditor extraFooter, fix endpoints rendering, and clean up deps
- Why
- Needed to separate help text from action buttons in JSONEditor for better layout and UX.
- Models table should robustly render both new object-based endpoint mappings and legacy arrays.
- Columns should re-render when vendor map changes.
- Minor import cleanups for consistency.
- What
- JSONEditor.js
- Added optional prop extraFooter to render content below the extraText divider.
- Kept extraText rendered via Divider; extraFooter appears on the next line for clear separation.
- EditModelModal.jsx
- Moved endpoint group buttons from extraText into extraFooter to display under the helper text.
- Kept merge-logic: group items are merged into current endpoints JSON with key override semantics.
- Consolidated lucide-react imports into a single line.
- ModelsColumnDefs.js
- Made endpoint renderer resilient:
- Supports object-based JSON (keys as endpoint types) and legacy array format.
- Displays keys/items as tags and limits the number shown; uses stringToColor for visual consistency.
- Consolidated Semi UI imports into a single line.
- ModelsTable.jsx
- Fixed columns memoization dependency to include vendorMap, ensuring re-render when vendor data changes.
- Notes
- Backward-compatible: extraFooter is additive; existing JSONEditor usage remains unchanged.
- No API changes to backend.
- No linter errors introduced.
- Files touched
- web/src/components/common/ui/JSONEditor.js
- web/src/components/table/models/modals/EditModelModal.jsx
- web/src/components/table/models/ModelsColumnDefs.js
- web/src/components/table/models/ModelsTable.jsx
- Impact
- Clearer UI for endpoint editing (buttons now below helper text).
- Correct endpoints display for object-based mappings in models list.
- More reliable reactivity when vendor data updates.
This commit is contained in:
@@ -18,13 +18,7 @@ For commercial licensing, please contact support@quantumnous.com
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import {
|
||||
Button,
|
||||
Space,
|
||||
Tag,
|
||||
Typography,
|
||||
Modal
|
||||
} from '@douyinfe/semi-ui';
|
||||
import { Button, Space, Tag, Typography, Modal } from '@douyinfe/semi-ui';
|
||||
import {
|
||||
timestamp2string,
|
||||
getLobeHubIcon,
|
||||
@@ -81,21 +75,39 @@ const renderTags = (text) => {
|
||||
});
|
||||
};
|
||||
|
||||
// Render endpoints
|
||||
const renderEndpoints = (text) => {
|
||||
let arr;
|
||||
// Render endpoints (supports object map or legacy array)
|
||||
const renderEndpoints = (value) => {
|
||||
try {
|
||||
arr = JSON.parse(text);
|
||||
} catch (_) { }
|
||||
if (!Array.isArray(arr)) return text || '-';
|
||||
return renderLimitedItems({
|
||||
items: arr,
|
||||
renderItem: (ep, idx) => (
|
||||
<Tag key={idx} color="white" size="small" shape='circle'>
|
||||
{ep}
|
||||
</Tag>
|
||||
),
|
||||
});
|
||||
const parsed = typeof value === 'string' ? JSON.parse(value) : value;
|
||||
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
|
||||
const keys = Object.keys(parsed || {});
|
||||
if (keys.length === 0) return '-';
|
||||
return renderLimitedItems({
|
||||
items: keys,
|
||||
renderItem: (key, idx) => (
|
||||
<Tag key={idx} size="small" shape='circle' color={stringToColor(key)}>
|
||||
{key}
|
||||
</Tag>
|
||||
),
|
||||
maxDisplay: 3,
|
||||
});
|
||||
}
|
||||
if (Array.isArray(parsed)) {
|
||||
if (parsed.length === 0) return '-';
|
||||
return renderLimitedItems({
|
||||
items: parsed,
|
||||
renderItem: (ep, idx) => (
|
||||
<Tag key={idx} color="white" size="small" shape='circle'>
|
||||
{ep}
|
||||
</Tag>
|
||||
),
|
||||
maxDisplay: 3,
|
||||
});
|
||||
}
|
||||
return value || '-';
|
||||
} catch (_) {
|
||||
return value || '-';
|
||||
}
|
||||
};
|
||||
|
||||
// Render quota type
|
||||
|
||||
Reference in New Issue
Block a user