Commit Graph

1170 Commits

Author SHA1 Message Date
IcedTangerine
34aca14858 Merge pull request #1309 from feitianbubu/pr/alpha/video-action-constant2
feat: video action to constant
2025-07-02 15:50:23 +08:00
CaIon
4322037639 🐛 fix: correct validation logic for redemption name input in EditRedemption component 2025-07-02 10:28:57 +08:00
skynono
6bd2316d9c feat: jimeng apiKey format to use | delimiter 2025-07-01 10:35:29 +08:00
同語
9b8b982d8a 🐛 fix: ratelimit style error
Merge pull request #1301 from tbphp/fix_ratelimit_style
2025-06-29 02:34:06 +08:00
t0ng7u
e6949e611a style: change the border radius of most components from full to lg size 2025-06-29 02:32:09 +08:00
t0ng7u
cffade7210 🤯style: remove useless card headerStyle 2025-06-29 00:11:15 +08:00
skynono
59a1f4c900 feat: video action to constant 2025-06-27 23:19:34 +08:00
skynono
05ea0dd54f feat: add video channel jimeng 2025-06-27 17:08:20 +08:00
Xyfacai
2171117c53 Merge pull request #1291 from feitianbubu/pr/add-origin-kling-api
feat: add origin kling api
2025-06-27 16:08:03 +08:00
t0ng7u
3ced5ff144 chore: Improve channel creation UX: defer "Fetch Model List" action until after creation
Previously, the "Fetch Model List" button was visible in the channel-creation view even though
it only functions once a channel record exists, leading to user confusion.

Changes introduced:
• Render the "Fetch Model List" button only when editing an existing channel (`isEdit === true`).
• Display an informational Banner in creation mode to remind users that the upstream model list
  can be fetched after the channel has been created.
• Refactored JSX to apply the above conditional rendering without altering existing logic.

This update streamlines the creation workflow and sets clearer expectations for users.
2025-06-27 10:08:44 +08:00
t0ng7u
38d3ab5acf 💄refactor: enhance EditUser and AddUser form validation & UX
Changes in `web/src/pages/User/EditUser.js`:
• Added `rules` to
  – `Form.Select group`: now required with error “Please select group”.
  – `Form.InputNumber quota`: now required with error “Please enter quota”.
• Added `step={500000}` to quota `InputNumber` for quicker numeric input.
• Replaced invalid `readonly` with React-correct `readOnly`, and added descriptive placeholders for all binding-info fields (GitHub/OIDC/WeChat/Email/Telegram).
• Removed unused `downloadTextAsFile` import.

These updates tighten form validation, improve data entry ergonomics, and restore clear read-only indicators for third-party bindings.
2025-06-27 09:44:18 +08:00
t0ng7u
ab32e15a86 🐛 fix(redemptions-table): correct initial page index and pagination state
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.
2025-06-27 07:42:04 +08:00
t0ng7u
25e17b95d5 🐛 fix(redemptions-table): show loading indicator while refetching data
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.
2025-06-27 07:29:28 +08:00
t0ng7u
d07224e658 🎁 refactor(ui/redemption): migrate EditRedemption page to Semi Form & enhance UX
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.
2025-06-27 07:25:46 +08:00
t0ng7u
aa15d45a3d refactor(ui/token): migrate EditToken page to Semi Form API and polish UX
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.
2025-06-26 22:58:25 +08:00
tbphp
c6c68da0b5 fix: ratelimit style error 2025-06-26 21:32:05 +08:00
t0ng7u
1a0aac81df 🎨 style: remove all prefix icons to simplify the layout of the sidesheet component 2025-06-26 16:36:36 +08:00
t0ng7u
39cb45c11c 🎨 style: unify card header UI, switch to Avatar icons & remove oversized props
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.
2025-06-26 16:05:13 +08:00
t0ng7u
05d9aa53ef 🔒 style: Hide registration link when Self-Use Mode is enabled
• 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
2025-06-26 04:29:44 +08:00
t0ng7u
86f374df58 🐛 fix(auth): prevent duplicate “session expired” toast on login
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.
2025-06-26 03:51:19 +08:00
t0ng7u
6935260bf0 🧶style(TokensTable): add IconDelete in Delete selected token button 2025-06-25 23:23:59 +08:00
t0ng7u
f0d888729b 🐛 fix(auth): restore proper state & context destructuring in Login- and Register-forms
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.
2025-06-25 23:13:55 +08:00
t0ng7u
6d7d4292ef 💫 feat(ui): introduce dispersed blur-ball background to all auth views
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.
2025-06-25 22:57:04 +08:00
t0ng7u
fcefac9dbe 🐛 fix(auth): prevent initial render flicker & clean up state usage
• 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.
2025-06-25 22:46:11 +08:00
t0ng7u
ad5f731b20 🍭style: add mt-[64px] in class auth componets 2025-06-25 22:21:14 +08:00
t0ng7u
5a6f32c392 🎨 style(ui): refactor Tabs in ModelPricing to use native Semi UI styling
• 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.
2025-06-25 15:40:27 +08:00
t0ng7u
29a44eb7ae feat(homepage): enhance banner visuals & UX
• 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.
2025-06-25 15:26:51 +08:00
t0ng7u
277645db50 🔧 style(ui): Inline tag edit action in ChannelsTable
• 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.
2025-06-24 18:09:16 +08:00
t0ng7u
0c5d4ca0a7 🎨 style(channels-table): standardize operation component size to small
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.
2025-06-24 18:02:34 +08:00
t0ng7u
44495b153a 🚀 feat: enhance model testing UI with bulk selection, copy & success-filter buttons (#1288)
* 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
2025-06-24 17:46:08 +08:00
t0ng7u
de6e551cdb fix: ensure table shows correct loading state on first render & during search
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.
2025-06-24 05:20:54 +08:00
t0ng7u
aeb393e391 🚀 feat: Align search API with channel listing & fix sorting toggle
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.
2025-06-24 05:13:47 +08:00
t0ng7u
db1b11deaf fix(channels-table): preserve group filter when switching type or status tabs
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.
2025-06-24 04:16:40 +08:00
t0ng7u
5a5e8ce652 Revert "🐛 fix: preserve group filter when switching channel type/status"
This reverts commit a8ba2eba33.
2025-06-24 01:51:26 +08:00
t0ng7u
6c31151430 💄 i18n: shorten channel search placeholder and update i18n
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.
2025-06-24 01:48:39 +08:00
t0ng7u
a8ba2eba33 🐛 fix: preserve group filter when switching channel type/status
Ensure that the selected "group" filter (and other form search values) persist across
type tab changes, status filter updates, pagination, and page-size changes.

Changes include:
• loadChannels: added `searchParams` argument and now appends keyword, group and model
  query strings to API calls.
• refresh / page handlers / type tabs / status Select: now pass current form values
  to loadChannels, keeping filters intact.
• searchChannels: maintains active type and status filters when issuing search requests.
• Form.Select (searchGroup): triggers loadChannels when only group filter is active,
  preventing parameter loss.
• Minor cleanup and comment adjustments.
2025-06-24 01:45:22 +08:00
t0ng7u
c974b1053c 🐛 fix(channel): remove duplicate model names in “Edit Channel” model dropdown (#1292)
• Unify the Select option structure as `{ key, label, value }`; add missing `key` to prevent duplicated rendering by Semi-UI.
• Trim and deduplicate the `models` array via `Set` inside `handleInputChange`, ensuring state always contains unique values.
• In the options-merging `useEffect`, use a `Map` keyed by `value` (after `trim`) to guarantee a unique `optionList` when combining backend data with currently selected models.
• Apply the same structure and de-duplication when:
  – Fetching models from `/api/channel/models`
  – Adding custom models (`addCustomModels`)
  – Fetching upstream model lists (`fetchUpstreamModelList`)
• Replace obsolete `text` field with `label` in custom option objects for consistency.

No backend changes are required; the fix is entirely front-end.

Closes #1292
2025-06-24 00:25:29 +08:00
t0ng7u
1ab75b8a92 🎨 feat(EditChannel): improve model selection UX, clipboard feedback & rounded styling (#1290)
* Added a dedicated effect to merge origin and selected models, ensuring selected items always remain in the dropdown list.
* Enhanced “Copy all models” button:
  * Shows info message when list is empty.
  * Displays success / error notification based on copy result.
* Unified UI look-and-feel by applying `!rounded-lg` class to inputs, selects, banners and buttons.
* i18n: added English translations for new prompts
  - "No models to copy"
  - "Model list copied to clipboard"
  - "Copy failed"
2025-06-24 00:02:22 +08:00
同語
75e3959474 🧬merge: Add a button to copy the selected model in the channel (#1290)
Merge pull request #1290 from JoeyLearnsToCode/feat-copy-models
2025-06-23 23:46:54 +08:00
t0ng7u
bc371778b6 🚀 feat: add enabled/disabled channel filtering & optimize type-based pagination (#1289)
WHAT’S NEW
• Backend
  – Introduced `parseStatusFilter` helper to normalize `status` query across handlers.
  – `GET /api/channel` & `GET /api/channel/search` now accept `status=enabled|disabled` to return only enabled or disabled channels.
  – Tag-mode branch respects both `statusFilter` and `typeFilter`; SQL paths trimmed to one query + one lightweight `GROUP BY` for `type_counts`.

• Frontend (`ChannelsTable.js`)
  – Added “Status Filter” `<Select>` (All / Enabled / Disabled) with localStorage persistence.
  – All data-loading and search requests now always append `type` (when not “all”) and `status` params, so filtering & pagination are handled entirely server-side.
  – Removed client-side post-filtering for type, preventing short pages and reducing CPU work.
  – Tabs’ type counts stay in sync via backend-provided `type_counts`.

IMPROVEMENTS
• Eliminated duplicated status-parsing logic; single source of truth eases future extension.
• Reduced redundant queries, improved consistency of counts in UI.
• Secured key leakage with `Omit("key")` unchanged; no perf regressions observed.

Closes #1289
2025-06-23 23:40:34 +08:00
skynono
cd2870aebc feat: add origin kling api 2025-06-23 22:36:23 +08:00
t0ng7u
2591ca3d60 🚀 chore(ui): Refactor UpstreamRatioSync with conflict-modal component, performance hooks & cleanup (#1286)
WHAT’S NEW
• Extracted reusable ConflictConfirmModal for clearer JSX hierarchy
• Added detailed conflict detection & confirmation flow before syncing options
• Refactored state-heavy callbacks (`selectValue`, `performSync`) with `useCallback` to avoid unnecessary renders
• Introduced build-time constants (later removed unused export) and unified helper utilities
• Ensured final ratios are rebuilt accurately before API `PUT`, fixing “value not updated” bug
• Enhanced UI hints: warning icon on conflict, multiline billing info, mobile-friendly modal size
• General code cleanup: removed dead variables, adopted early returns, improved comments

WHY
Improves maintainability, user clarity when billing-type collisions occur, and guarantees data consistency after synchronisation.
2025-06-23 17:35:39 +08:00
t0ng7u
c28190316f 🐛 fix(ratio-sync): reset pagination when filter/search changes
Add a `useEffect` hook in `UpstreamRatioSync.js` to automatically set
`currentPage` to `1` whenever `ratioTypeFilter` or `searchKeyword`
updates.
This prevents the table from appearing empty when users switch to the
“model_price” (fixed price) filter or perform a new search while on a
later page.

Additional changes:
- Import `useEffect` from React.

This enhancement delivers a smoother UX by ensuring the first page of
results is always shown after any filtering action.
2025-06-23 16:34:00 +08:00
JoeyLearnsToCode
ffc22b8dac Merge branch 'main' into feat-copy-models 2025-06-23 16:12:18 +08:00
t0ng7u
5367015a31 🎛️ feat(web): add “Conflict Rates” filter & highlight in Model Settings Visual Editor (#1286)
Introduce the ability to quickly locate models with conflicting billing configurations.

Key points
• Added `hasConflict` flag to detect models that define both a fixed price (`ModelPrice`) and any ratio (`ModelRatio` or `CompletionRatio`).
• Added “Show Only Conflict Rates” `Checkbox` to toolbar; filtering logic now supports keyword + conflict filtering.
• Display a red `Tag` beside the model name when a conflict is detected for immediate visual feedback.
• Kept `hasConflict` state in sync during add, update and delete operations.
• Imported `Checkbox` and `Tag` from **@douyinfe/semi-ui**.
• Minor UI tweaks (circle tag style, margin) for consistency.

This enhancement helps administrators swiftly identify and resolve incompatible pricing rules, addressing the need discussed in issue #1286.
2025-06-23 15:55:10 +08:00
t0ng7u
6192aebe66 🍭style: update home main title style font-semibold to font-bold 2025-06-22 18:28:32 +08:00
t0ng7u
014c9450ba feat(ui): Implement unified compact/adaptive table mode + icon refinement
Summary
• Added per-table “Compact / Adaptive” view toggle to all major table components (Tokens, Channels, Logs, MjLogs, TaskLogs, Redemptions, Users).
• Persist user preference in a single localStorage entry (`table_compact_modes`) instead of scattered keys.

Details
1. utils.js
   • Re-implemented `getTableCompactMode` / `setTableCompactMode` to read & write a shared JSON object.
   • Imported storage-key constant from `constants`.

2. hooks/useTableCompactMode.js
   • Hook now consumes the unified helpers and listens to `storage` events via the shared key constant.

3. constants
   • Added `TABLE_COMPACT_MODES_KEY` to `common.constant.js` and re-exported via `constants/index.js`.

4. Table components
   • Integrated `useTableCompactMode('<tableName>')`.
   • Dynamically remove `fixed: 'right'` column and horizontal `scroll` when in compact mode.
   • UI: toggle button placed at card title’s right; responsive layout on small screens.

5. UI polish
   • Replaced all lucide-react `List`/`ListIcon` usages with Semi UI `IconDescend` for consistency.
   • Restored correct icons where `Hash` was intended (TaskLogsTable).

Benefits
• Consistent UX for switching list density across the app.
• Cleaner localStorage footprint with easier future maintenance.
2025-06-22 18:10:00 +08:00
t0ng7u
d7c97d4d34 feat(tokens-table): add selectable copy modes for bulk token copy action
This commit enhances the “Copy Selected Tokens to Clipboard” feature in `TokensTable.js` by introducing a user-friendly modal that lets users choose how they want to copy tokens.

Changes made
• Replaced direct copy logic with a `Modal.info` dialog.
• Modal displays the prompt “Please choose your copy mode”.
• Added two buttons in a custom footer:
  – **Name + Secret**: copies `tokenName    sk-tokenKey`.
  – **Secret Only**: copies `sk-tokenKey`.
• Each button triggers the copy operation and closes the dialog.
• Maintains existing validations (e.g., selection check, clipboard feedback).

Benefits
• Gives users clear control over copy format, reducing manual editing.
• Aligns UI with Semi UI’s best practices via custom modal footer.

No backend/API changes are involved; all updates are limited to the front-end UI logic.
2025-06-22 16:49:44 +08:00
t0ng7u
dce794dbf7 Merge remote-tracking branch 'origin/alpha' into alpha 2025-06-22 16:39:52 +08:00
t0ng7u
093d86040f 🗑️ feat(token): implement batch token deletion API & front-end integration
• Back-end
  • model/token.go
    • Add `BatchDeleteTokens(ids []int, userId int)` – transactional DB removal + async Redis cache cleanup.
  • controller/token.go
    • Introduce `TokenBatch` DTO and `DeleteTokenBatch` handler calling the model layer; returns amount deleted.
  • router/api-router.go
    • Register `POST /api/token/batch` route (user-scoped).

• Front-end (TokensTable.js)
  • Replace per-token deletion loops with single request to `/api/token/batch`.
  • Display dynamic i18n message: “Deleted {{count}} tokens!”.
  • Add modal confirmation:
    • Title “Batch delete token”.
    • Content “Are you sure you want to delete the selected {{count}} tokens?”.
  • UI/UX tweaks
    • Responsive button group (flex-wrap, mobile line-break).
    • Clear `selectedKeys` after refresh / successful deletion to avoid ghost selections.

• i18n
  • Ensure placeholder style matches translation keys (`{{count}}`).

This commit delivers efficient, scalable token management and an improved user experience across devices.
2025-06-22 16:35:30 +08:00