Commit Graph

236 Commits

Author SHA1 Message Date
t0ng7u
63b9457b6c 🔍 fix(pricing): synchronize search term with sidebar filters & reset behavior
* Add `searchValue` to every dependency array in `usePricingFilterCounts`
  to ensure group/vendor/tag counts and disabled states update dynamically
  while performing fuzzy search.

* Refactor `PricingTopSection` search box into a controlled component:
  - Accept `searchValue` prop and bind it to `Input.value`
  - Extend memo dependencies to include `searchValue`
  This keeps the UI in sync with state changes triggered by `handleChange`.

* Guarantee that `resetPricingFilters` clears the search field by
  leveraging the new controlled input.

As a result, sidebar counters/disabled states now react to search input,
and the “Reset” button fully restores default filters without leaving the
search term visible.
2025-08-12 23:32:25 +08:00
t0ng7u
936b1f8d09 🐛 fix: group-ratio display & deduplicate price logic in model-pricing views
Summary
• Ensure “Group Ratio” shows correctly when “All” groups are selected.
• Eliminate redundant price calculations in both card and table views.

Details
1. PricingCardView.jsx
   • Removed obsolete renderPriceInfo function.
   • Calculate priceData once per model and reuse for header price string and footer ratio block.
   • Display priceData.usedGroupRatio as the group ratio fallback.

2. PricingTableColumns.js
   • Introduced WeakMap-based cache (getPriceData) to compute priceData only once per row.
   • Updated ratioColumn & priceColumn to reuse cached priceData.
   • Now displays priceData.usedGroupRatio, preventing empty cells for “All” group.

Benefits
• Correct visual output for group ratio across all views.
• Reduced duplicate calculations, improving render performance.
• Removed dead code, keeping components clean and maintainable.
2025-08-12 23:10:29 +08:00
t0ng7u
39c966efdd 🐛 fix: make ModelSelectModal panels collapsible and default to collapsed
- Switch Collapse from controlled (activeKey) to uncontrolled (defaultActiveKey) so user toggling works
- Add a stable key to reset Collapse state when tab/category changes
- Default all panels to collapsed via defaultActiveKey: []
- Preserve Panel itemKey for consistent behavior
- No linter errors introduced

Scope: web/src/components/table/channels/modals/ModelSelectModal.jsx
2025-08-12 10:22:00 +08:00
t0ng7u
03cfc05afd 🍭 ui: change pricing page card view pt-4 to py-4 2025-08-11 19:11:58 +08:00
t0ng7u
fa686207ed 🍭 ui: change pricing page card view p-4 to px-4 2025-08-11 18:32:19 +08:00
t0ng7u
da17bdb688 💄 style: Use segmented renderer for billing types in Models table; keep Pricing view unchanged
Frontend
- Models table (model management):
  - Render billing types with the same segmented list component (renderLimitedItems) used by tags and endpoints
  - Display quota_types as an array with capped items (maxDisplay: 3) and graceful fallback for unknown types
- Pricing view (unchanged by request):
  - Revert to single-value quota_type rendering and sorter
  - Keep ratio display logic based on quota_type only

Files
- web/src/components/table/models/ModelsColumnDefs.js
- web/src/components/table/model-pricing/view/table/PricingTableColumns.js

Notes
- This commit only adjusts the model management UI rendering; pricing views remain as-is
2025-08-11 15:53:55 +08:00
t0ng7u
4ad8eefaec 🚀 perf: optimize model management APIs, unify pricing types as array, and remove redundancies
Backend
- Add GetBoundChannelsByModelsMap to batch-fetch bound channels via a single JOIN (Distinct), compatible with SQLite/MySQL/PostgreSQL
- Replace per-record enrichment with a single-pass enrichModels to avoid N+1 queries; compute unions for prefix/suffix/contains matches in memory
- Change Model.QuotaType to QuotaTypes []int and expose quota_types in responses
- Add GetModelQuotaTypes for cached O(1) lookups; exact models return a single-element array
- Sort quota_types for stable output order
- Remove unused code: GetModelByName, GetBoundChannels, GetBoundChannelsForModels, FindModelByNameWithRule, buildPrefixes, buildSuffixes
- Clean up redundant comments, keeping concise and readable code

Frontend
- Models table: switch to quota_types, render multiple billing modes ([0], [1], [0,1], future values supported)
- Pricing table: switch to quota_types; ratio display now checks quota_types.includes(0); array rendering for billing tags

Compatibility
- SQL uses standard JOIN/IN/Distinct; works across SQLite/MySQL/PostgreSQL
- Lint passes; no DB schema changes (quota_types is a JSON response field only)

Breaking Change
- API field renamed: quota_type -> quota_types (array). Update clients accordingly.
2025-08-11 14:40:01 +08:00
t0ng7u
c8f7aa76e7 🔍 feat: Show matched model names & counts for non-exact model rules
Summary
-------
1. **Backend**
   • `model/model_meta.go`
     – Add `MatchedModels []string` and `MatchedCount int` (ignored by GORM) to expose matching details in API responses.
   • `controller/model_meta.go`
     – When processing prefix/suffix/contains rules in `fillModelExtra`, collect every matched model name, fill `MatchedModels`, and calculate `MatchedCount`.

2. **Frontend**
   • `web/src/components/table/models/ModelsColumnDefs.js`
     – Import `Tooltip`.
     – Enhance `renderNameRule` to:
       – Display tag text like “前缀 5个模型” for non-exact rules.
       – Show a tooltip listing all matched model names on hover.

Impact
------
Users now see the total number of concrete models aggregated under each prefix/suffix/contains rule and can inspect the exact list via tooltip, improving transparency in model management.
2025-08-10 21:32:18 +08:00
t0ng7u
42d2394585 Merge remote-tracking branch 'origin/alpha' into alpha 2025-08-10 21:14:47 +08:00
t0ng7u
94bd44d0f2 feat: enhance model billing aggregation & UI display for unknown quota type
Summary
-------
1. **Backend**
   • `controller/model_meta.go`
     – For prefix/suffix/contains rules, aggregate endpoints, bound channels, enable groups, and quota types across all matched models.
     – When mixed billing types are detected, return `quota_type = -1` (unknown) instead of defaulting to volume-based.

2. **Frontend**
   • `web/src/helpers/utils.js`
     – `calculateModelPrice` now handles `quota_type = -1`, returning placeholder `'-'`.

   • `web/src/components/table/model-pricing/view/card/PricingCardView.jsx`
     – Billing tag logic updated: displays “按次计费” (times), “按量计费” (volume), or `'-'` for unknown.

   • `web/src/components/table/model-pricing/view/table/PricingTableColumns.js`
     – `renderQuotaType` shows “未知” for unknown billing type.

   • `web/src/components/table/models/ModelsColumnDefs.js`
     – Unified `renderQuotaType` to return `'-'` when type is unknown.

   • `web/src/components/table/model-pricing/modal/components/ModelPricingTable.jsx`
     – Group price table honors unknown billing type; pricing columns show `'-'` and neutral tag color.

3. **Utilities**
   • Added safe fallback colours/tags for unknown billing type across affected components.

Impact
------
• Ensures correct data aggregation for non-exact model matches.
• Prevents UI from implying volume billing when actual type is ambiguous.
• Provides consistent placeholder display (`'-'` or “未知”) across cards, tables and modals.

No breaking API changes; frontend gracefully handles legacy values.
2025-08-10 21:09:49 +08:00
CaIon
7f462a084c feat: Add ChannelOtherSettings to manage additional channel configurations 2025-08-10 20:21:30 +08:00
t0ng7u
d1d945eaa0 🔠 refactor: refine group label formatting in price info
Summary:
• Updated `helpers/utils.js` to display the “group” label without a colon, ensuring consistent typography with other price elements.

Details:
1. `formatPriceInfo`
   – Changed `{t('分组')}:` to `{t('分组')}` for a cleaner look.
   – Keeps spacing intact between label and selected group name.
2. No functional impact; purely visual polish.
2025-08-10 17:17:49 +08:00
t0ng7u
dbde044213 📱 style: Hide vendor introduction on mobile devices
Summary:
• Updated `PricingTopSection.jsx` to conditionally render `PricingVendorIntroWithSkeleton` only when `isMobile` is false.

Details:
1. Wrapped vendor-intro block in `!isMobile` check, preventing unnecessary content on small screens.
2. Kept desktop experience unchanged; no impact on other features.
3. Lint check passed with no new issues.

Result:
Cleaner mobile UI with improved performance and visual focus.
2025-08-10 14:10:50 +08:00
t0ng7u
870132a5cb feat: Add tag-based filtering & refactor filter counts logic
Overview:
• Introduced a new “Model Tag” filter across pricing screens
• Refactored `usePricingFilterCounts` to eliminate duplicated logic
• Improved tag handling to be case-insensitive and deduplicated
• Extended utilities to reset & persist the new filter

Details:
1. Added `filterTag` state to `useModelPricingData` and integrated it into all filtering paths.
2. Created reusable `PricingTags` component using `SelectableButtonGroup`.
3. Incorporated tag filter into `PricingSidebar` and mobile `PricingFilterModal`, including reset support.
4. Enhanced `resetPricingFilters` (helpers/utils) to restore tag filter defaults.
5. Refactored `usePricingFilterCounts.js`:
   • Centralized predicate `matchesFilters` to remove redundancy
   • Normalized tag parsing via `normalizeTags` helper
   • Memoized model subsets with concise filter calls
6. Updated lints – zero errors after refactor.

Result:
Users can now filter models by custom tags with consistent UX, and internal logic is cleaner, faster, and easier to extend.
2025-08-10 14:05:25 +08:00
t0ng7u
ffa898c52d 🐛 fix(PricingCardView): hide placeholder dash when no custom tags
Previously, the card view displayed a “-” whenever a model had no custom tags,
because `renderLimitedItems` returned a dash for an empty array.
Now the function is only invoked when `customTags.length > 0`, removing the
unwanted placeholder and keeping the UI clean.

File affected:
- web/src/components/table/model-pricing/view/card/PricingCardView.jsx
2025-08-10 13:45:16 +08:00
CaIon
1cc81deb69 feat: Enhance EditChannelModal with JSONEditor key updates and input reset
- Added unique keys for JSONEditor components to ensure proper re-rendering based on channelId.
- Implemented input reset to clear previous JSON field values when the modal is opened.
2025-08-10 12:22:18 +08:00
Calcium-Ion
d6b03d4760 Merge pull request #1541 from QuantumNous/fluent-read
feat: added "流畅阅读" (FluentRead) as a new chat provider option.
2025-08-10 10:26:22 +08:00
t0ng7u
cb75e25a1a feat: Add model icon support across backend and UI; prefer model icon over vendor; add icon column in Models table
Backend:
- Model: Add `icon` field to `model.Model` (gorm: varchar(128)); auto-migrated via GORM.
- Pricing API: Extend `model.Pricing` with `icon` and populate from model meta in `GetPricing()`.

Frontend:
- EditModelModal: Add `icon` input (with @lobehub/icons helper link); wire into init/load/submit flows.
- ModelHeader / PricingCardView: Prefer rendering `model.icon`; fallback to `vendor_icon`; final fallback to initials avatar.
- Models table: Add leading “Icon” column, rendering `model.icon` or `vendor` icon via `getLobeHubIcon`.

Notes:
- Backward-compatible. Existing data without `icon` remain unaffected.
- No manual SQL needed; column is added by AutoMigrate.

Affected files:
- model/model_meta.go
- model/pricing.go
- web/src/components/table/models/modals/EditModelModal.jsx
- web/src/components/table/model-pricing/modal/components/ModelHeader.jsx
- web/src/components/table/model-pricing/view/card/PricingCardView.jsx
- web/src/components/table/models/ModelsColumnDefs.js
2025-08-10 01:38:59 +08:00
t0ng7u
9572e16dcb feat: Support dot‑chained props for LobeHub icons
- render.js: Enhance getLobeHubIcon to parse dot‑chained props, e.g.:
  - OpenAI.Avatar.type={'platform'}
  - OpenRouter.Avatar.shape={'square'}
  - Parses booleans/numbers/strings and {…} wrappers; keeps the 2nd arg `size` unless overridden by chain props. Backward compatible.
- EditVendorModal.jsx: Update UI copy — simplify placeholder; document chain‑parameter examples in extra text with doc link.
- en.json: Fix invalid escape sequences in the new i18n string to satisfy linter.

No behavioral changes outside icon rendering; lints pass.
2025-08-10 01:18:36 +08:00
t0ng7u
459fce196f 🍎 chore: modify pagination pageSizeOpts 2025-08-10 00:58:17 +08:00
t0ng7u
ada434fb20 🎨 refactor: MultiKeyManageModal: cleaner stats UI, remove chart, integrate toolbar/pagination, and improve UX
- Replace custom dots with Semi Badge types (success/danger/warning); add compact Progress bars
- Remove pie chart and related deps/config; move total key count and mode tags into the modal title
- Rework header using Row/Col; three equal stat cards (enabled/manual-disabled/auto-disabled)
- Integrate toolbar into Table title; wrap content with Card; use Table’s native empty state
- Make “Enable All” conditional (hidden when all keys are enabled), mirroring “Disable All”
- Unify numeric typography (current/total same size) for better readability
- Default page size set to 10; fallback to 10 when backend page_size is absent; page-size options: 10/20/50/100
- Cleanup imports and dead code (remove VChart and pie-spec logic)
- Minor spacing polish (extra bottom margin before table), no footer buttons
2025-08-10 00:55:18 +08:00
t0ng7u
0727353afa 💄 style(ui): replace inline gradients with reusable pastel blur balls; improve dark mode
- Introduce a global CSS utility `with-pastel-balls` in `web/src/index.css`, rendering pastel “blur balls” via ::before with CSS variables (`--pb1..--pb4`, `--pb-opacity`, `--pb-blur`) for easy theming.
- Apply the utility to pricing header cards and skeletons:
  - `web/src/components/table/model-pricing/layout/header/PricingVendorIntro.jsx`
  - `web/src/components/table/model-pricing/layout/header/PricingVendorIntroSkeleton.jsx`
- Remove per-component inline `linear-gradient(...)` backgrounds and redundant absolute-positioned decoration nodes to reduce duplication.
- Dark mode:
  - Keep the same pastel palette (pink/lavender/mint/peach).
  - Increase visibility with `--pb-opacity: 0.36`, `--pb-blur: 65px`, and `mix-blend-mode: screen`.
- No functional logic changes; UI-only. Lint passes.

Affected files:
- web/src/index.css
- web/src/components/table/model-pricing/layout/header/PricingVendorIntro.jsx
- web/src/components/table/model-pricing/layout/header/PricingVendorIntroSkeleton.jsx
2025-08-09 21:40:32 +08:00
CaIon
8639699d49 feat: improve FluentRead notification handling and user prompts 2025-08-09 18:37:08 +08:00
CaIon
55dbdba636 feat: add FluentRead support in chat configuration 2025-08-09 18:26:45 +08:00
CaIon
919eacd907 Merge remote-tracking branch 'origin/alpha' into alpha 2025-08-09 17:02:20 +08:00
CaIon
4cec55c9a4 feat: enhance TokensPage and useTokensData to support Fluent integration and notifications 2025-08-09 17:02:06 +08:00
t0ng7u
aa8ec92976 🧹 Refactor: remove redundant code and simplify renderers
- Users table (UsersColumnDefs.js):
  - Remove unused quota calculations from the status renderer
  - Keep status Tag minimal; tooltip shows request count only
  - No functional changes

- Tokens table (TokensColumnDefs.js):
  - Simplify chats menu parsing from localStorage; remove redundant flags/loops
  - Remove unused variables and console statements
  - Keep error handling via showError; preserve existing operations behavior

- General:
  - Codebase tidying only; no UI/logic changes beyond cleanup
  - Lint passes successfully
2025-08-09 16:51:09 +08:00
t0ng7u
44da9c9a28 style(ui): Replace switches with buttons; add quota column with Popover; cleanup
- Tokens/Users tables:
  - Replaced status Switch with explicit Enable/Disable buttons in the operation column
  - Unified button styles with Channels/Models (Disable: danger + small; Enable: default + small)
  - Status column now shows a small Tag only; standardized labels (Enabled/Disabled/etc.); removed usage info

- New "Remaining/Total Quota" column:
  - Wrapped in a white Tag; shows Remaining/Total with a progress bar
  - Replaced Tooltip with Popover; contents use Typography.Paragraph with copyable values
  - Copyable content excludes percentages (only numeric quota values are copied)
  - Added padding to Popover content for better readability

- Tokens specifics:
  - For unlimited quota, show a white Tag "Unlimited quota" with a Popover that displays copyable "Used quota"

- Cleanup:
  - Removed Switch imports/handlers and unused code paths
  - Eliminated console logs and redundant flags; simplified chats parsing
  - Removed quota calculations from status renderers

Files:
- web/src/components/table/tokens/TokensColumnDefs.js
- web/src/components/table/users/UsersColumnDefs.js
2025-08-09 16:47:14 +08:00
CaIon
2a804b6c02 feat: add system prompt override functionality in channel settings and request handling #1468 2025-08-09 12:53:06 +08:00
Calcium-Ion
ec28671aed Merge pull request #1429 from feitianbubu/pr/video-preview-modal
feat: add video preview modal
2025-08-09 11:37:19 +08:00
t0ng7u
2fc0d7b2a7 📱 feat(ui): enhance mobile pagination in PricingCardView
* Integrate `useIsMobile` hook to detect mobile devices.
* Pagination now automatically:
  * sets `size="small"` on mobile screens
  * enables `showQuickJumper` for quicker navigation on small screens
* Desktop behaviour remains unchanged.
2025-08-09 10:14:35 +08:00
t0ng7u
3a9e394814 feat: Extend endpoint templates to cover all native endpoints
This commit updates the quick-fill endpoint templates used in the model and pre-fill group editors:

• `EditModelModal.jsx`
• `EditPrefillGroupModal.jsx`

Key changes
1. Added missing default endpoints defined in `common/endpoint_defaults.go`.
   - `openai-response`
   - `gemini`
   - `jina-rerank`
2. Ensured each template entry includes both `path` and `method` for clarity.

Benefits
• Provides one-click access to every built-in upstream endpoint, reducing manual input.
• Keeps the UI definitions in sync with backend defaults, preventing mismatch errors.
2025-08-09 09:33:13 +08:00
t0ng7u
3d9d3da1ae 🔧 fix(pricing): synchronize group ratio in Table & Card views with sidebar selection
Problem
Choosing a different token-group in the pricing sidebar only updated the filter but did **not** refresh the displayed group ratio in both the Table (`@table/`) and Card (`@card/`) views. The callback used by the sidebar changed `filterGroup` yet left `selectedGroup` untouched, so ratio columns/cards kept showing the previous value.

Solution
• `PricingSidebar.jsx`
  – Accept new prop `handleGroupClick` (from `useModelPricingData`).
  – Forward this callback to `PricingGroups` (`setFilterGroup={handleGroupClick}`) while retaining `setFilterGroup` for reset logic.
  – Keeps both `filterGroup` filtering and `selectedGroup` state in sync via the single unified handler.

Result
Switching groups in the sidebar now simultaneously updates:
1. the model list filtering, and
2. the ratio information shown in both pricing Table and Card views.

No UI/UX regression; linter passes.
2025-08-09 08:58:36 +08:00
t0ng7u
c6bb1dcc0e 🔧 refactor(pricing): render “auto” routing chain only when relevant & remove unused prop
Changes
1. ModelPricingTable.jsx
   • Compute `autoChain` as the intersection of `autoGroups` and the model’s `enable_groups` (order preserved).
   • Display the chain banner only when `autoChain.length > 0`; banner shows the reduced path (e.g. `a → c → e`).
   • Dropped obsolete `selectedGroup` prop; all callers updated.

2. ModelDetailSideSheet.jsx / PricingPage.jsx
   • Removed forwarding of deleted `selectedGroup` prop.

Outcome
– “Auto group routing” appears only for models that actually participate in the chain, avoiding empty or irrelevant banners.
– Codebase simplified by eliminating an unused prop.
2025-08-08 15:11:31 +08:00
t0ng7u
1690b05629 🚀 feat(pricing): clarify “auto” group routing chain and exclude it from price table
Detailed changes
Backend
• `controller/pricing.go` now includes `auto_groups` in `/api/pricing` response, sourced from `setting.AutoGroups`.

Frontend
• `useModelPricingData.js`
  – Parses `auto_groups` and exposes `autoGroups` state.
• `PricingPage.jsx` → `ModelDetailSideSheet.jsx` → `ModelPricingTable.jsx`
  – Thread `autoGroups` through component tree.
• `ModelPricingTable.jsx`
  – Removes deprecated `getGroupDescription` / `Tooltip`.
  – Filters out `auto` when building price table rows.
  – Renders a descriptive banner: “auto 分组调用链路 → auto → group1 → …”, clarifying fallback order without showing prices.
• Minor i18n tweak: adds `auto分组调用链路` key for the banner text.

Why
Users were confused by the “auto” tag appearing alongside regular groups with no price.
This change:
1. Makes the routing chain explicit.
2. Keeps the pricing table focused on billable groups.

No breaking API changes; existing clients can ignore the new `auto_groups` field.
2025-08-08 14:49:55 +08:00
t0ng7u
d0fb54fbfe feat(web): add model prefill group quick-add buttons to channel models selector
- Added support to fetch and render “model prefill groups” in `EditChannelModal.jsx`
- Users can now click a group button to instantly merge that group’s models into the models Select
- Mirrors the prefill-group UX used for tags/endpoints in `EditModelModal.jsx`

Details
- UI/UX:
  - Renders one button per model group inside the models field’s extra actions
  - Clicking a button merges its items into the selected models (trimmed, deduplicated), updating immediately
  - Non-destructive and works alongside existing actions (fill related/all models, fetch upstream, clear, copy)
- API:
  - GET `/api/prefill_group?type=model`
  - Handles `items` as either an array or a JSON string array for robustness
  - If request fails or returns no groups, buttons are simply not shown
- i18n:
  - Reuses existing i18n; group names come from backend and are displayed as-is
- Performance:
  - Simple set merge; negligible overhead
- Backward compatibility:
  - No changes required on the backend or elsewhere; feature is additive
- Testing (manual):
  1) Open channel modal (new or edit) and navigate to the Models section
  2) Confirm model group buttons render when groups are configured
  3) Click a group button → models Select updates with merged models (no duplicates)
  4) Verify other actions (fill related/all, fetch upstream, clear, copy) still work
  5) Close/reopen modal → state resets as expected

Implementation
- `web/src/components/table/channels/modals/EditChannelModal.jsx`
  - Added `modelGroups` state and `fetchModelGroups()` (GET `/api/prefill_group?type=model`)
  - Invoked `fetchModelGroups()` when the modal opens
  - Rendered group buttons in the models Select `extraText`, merging group items into current selection

Chore
- Verified no new linter errors were introduced.
2025-08-08 04:48:18 +08:00
t0ng7u
346b869d60 💄 ui: adjust column layout in pricing table
- Move model price column to fixed right position
- Convert endpoint types column from fixed to regular column
- Reorder columns: endpoint types now appears before ratio column
- Improve table layout and user experience for pricing data viewing

Changes made to web/src/components/table/model-pricing/view/table/PricingTableColumns.js:
* Removed `fixed: 'right'` from endpointColumn
* Added `fixed: 'right'` to priceColumn
* Updated column order in the columns array
2025-08-08 04:41:46 +08:00
t0ng7u
473f3b6f3e ♻️ refactor(model): replace gorm.io/datatypes with JSONValue for PrefillGroup.Items; fix JSON scan across drivers
- Why:
  - Avoid introducing `gorm.io/datatypes` for a single field.
  - Align with existing pattern (`ChannelInfo`, `Properties`) using `Scanner`/`Valuer`.
  - Fix runtime error when drivers return JSON as string.

- What:
  - Introduced `JSONValue` (based on `json.RawMessage`) implementing `sql.Scanner` and `driver.Valuer`, with `MarshalJSON`/`UnmarshalJSON` to preserve raw JSON in API.
  - Updated `PrefillGroup.Items` to use `JSONValue` with `gorm:"type:json"`.
  - Localized comments in `model/prefill_group.go` to Chinese.

- Impact:
  - Resolves “unsupported Scan, storing driver.Value type string into type *json.RawMessage”.
  - Works with MySQL/Postgres/SQLite whether JSON is returned as `[]byte` or `string`.
  - API and DB schema remain unchanged; no `go.mod` changes; lints pass.

Files changed:
- model/prefill_group.go
2025-08-08 04:09:53 +08:00
t0ng7u
6341847203 🎨 refactor(ui): merge “Content Configuration” into “Basic Information” card in EditPrefillGroupModal
- Move `items` field (`JSONEditor` for endpoint type, `Form.TagInput` otherwise) into the first “Basic Information” card
- Remove the second “Content Configuration” card and its header; consolidate to a single-card layout
- Preserve form initialization, validation, and submit logic; API payload structure remains unchanged
- Improves clarity and reduces visual clutter without altering behavior
- Lint passes

Affected file:
- `web/src/components/table/models/modals/EditPrefillGroupModal.jsx`

No breaking changes.
2025-08-08 03:04:51 +08:00
t0ng7u
4e75a9b3b3 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.
2025-08-08 02:59:45 +08:00
t0ng7u
8fba0017c7 feat(pricing+endpoints+ui): wire custom endpoint mapping end‑to‑end and overhaul visual JSON editor
Backend (Go)
- Include custom endpoints in each model’s SupportedEndpointTypes by parsing Model.Endpoints (JSON) and appending keys alongside native endpoint types.
- Build a global supportedEndpointMap map[string]EndpointInfo{path, method} by:
  - Seeding with native defaults.
  - Overriding/adding from models.endpoints (accepts string path → default POST, or {path, method}).
- Expose supported_endpoint at the top level of /api/pricing (vendors-like), removing per-model duplication.
- Fix default path for EndpointTypeOpenAIResponse to /v1/responses.
- Keep concurrency/caching for pricing retrieval intact.

Frontend (React)
- Fetch supported_endpoint in useModelPricingData and propagate to PricingPage → ModelDetailSideSheet → ModelEndpoints.
- ModelEndpoints
  - Resolve path+method via endpointMap; replace {model} with actual model name.
  - Fix mobile visibility; always show path and HTTP method.
- JSONEditor
  - Wrap with Form.Slot to inherit form layout; simplify visual styles.
  - Use Tabs for “Visual” / “Manual” modes.
  - Unify editors: key-value editor now supports nested JSON:
    - “+” to convert a primitive into an object and add nested fields.
    - Add “Convert to value” for two‑way toggle back from object.
    - Stable key rename without reordering rows; new rows append at bottom.
    - Use Row/Col grid for clean alignment; region editor uses Form.Slot + grid.
- Editing flows
  - EditModelModal / EditPrefillGroupModal use JSONEditor (editorType='object') for endpoint mappings.
  - PrefillGroupManagement renders endpoint group items by JSON keys.

Data expectations / compatibility
- models.endpoints should be a JSON object mapping endpoint type → string path or {path, method}. Strings default to POST.
- No schema changes; existing TEXT field continues to store JSON.

QA
- /api/pricing now returns custom endpoint types and global supported_endpoint.
- UI shows both native and custom endpoints; paths/methods render on mobile; nested editing works and preserves order.
2025-08-08 02:34:15 +08:00
t0ng7u
0a231a8acc 🎨 feat(models): add row styling for disabled models in ModelsTable
Add visual distinction for enabled/disabled models by applying different
background colors to table rows based on model status. This implementation
follows the same pattern used in ChannelsTable for consistent user experience.

Changes:
- Modified handleRow function in useModelsData.js to include row styling
- Disabled models (status !== 1) now display with gray background using
  --semi-color-disabled-border CSS variable
- Enabled models (status === 1) maintain normal background color
- Preserved existing row click selection functionality

This enhancement improves the visual feedback for users to quickly identify
which models are active vs inactive in the models management interface.
2025-08-07 10:54:05 +08:00
t0ng7u
94506bee99 feat(models): Revamp EditModelModal UI and UX
This commit significantly refactors the `EditModelModal` component to streamline the user interface and enhance usability, aligning it with the interaction patterns found elsewhere in the application.

- **Consolidated Layout:** Merged the "Vendor Information" and "Feature Configuration" sections into a single "Basic Information" card. This simplifies the form, reduces clutter, and makes all settings accessible in one view.

- **Improved Prefill Groups:** Replaced the separate `Select` dropdowns for tag and endpoint groups with a more intuitive button-based system within the `extraText` of the `TagInput` components.

- **Additive Button Logic:** The prefill group buttons now operate in an additive mode. Users can click multiple group buttons to incrementally add tags or endpoints, with duplicates being automatically handled.

- **Clear Functionality:** Added "Clear" buttons for both tags and endpoints, allowing users to easily reset the fields.

- **Code Cleanup:** Removed the unused `endpointOptions` constant and unnecessary icon imports (`Building`, `Settings`) to keep the codebase clean.
2025-08-06 03:29:45 +08:00
t0ng7u
7c814a5fd9 🚀 refactor: migrate vendor-count aggregation to model layer & align frontend logic
Summary
• Backend
  – Moved duplicate-name validation and total vendor-count aggregation from controllers (`controller/model_meta.go`, `controller/vendor_meta.go`, `controller/prefill_group.go`) to model layer (`model/model_meta.go`, `model/vendor_meta.go`, `model/prefill_group.go`).
  – Added `GetVendorModelCounts()` and `Is*NameDuplicated()` helpers; controllers now call these instead of duplicating queries.
  – API response for `/api/models` now returns `vendor_counts` with per-vendor totals across all pages, plus `all` summary.
  – Removed redundant checks and unused imports, eliminating `go vet` warnings.

• Frontend
  – `useModelsData.js` updated to consume backend-supplied `vendor_counts`, calculate the `all` total once, and drop legacy client-side counting logic.
  – Simplified initial data flow: first render now triggers only one models request.
  – Deleted obsolete `updateVendorCounts` helper and related comments.
  – Ensured search flow also sets `vendorCounts`, keeping tab badges accurate.

Why
This refactor enforces single-responsibility (aggregation in model layer), delivers consistent totals irrespective of pagination, and removes redundant client queries, leading to cleaner code and better performance.
2025-08-06 01:40:08 +08:00
t0ng7u
327a0ca323 🚀 refactor: refine pricing refresh logic & hide disabled models
Summary
-------
1. Pricing generation
   • `model/pricing.go`: skip any model whose `status != 1` when building
     `pricingMap`, ensuring disabled models are never returned to the
     front-end.

2. Cache refresh placement
   • `controller/model_meta.go`
     – Removed `model.RefreshPricing()` from pure read handlers
       (`GetAllModelsMeta`, `SearchModelsMeta`).
     – Kept refresh only in mutating handlers
       (`Create`, `Update`, `Delete`), guaranteeing data is updated
       immediately after an admin change while avoiding redundant work
       on every read.

Result
------
Front-end no longer receives information about disabled models, and
pricing cache refreshes occur exactly when model data is modified,
improving efficiency and consistency.
2025-08-05 23:18:12 +08:00
t0ng7u
1ccc728e5d 💄 fix(pricing-card): align skeleton responsive grid with actual card layout
- Update PricingCardSkeleton grid classes from 'sm:grid-cols-2 lg:grid-cols-3'
  to 'xl:grid-cols-2 2xl:grid-cols-3' to match PricingCardView layout
- Ensures consistent column count between skeleton and actual content
  at same screen sizes
- Improves loading state visual consistency across different breakpoints
2025-08-04 22:03:12 +08:00
t0ng7u
11ee80d377 🍎 chore: modify the JSONEditor component import path 2025-08-04 21:58:10 +08:00
t0ng7u
512850e83d Merge remote-tracking branch 'origin/alpha' into refactor/model-pricing 2025-08-04 21:37:38 +08:00
t0ng7u
0e9c3cde7c 🏗️ refactor: Replace model categories with vendor-based filtering and optimize data structure
- **Backend Changes:**
  - Refactor pricing API to return separate vendors array with ID-based model references
  - Remove redundant vendor_name/vendor_icon fields from pricing records, use vendor_id only
  - Add vendor_description to pricing response for frontend display
  - Maintain 1-minute cache protection for pricing endpoint security

- **Frontend Data Flow:**
  - Update useModelPricingData hook to build vendorsMap from API response
  - Enhance model records with vendor info during data processing
  - Pass vendorsMap through component hierarchy for consistent vendor data access

- **UI Component Replacements:**
  - Replace PricingCategories with PricingVendors component for vendor-based filtering
  - Replace PricingCategoryIntro with PricingVendorIntro in header section
  - Remove all model category related components and logic

- **Header Improvements:**
  - Implement vendor intro with real backend data (name, icon, description)
  - Add text collapsible feature (2-line limit with expand/collapse functionality)
  - Support carousel animation for "All Vendors" view with vendor icon rotation

- **Model Detail Modal Enhancements:**
  - Update ModelHeader to use real vendor icons via getLobeHubIcon()
  - Move tags from header to ModelBasicInfo content area to avoid SideSheet title width constraints
  - Display only custom tags from backend with stringToColor() for consistent styling
  - Use Space component with wrap property for proper tag layout

- **Table View Optimizations:**
  - Integrate RenderUtils for description and tags columns
  - Implement renderLimitedItems for tags (max 3 visible, +x popover for overflow)
  - Use renderDescription for text truncation with tooltip support

- **Filter Logic Updates:**
  - Vendor filter shows disabled options instead of hiding when no models match
  - Include "Unknown Vendor" category for models without vendor information
  - Remove all hardcoded vendor descriptions, use real backend data

- **Code Quality:**
  - Fix import paths after component relocation
  - Remove unused model category utilities and hardcoded mappings
  - Ensure consistent vendor data usage across all pricing views
  - Maintain backward compatibility with existing pricing calculation logic

This refactor provides a more scalable vendor-based architecture while eliminating
data redundancy and improving user experience with real-time backend data integration.
2025-08-04 21:36:31 +08:00
CaIon
c00f5a17c8 feat: improve layout and pagination handling in MultiKeyManageModal 2025-08-04 20:16:51 +08:00