1. EditModelModal quality-of-life
• Added comma parsing to `Form.TagInput`; users can now paste
`tag1, tag2 , tag3` to bulk-create tags.
• Updated placeholder copy to reflect the new capability.
All files pass linting; no runtime changes outside the intended UI updates.
• Removed obsolete `sidebarIconColors` map and `getItemColor` util from
SiderBar/render; all selected states now use the single CSS variable
`--semi-color-primary` for both text and icons.
• Simplified `getLucideIcon`:
– Added `Package` to Lucide imports.
– Switched “models” case to `<Package />`, avoiding duplication with
the Layers glyph.
– Replaced per-key color logic with `iconColor` derived from the new
uniform highlight color.
• Stripped any unused imports / dead code paths after the refactor.
• Lint passes; sidebar hover/focus behavior unchanged while visual
consistency is improved.
Highlights
──────────
1. Removed code duplication
• Introduced `extractItems` helper to safely unwrap API payloads.
• Simplified `getFormValues` to a single-line fallback expression.
• Replaced repeated list-extraction code in `loadModels`, `searchModels`,
and `refreshVendorCounts` with the new helper.
2. Vendor tab accuracy & performance
• Added `refreshVendorCounts` to recalc counts via a single lightweight
request; invoked only when必要 (current tab ≠ "all“) to avoid redundancy.
• `loadModels` still updates counts instantly when viewing "all", ensuring
accurate numbers on initial load and page changes.
3. Misc clean-ups
• Streamlined conditional URL building and state updates.
• Confirmed all async branches include error handling with i18n messages.
• Ran linter → zero issues.
Result: leaner, easier-to-maintain hook with correct, real-time vendor counts
and no repeated logic.
Backend
• model/model_meta.go
– Import strconv
– SearchModels: support numeric vendor ID filter vs. fuzzy name search
– Explicitly order by `models.id` to avoid “ambiguous column name: id” error
Frontend
• hooks/useModelsData.js
– Change vendor-filter API to pass vendor ID
– Automatically reload models when `activeVendorKey` changes
– Update vendor counts only when viewing “All” to preserve other tab totals
• Add missing effect in EditModelModal to refresh vendor list only when modal visible
• Other minor updates to keep lints clean
Result
Tabs now:
1. Trigger API requests on click
2. Show accurate per-vendor totals
3. Filter models without resetting other counts
Backend search handles both vendor IDs and names without SQL errors.
Backend
• Add `model/model_meta.go` and `model/vendor_meta.go` defining Model & Vendor entities with CRUD helpers, soft-delete and time stamps
• Create corresponding controllers `controller/model_meta.go`, `controller/vendor_meta.go` and register routes in `router/api-router.go`
• Auto-migrate new tables in DB startup logic
Frontend
• Build complete “Model Management” module under `/console/models`
- New pages, tables, filters, actions, hooks (`useModelsData`) and dynamic vendor tabs
- Modals `EditModelModal.jsx` & unified `EditVendorModal.jsx`; latter now uses default confirm/cancel footer and mobile-friendly modal sizing (`full-width` / `small`) via `useIsMobile`
• Update sidebar (`SiderBar.js`) and routing (`App.js`) to surface the feature
• Add helper updates (`render.js`) incl. `stringToColor`, dynamic LobeHub icon retrieval, and tag color palettes
Table UX improvements
• Replace separate status column with inline Enable / Disable buttons in operation column (matching channel table style)
• Limit visible tags to max 3; overflow represented as “+x” tag with padded `Popover` showing remaining tags
• Color all tags deterministically using `stringToColor` for consistent theming
• Change vendor column tag color to white for better contrast
Misc
• Minor layout tweaks, compact-mode toggle relocation, lint fixes and TypeScript/ESLint clean-up
These changes collectively deliver end-to-end model & vendor administration while unifying visual language across management tables.
Summary
• Introduced standalone `ModelSelectModal.jsx` for selecting channel models
• Fetch-list now opens modal instead of in-place select, keeping EditChannelModal lean
Modal Features
1. Search bar with `IconSearch`, keyboard clear & mobile full-screen support
2. Tab layout (“New Models” / “Existing Models”) displayed next to title, responsive wrapping
3. Models grouped by vendor via `getModelCategories` and rendered inside always-expanded `Collapse` panels
4. Per-category checkbox in panel extra area for bulk select / deselect
5. Footer checkbox for bulk select of all models in current tab, with real-time counter
6. Empty state uses `IllustrationNoResult` / `IllustrationNoResultDark` for visual consistency
7. Accessible header/footer paddings aligned with Semi UI defaults
Fixes & Improvements
• All indeterminate and full-select states handled correctly
• Consistent “selected X / Y” stats synced with active tab, not global list
• All panels now controlled via `activeKey`, ensuring they remain expanded
• Search, vendor grouping, and responsive layout tested across mobile & desktop
These changes modernise the channel model management workflow and prepare the codebase for upcoming upstream-ratio integration.
Summary
• Added role-specific localStorage keys for column visibility in three hooks:
- `useUsageLogsData.js` → `logs-table-columns-admin` / `logs-table-columns-user`
- `useMjLogsData.js` → `mj-logs-table-columns-admin` / `mj-logs-table-columns-user`
- `useTaskLogsData.js` → `task-logs-table-columns-admin` / `task-logs-table-columns-user`
Details
1. Each hook now derives a `STORAGE_KEY` based on `isAdminUser`, preventing admin and non-admin sessions from overwriting one another’s column settings.
2. Removed the previous “save but strip admin columns” workaround—settings are persisted unmodified to each role’s key.
3. Kept runtime behaviour: non-admin users still see admin-only columns forcibly hidden.
4. Replaced newly added Chinese comments with clear English equivalents for consistency.
Result
Switching between admin and non-admin accounts no longer corrupts column visibility preferences, and codebase comments are fully English-localized.
Summary
• Introduced a unified `selectFilter` helper that matches both `option.value` and `option.label`, ensuring all `<Select>` components support intuitive search (fixes channel “type” dropdown not filtering).
• Replaced all usages of the old `modelSelectFilter` with `selectFilter` in:
• `EditChannelModal.jsx`
• `SettingsPanel.js`
• `EditTokenModal.jsx`
• `EditTagModal.jsx`
• Removed the deprecated `modelSelectFilter` export from `utils.js` (no backward-compat alias).
• Updated documentation comments accordingly.
Why
The old filter only inspected `option.value`, causing searches to fail when `label` carried the meaningful text (e.g., numeric IDs for channel types). The new helper searches both fields, covering all scenarios and unifying the API across the codebase.
Notes
No functional regressions expected; all components have been migrated.
This commit introduces a unified, maintainable solution for all model-pricing filter buttons and removes redundant code.
Key points
• Added `usePricingFilterCounts` hook
- Centralises filtering logic and returns:
- `quotaTypeModels`, `endpointTypeModels`, `dynamicCategoryCounts`, `groupCountModels`
- Keeps internal helpers private (removed public `modelsAfterCategory`).
• Updated components to consume the new hook
- `PricingSidebar.jsx`
- `FilterModalContent.jsx`
• Improved button UI/UX
- `SelectableButtonGroup.jsx` now respects `item.disabled` and auto-disables when `tagCount === 0`.
- `PricingGroups.jsx` counts models per group (after all other filters) and disables groups with zero matches.
- `PricingEndpointTypes.jsx` enumerates all endpoint types, computes filtered counts, and disables entries with zero matches.
• Removed obsolete / duplicate calculations and comments to keep components lean.
The result is consistent, real-time tag counts across all filter groups, automatic disabling of unavailable options, and a single source of truth for filter computations, making future extensions straightforward.
Previously, the "Force Format" switch was displayed for every channel type
although it only applies to OpenAI (type === 1).
This change wraps the switch in a conditional so it renders exclusively when
the selected channel type is OpenAI.
Why:
- Prevents user confusion when configuring non-OpenAI channels
- Keeps the UI clean and context-relevant
Scope:
- web/src/components/table/channels/modals/EditChannelModal.jsx
No backend logic affected.
- Extract channel extra settings into a dedicated Card component for better visual hierarchy
- Replace custom gray background container with consistent Form component styling
- Simplify layout structure by removing complex Row/Col grid layout in favor of native Form component layout
- Unify help text styling by using extraText prop consistently across all form fields
- Move "Settings Documentation" link to card header subtitle for better accessibility
- Improve visual consistency with other setting cards by using matching design patterns
The channel extra settings (force format, thinking content conversion, pass-through body, proxy address, and system prompt) now follow the same design language as other configuration sections, providing a more cohesive user experience.
Affected settings:
- Force Format (OpenAI channels only)
- Thinking Content Conversion
- Pass-through Body
- Proxy Address
- System Prompt
- **Fix SideSheet double-click issue**: Remove early return for null modelData to prevent rendering blockage during async state updates
- **Component modularization**:
- Split ModelDetailSideSheet into focused sub-components (ModelHeader, ModelBasicInfo, ModelEndpoints, ModelPricingTable)
- Refactor PricingFilterModal with FilterModalContent and FilterModalFooter components
- Remove unnecessary FilterSection wrapper for cleaner interface
- **Improve visual consistency**:
- Unify avatar/icon logic between ModelHeader and PricingCardView components
- Standardize tag colors across all pricing components (violet/teal for billing types)
- Apply consistent dashed border styling using Semi UI theme colors
- **Enhance data accuracy**:
- Display raw endpoint type names (e.g., "openai", "anthropic") instead of translated descriptions
- Remove text alignment classes for better responsive layout
- Add proper null checks to prevent runtime errors
- **Code quality improvements**:
- Reduce component complexity by 52-74% through modularization
- Improve maintainability with single responsibility principle
- Add comprehensive error handling for edge cases
This refactoring improves component reusability, reduces bundle size, and provides a more consistent user experience across the model pricing interface.
Ensure non-admin users cannot enable columns reserved for administrators
across the following hooks:
* web/src/hooks/usage-logs/useUsageLogsData.js
- Force-hide CHANNEL, USERNAME and RETRY columns for non-admins.
* web/src/hooks/mj-logs/useMjLogsData.js
- Force-hide CHANNEL and SUBMIT_RESULT columns for non-admins.
* web/src/hooks/task-logs/useTaskLogsData.js
- Force-hide CHANNEL column for non-admins.
The checks run when loading column preferences from localStorage, overriding
any tampered settings to keep sensitive information hidden from
unauthorized users.
- Extract default values to DEFAULT_PRICING_FILTERS constant for centralized configuration
- Replace verbose type checks with optional chaining operator (?.) for cleaner code
- Eliminate redundant function type validations and comments
- Reduce code lines by ~50% (from 60 to 25 lines) while maintaining full functionality
- Improve code readability and follow modern JavaScript best practices
This refactoring enhances code quality without changing the function's behavior,
making it easier to maintain and modify default filter values in the future.
- Extract default values to DEFAULT_PRICING_FILTERS constant for centralized configuration
- Replace verbose type checks with optional chaining operator (?.) for cleaner code
- Eliminate redundant function type validations and comments
- Reduce code lines by ~50% (from 60 to 25 lines) while maintaining full functionality
- Improve code readability and follow modern JavaScript best practices
This refactoring enhances code quality without changing the function's behavior,
making it easier to maintain and modify default filter values in the future.
- Remove K/M switch from model price column header in pricing table
- Add "Display in K units" option to pricing display settings panel
- Update parameter passing for tokenUnit and setTokenUnit across components:
- PricingDisplaySettings: Add tokenUnit toggle functionality
- PricingSidebar: Pass tokenUnit props to display settings
- PricingFilterModal: Include tokenUnit in mobile filter modal
- Enhance resetPricingFilters utility to reset token unit to default 'M'
- Clean up PricingTableColumns by removing unused setTokenUnit parameter
- Add English translation for "按K显示单位" as "Display in K units"
This change improves UX by consolidating all display-related controls
in the filter settings panel, making the interface more organized and
the token unit setting more discoverable alongside other display options.
Affected components:
- PricingTableColumns.js
- PricingDisplaySettings.jsx
- PricingSidebar.jsx
- PricingFilterModal.jsx
- PricingTable.jsx
- utils.js (resetPricingFilters)
- en.json (translations)
- Create PricingEndpointTypes.jsx component for endpoint type filtering
- Add filterEndpointType state management in useModelPricingData hook
- Integrate endpoint type filtering logic in filteredModels computation
- Update PricingSidebar.jsx to include endpoint type filter component
- Update PricingFilterModal.jsx to support endpoint type filtering on mobile
- Extend resetPricingFilters utility function to include endpoint type reset
- Support filtering models by endpoint types (OpenAI, Anthropic, Gemini, etc.)
- Display model count for each endpoint type with localized labels
- Ensure filter state resets to first page when endpoint type changes
This enhancement allows users to filter models by their supported endpoint types,
providing more granular control over model selection in the pricing interface.
- Increase skeleton card count from 6 to 10 for better visual coverage
- Extend minimum skeleton display duration from 500ms to 1000ms for smoother UX
- Add circle shape to all pricing tags for consistent rounded design
- Apply circle styling to billing type, popularity, endpoint, and context tags
This commit improves the visual consistency and user experience of the pricing
card view by standardizing tag appearance and optimizing skeleton loading timing.
- Replace model count with group ratio display (x2.2, x1) in group filter
- Remove redundant "Available Groups" column from pricing table
- Remove "Availability" column and related logic completely
- Move "Supported Endpoint Types" column to fixed right position
- Clean up unused parameters and variables in PricingTableColumns.js
- Optimize variable declarations (let → const) and simplify render logic
- Improve code readability and reduce memory allocations
This refactor enhances user experience by:
- Providing clearer group ratio information in filters
- Simplifying table layout while maintaining essential functionality
- Improving performance through better code organization
Breaking changes: None
Filter out the special empty string group ("": "用户分组") from the
usable groups in PricingGroups component. This empty group represents
"user's current group" but contains no data and should not be displayed
in the group filter options.
- Add filter condition to exclude empty string keys from usableGroup
- Prevents displaying invalid empty group option in UI
- Improves user experience by showing only valid selectable groups
Add comprehensive loading state support with skeleton animations for the SelectableButtonGroup component, improving user experience during data loading.
Key Changes:
- Add loading prop to SelectableButtonGroup with minimum 500ms display duration
- Implement skeleton buttons with proper Semi-UI Skeleton wrapper and active animation
- Use fixed skeleton count (6 items) to prevent visual jumping during load transitions
- Pass loading state through all pricing filter components hierarchy:
- PricingSidebar and PricingFilterModal as container components
- PricingDisplaySettings, PricingCategories, PricingGroups, PricingQuotaTypes as filter components
Technical Details:
- Reference CardTable.js implementation for consistent skeleton UI patterns
- Add useEffect hook for 500ms minimum loading duration control
- Support both checkbox and regular button skeleton modes
- Maintain responsive layout compatibility (mobile/desktop)
- Add proper JSDoc parameter documentation for loading prop
Fixes:
- Prevent skeleton count sudden changes that caused visual discontinuity
- Ensure proper skeleton animation with Semi-UI active parameter
- Maintain consistent loading experience across all filter components
- Add withCheckbox prop to SelectableButtonGroup component for checkbox-prefixed buttons
- Support both single value and array activeValue for multi-selection scenarios
- Refactor PricingDisplaySettings to use consistent SelectableButtonGroup styling
- Replace Switch components with checkbox-enabled SelectableButtonGroup
- Replace Select dropdown with SelectableButtonGroup for currency selection
- Maintain unified UI/UX across all pricing filter components
- Add proper JSDoc documentation for new withCheckbox functionality
This improves visual consistency and provides a more cohesive user experience
in the model pricing filter interface.
Summary
• Swapped out the old availability UI for clearer icon-based feedback.
• Users now see a green check icon when their group can use a model and a red × icon (with tooltip) when it cannot.
Details
1. Imports
• Removed deprecated `IconVerify`.
• Added `IconCheckCircleStroked` ✅ and `IconClose` ❌ for new states.
2. Availability column
• `renderAvailable` now
– Shows a green `IconCheckCircleStroked` inside a popover (“Your group can use this model”).
– Shows a red `IconClose` inside a popover (“你的分组无权使用该模型”) when the model is inaccessible.
– Eliminates the empty cell/grey tag fallback.
3. Group tag
• Updated selected-group tag to use `IconCheckCircleStroked` for visual consistency.
Result
Improves UX by providing explicit visual cues for model availability and removes ambiguous blank cells.
Centralize filter-reset logic to improve maintainability and consistency.
- Add `resetPricingFilters` helper to `web/src/helpers/utils.js`, encapsulating all reset actions (search, category, currency, ratio, group, quota type, etc.).
- Update `PricingFilterModal.jsx` and `PricingSidebar.jsx` to import and use the new utility instead of keeping their own duplicate `handleResetFilters`.
- Removes repeated code, ensures future changes to reset behavior require modification in only one place, and keeps components lean.
* **PricingDisplaySettings.jsx**
• Extracted display settings (recharge price, currency, ratio toggle) from PricingSidebar
• Maintains complete styling and functionality as standalone component
* **SelectableButtonGroup.jsx**
• Added isMobile detection with conditional Col spans
• Mobile: `span={12}` (2 buttons per row) for better touch experience
• Desktop: preserved responsive grid `xs={24} sm={24} md={24} lg={12} xl={8}`
* **PricingSidebar.jsx**
• Updated imports to use new PricingDisplaySettings component
• Simplified component structure while preserving reset logic
These changes enhance code modularity and provide optimized mobile UX for filter button groups across the pricing interface.