1. 27 Jun, 2025 12 commits
  2. 26 Jun, 2025 6 commits
    • 🐛 fix(redemptions-table): correct initial page index and pagination state · 0cad369f
      Summary:
      The redemption list occasionally displayed an invalid range such as “Items -9 - 0” and failed to highlight page 1 after a refresh. This was caused by the table being initialized with `currentPage = 0`.
      
      Changes:
      • update `useEffect` to load data starting from page 1 instead of page 0
      • refactor `loadRedemptions` to accept `page` (default 1) and sanitize backend‐returned pages (`<= 0` coerced to 1)
      • keep other logic unchanged
      
      Impact:
      Pagination text and page selection now show correct values on first load or refresh, eliminating negative ranges and ensuring the first page is properly highlighted.
      t0ng7u committed
    • 🐛 fix(redemptions-table): show loading indicator while refetching data · 256b9a9f
      Previously, the table did not enter the loading state after performing actions such as deleting, enabling, or disabling a redemption code. This caused a brief period where the UI appeared unresponsive while awaiting the backend response.
      
      Changes made:
      • Added `setLoading(true)` at the beginning of `loadRedemptions` to activate the loading spinner whenever data is (re)fetched.
      • Added an explanatory code comment to clarify the intent.
      
      This improves user experience by clearly indicating that the system is processing and prevents confusion during data refresh operations.
      t0ng7u committed
    • 🎁 refactor(ui/redemption): migrate EditRedemption page to Semi Form & enhance UX · f2dd64a3
      SUMMARY
      • Re-implemented `web/src/pages/Redemption/EditRedemption.js` with Semi Form components, removing legacy local-state handling.
      • Added `formApiRef` for centralized control; external “Submit” button now triggers `formApi.submitForm()`.
      • Replaced `Input/AutoComplete/DatePicker` etc. with `<Form.*>` fields, leveraging built-in validation & accessibility.
      • Field validations:
        – `name` (create only), `quota`, `count` → required with localized messages.
      • Expiration-time flow:
        – Default value `null` (no more 1970-01-01).
        – When loading data, convert 0 → null, timestamp → Date.
        – On submit, Date → unix seconds; empty → 0.
      • Responsive grid layout (`Row/Col`) for tidy alignment.
      • Added helpful `showClear` & full-width styling for inputs; quota presets retained.
      • Cleaned unused imports & handlers; fixed linter issues.
      
      RESULT
      The Redemption form now benefits from higher performance, clearer validation, and a cleaner codebase consistent with Semi Design best practices.
      t0ng7u committed
    • refactor(ui/token): migrate EditToken page to Semi Form API and polish UX · 0900f43c
      SUMMARY
      • Re-implemented `EditToken.js` with Semi Form components, eliminating manual state handling and reducing re-renders.
      • Added grid-based layout; “Expiration Time” selector now sits inline with quick-set buttons for consistent alignment on desktop & mobile.
      • Introduced dedicated “Quota”, “Access”, “Model Limits”, and “Group” cards for clearer field grouping.
      • Reworked model-limit interaction: single multi-select list replaces checkbox toggle; backend flag `model_limits_enabled` is now inferred automatically.
      • Applied required validation rules to critical fields (`name`, `remain_quota`, `group`, `expired_time`, `tokenCount`) with localized messages.
      • Enabled dynamic option loading for models & groups; default auto-group honoured.
      • Added unlimited-quota switch, quota presets, and helpful extraText/tooltips.
      • Removed obsolete `handleInputChange` & `setUnlimitedQuota` helpers; formApi now manages all data flow.
      • Cleaned imports (e.g., dropped unused `IconUserGroup`), fixed linter errors, and updated submit logic to use `formApi.submitForm()`.
      
      RESULT
      The token creation/editing experience is faster, more accessible, and easier to maintain, fully aligned with Semi Design best practices.
      t0ng7u committed
    • 🎨 style: unify card header UI, switch to Avatar icons & remove oversized props · f80eb958
      Summary
      • Replaced gradient header blocks with compact, neutral headers wrapped in `Avatar` across the following pages:
        - Channel / EditChannel.js
        - Channel / EditTagModal.js
        - Redemption / EditRedemption.js
        - Token / EditToken.js
        - User / EditUser.js
        - User / AddUser.js
      
      Details
      1. Added `Avatar` import and substituted raw icon elements, assigning semantic colors (`blue`, `green`, `purple`, `orange`, etc.) and consistent 16 px icons for a cleaner look.
      2. Removed gradient backgrounds, decorative “blur-ball” shapes, and extra paddings from header containers to achieve a tight, flat design.
      3. Stripped all `size="large"` attributes from `Button`, `Input`, `Select`, `DatePicker`, `AutoComplete`, and `Avatar` components, allowing default sizing for better visual density.
      4. Eliminated redundant `bodyStyle` background overrides in some `SideSheet` components.
      5. No business logic touched; all changes are purely presentational.
      
      Result
      The editing and creation dialogs now share a unified, compact style consistent with the latest design language, improving readability and user experience without altering functionality.
      t0ng7u committed
  3. 25 Jun, 2025 11 commits
    • 🔒 style: Hide registration link when Self-Use Mode is enabled · a976d9d3
      • Add conditional rendering (`!status.self_use_mode_enabled`) to LoginForm
      • Suppress “Don't have an account? Register” CTA in self-hosted scenarios
      • Keeps UI clean and prevents unintended user sign-ups under self-use mode
      • No impact on regular multi-user deployments
      t0ng7u committed
    • 🐛 fix(auth): prevent duplicate “session expired” toast on login · 12756671
      Login Form used to display the message “未登录或登录已过期,请重新登录” twice
      because the `useEffect` that inspects the `expired` query parameter was
      re-executed on every re-render (e.g. language change or React StrictMode’s
      double-mount in development).
      
      ### What's changed
      • **LoginForm.js** – `useEffect` that shows the toast now has an empty
        dependency array so it runs only once on initial mount.
      • Reviewed **PasswordResetConfirm.js**, **PasswordResetForm.js** and
        **RegisterForm.js** and confirmed they do not contain the same issue;
        no changes were required.
      
      ### Impact
      Users now see the “session expired” notification exactly once, removing
      confusion and improving the overall UX.
      t0ng7u committed
    • 🐛 fix(auth): restore proper state & context destructuring in Login- and Register-forms · dabd9a9a
      Why
      Clicking the “Continue” button on the login page no longer triggered the submission logic. The issue was introduced when `useState`/`useContext` hooks were destructured incorrectly, breaking the setter reference and omitting required values.
      
      What’s changed
      • **LoginForm.js**
        – Re-added setter in `useSearchParams` (`[searchParams, setSearchParams]`).
        – Corrected order of destructuring for `inputs` so `username`/`password` are available after hooks.
        – Switched `useContext` to `[userState, userDispatch]` for consistency.
      
      • **RegisterForm.js**
        – Adopted `[userState, userDispatch]` from `UserContext` to mirror LoginForm and retain full state access.
      
      Outcome
      Login button now successfully invokes `handleSubmit`, and both auth components have consistent, fully-featured hook destructuring, preventing runtime errors and ensuring future state usage is straightforward.
      t0ng7u committed
    • 💫 feat(ui): introduce dispersed blur-ball background to all auth views · 06b7b595
      This commit refreshes the visual design of the authentication pages and aligns them with the Home banner style.
      
      Details
      • LoginForm.js / RegisterForm.js / PasswordResetForm.js / PasswordResetConfirm.js
        – Wrap top-level container with `relative overflow-hidden` to provide a positioning context.
        – Inject two decorative blur balls:
          ▸ Indigo ball on the top-right (`blur-ball-indigo`).
          ▸ Teal ball on the middle-left (`blur-ball-teal`).
        – Disabled the default X-axis transform on the indigo ball to keep the ball anchored to the corner.
        – Removed redundant `mt-[64px]` from the outer container and shifted it to the inner wrapper to maintain vertical rhythm without affecting the background placement.
      
      Result
      The auth screens now feature subtle, non-intrusive atmospheric gradients in the top-right and mid-left corners, offering a cohesive look & feel across the application without obstructing the main content.
      t0ng7u committed
    • 🐛 fix(auth): prevent initial render flicker & clean up state usage · 8fb5cb66
      • LoginForm / RegisterForm now initialise `status` directly from localStorage,
        avoiding a post-mount state update that caused a UI flash between OAuth
        options and email/username forms.
      
      • Move Turnstile configuration into a dedicated effect that depends on
        `status`, ensuring setState is not called during rendering.
      
      • Remove unused `setStatus` setter to resolve ESLint “declared but never read”
        warnings.
      
      • Minor refactors: reorder hooks, de-duplicate navigate/context variables and
        streamline state destructuring for improved readability.
      t0ng7u committed
    • 🔧 fix(xinference): update Document type to 'any' for flexibility · 038202b1
      - Changed the type of `Document` in `XinRerankResponseDocument` from `string` to `any` to accommodate various data types.
      - Updated the `RerankHandler` to handle `Document` as `any`, ensuring proper assignment based on its actual type.
      
      These modifications enhance the handling of document data, allowing for greater versatility in response structures.
      CaIon committed
    • 🎨 style(ui): refactor Tabs in ModelPricing to use native Semi UI styling · 6d2f34a8
      • Removed the custom `renderArrow` helper and its `Dropdown`-based arrow navigation, simplifying the component logic.
      • Switched the `<Tabs>` component to rely on Semi UI’s built-in behaviour (no more `renderArrow` override).
      • Kept `type="card"` and `collapsible` props for consistent visual appearance while still using the default style.
      • Eliminated the now-unused `Dropdown` import.
      
      This cleanup reduces bespoke UI code, makes future maintenance easier, and keeps the interface consistent with the rest of the application.
      t0ng7u committed
    • feat(homepage): enhance banner visuals & UX · 70a4b576
      • Added read-only Base URL input that shows `status.server_address` (fallback `window.location.origin`) and copies value on click.
      • Embedded `ScrollList` as input `suffix`; auto-cycles common endpoints every 3 s and allows manual selection.
      • Introduced `API_ENDPOINTS` array in `web/src/constants/common.constant.js` for centralized endpoint management.
      • Implemented custom CSS to hide ScrollList wheel indicators / scrollbars for a cleaner look.
      • Created two blurred colour spheres behind the banner (`blur-ball-indigo`, `blur-ball-teal`) with light-/dark-mode opacity tweaks and lower vertical placement.
      • Increased letter-spacing for Chinese heading via conditional `tracking-wide` / `md:tracking-wider` classes to improve readability.
      • Misc: updated imports, helper functions, and responsive sizes to keep UI consistent across devices.
      t0ng7u committed
  4. 24 Jun, 2025 6 commits
    • 🚀 feat(auth): support new model API paths in authentication and routing · 04d525e3
      - Updated TokenAuth middleware to handle requests for both `/v1beta/models/` and `/v1/models/`.
      - Adjusted distributor middleware to recognize the new model path.
      - Enhanced relay mode determination to include the new model path.
      - Added route for handling POST requests to `/models/*path`.
      
      These changes ensure compatibility with the new model API structure, improving the overall routing and authentication flow.
      CaIon committed
    • 🔧 style(ui): Inline tag edit action in ChannelsTable · 87e90e52
      • Removed the dropdown menu previously used for tag-level operations.
      • Added a standalone “Edit” button directly after the “Disable All” button, reducing the number of clicks required to edit a tag group.
      • Deleted the now-unused `IconEdit` import and its icon reference.
      
      This streamlines the tag management flow and keeps the UI cleaner and more accessible.
      t0ng7u committed
    • 🎨 style(channels-table): standardize operation component size to `small` · 7a4c213b
      All operation-related UI controls in `ChannelsTable` (buttons, dropdowns,
      switches, inputs, tags, etc.) now explicitly use `size="small"`.
      
      Reasons & benefits:
      - Creates a more compact and consistent look across the table and modals.
      - Improves visual coherence between desktop and mobile views.
      - Purely presentational; no functional logic is affected.
      
      No database changes or API interactions are involved.
      t0ng7u committed
    • 🚀 feat: enhance model testing UI with bulk selection, copy & success-filter buttons (#1288) · 610853e9
      * ChannelsTable
        - Added row-level checkboxes to the model-testing table for multi-selection
        - Implemented cross-page “Select All / Deselect All” via rowSelection.onSelectAll
        - Introduced allSelectingRef to ignore redundant onChange after onSelectAll
        - Added “Copy Selected” button to copy chosen model names (comma-separated) using helpers.copy
        - Added “Select Successful” button to auto-tick all models that passed testing
        - Moved search bar and new action buttons into the modal title for better UX
        - Centralised page size constant MODEL_TABLE_PAGE_SIZE in channel.constants.js
        - Fixed pagination slicing and auto-page-switch logic during batch testing
      
      * channel.constants
        - Exported MODEL_TABLE_PAGE_SIZE (default 10) for unified pagination control
      
      This commit enables users to conveniently copy or filter successful models, fully supports cross-page bulk operations, and resolves previous selection inconsistencies.
      
      Refs: #1288
      t0ng7u committed
  5. 23 Jun, 2025 5 commits
    • fix: ensure table shows correct loading state on first render & during search · 62daf16b
      Frontend (`ChannelsTable.js`)
      1. Initialize `loading` state to `true` so the spinner is visible while the first data request is in-flight.
      2. Set `<Table>` prop `loading={loading || searching}` — the spinner now appears for both the initial load and any subsequent search requests.
      
      Result
      Users immediately see a loading indicator on page entry and whenever a search is running, improving perceived responsiveness.
      t0ng7u committed
    • 🚀 feat: Align search API with channel listing & fix sorting toggle · d19ab54e
      1. Backend
         • `controller/channel.go`
           – Added pagination (`p`, `page_size`) support to `SearchChannels`.
           – Added independent `type` filter (keeps `type_counts` unaffected).
           – Returned `total`, `type_counts` to match `/api/channel/` response.
      
      2. Frontend
         • `ChannelsTable.js`
           – `loadChannels` / `searchChannels` now pass `p`, `page_size`, `id_sort`, `type`, `status` correctly.
           – Pagination, page-size selector and type tabs work for both normal list and search mode.
           – Switch for “ID sort” calls proper API and keeps UI state in sync.
           – Removed unnecessary `normalize` helper; `getFormValues` back to concise form.
      
      Result
      • Search mode and normal listing now share identical pagination and filtering behavior.
      • Type tabs show correct counts even after searching.
      • “ID Sort” toggle no longer inverses actual behaviour.
      t0ng7u committed
    • fix(channels-table): preserve group filter when switching type or status tabs · 8f0f0c0d
      Refactors `ChannelsTable.js` to ensure that the selected group filter is **never lost** when:
      
      1. Cycling between channel-type tabs.
      2. Changing the status dropdown (all / enabled / disabled).
      
      Key points:
      
      • `loadChannels` now detects active search filters (keyword / group / model) and transparently delegates to `searchChannels`, guaranteeing all parameters are sent in every request.
      • `searchChannels` accepts optional `typeKey` and `statusF` arguments, enabling reuse without code duplication.
      • Loading state handling is unified; no extra renders or side effects were introduced, keeping UI performance intact.
      • Duplicate logic removed and responsibilities clearly separated for easier future maintenance.
      t0ng7u committed
    • Revert "🐛 fix: preserve group filter when switching channel type/status" · 9bf32ef5
      This reverts commit 4949d986.
      t0ng7u committed
    • 💄 i18n: shorten channel search placeholder and update i18n · 9469c497
      Replaced the verbose placeholder “Search channel ID, name, key and API address ...”
      with a concise version “Channel ID, name, key, API address” in
      `ChannelsTable.js` and synchronized the corresponding i18n entries.
      
      This improves readability and keeps UI text consistent across languages.
      t0ng7u committed