Commit Graph

55 Commits

Author SHA1 Message Date
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
f3a1f98add 🐛 fix(models): eliminate vendor column flicker by loading vendors before models
Why:
• The vendor list API is separate from the models API, causing the “Vendor” column in `ModelsTable` to flash (rendering `'-'` first, then updating) after the table finishes loading.
• This visual jump degrades the user experience.

What:
• Updated `web/src/hooks/models/useModelsData.js`
  – In the initial `useEffect`, vendors are fetched first with `loadVendors()` and awaited.
  – Only after vendors are ready do we call `loadModels()`, ensuring `vendorMap` is populated before the table renders.

Outcome:
• The table now renders with complete vendor data on first paint, removing the flicker and providing a smoother UI.
2025-08-04 22:11:13 +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
ecdd9d1ccb feat: add multi-key management 2025-08-04 16:52:31 +08:00
t0ng7u
5e81ef4a44 ♻️ refactor(hooks/models): deduplicate useModelsData and optimize vendor-tab counts
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.
2025-08-01 02:39:12 +08:00
t0ng7u
232612898b 🔄 fix: improve vendor-tab filtering & counts, resolve SQL ambiguity, and reload data correctly
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.
2025-07-31 23:30:45 +08:00
t0ng7u
af59b61f8a 🚀 feat: Introduce full Model & Vendor Management suite (backend + frontend) and UI refinements
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.
2025-07-31 22:28:09 +08:00
t0ng7u
4cc76f2deb Merge branch 'alpha' into refactor/model-pricing 2025-07-27 09:51:35 +08:00
t0ng7u
0cb2bb2ea7 🗂️ refactor(table): isolate column preferences per role
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.
2025-07-27 09:49:57 +08:00
t0ng7u
75548c449b refactor: pricing filters for dynamic counting & cleaner logic
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.
2025-07-26 18:38:18 +08:00
t0ng7u
0b1a1ca064 refactor: Restructure model pricing components and improve UX consistency
- **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.
2025-07-26 04:24:22 +08:00
t0ng7u
52a9cee0e1 Merge branch 'alpha' into refactor/model-pricing 2025-07-25 20:33:14 +08:00
t0ng7u
fe16d05fbb 🔒 fix: Enforce admin-only column visibility in logs tables
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.
2025-07-25 20:31:20 +08:00
t0ng7u
1880164e29 ♻️ Refactor: Move token unit toggle from table header to filter settings
- 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)
2025-07-24 17:10:08 +08:00
t0ng7u
59a76b3970 feat: Add endpoint type filter to model pricing system
- 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.
2025-07-24 03:25:57 +08:00
t0ng7u
53be79a00e 💄 style(pricing): enhance card view UI and skeleton loading experience (#1365)
- 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.
2025-07-24 03:19:32 +08:00
t0ng7u
a044070e1d 🎨 feat(model-pricing): refactor layout and component structure (#1365)
* Re-architected model-pricing page into modular components:
  * PricingPage / PricingSidebar / PricingContent
  * Removed obsolete `ModelPricing*` components and column defs
* Introduced reusable `SelectableButtonGroup` in `common/ui`
  * Supports Row/Col grid (3 per row)
  * Optional collapsible mode with gradient mask & toggle
* Rebuilt filter panels with the new button-group:
  * Model categories, token groups, and quota types
  * Added dynamic `tagCount` badges to display item totals
* Extended `useModelPricingData` hook
  * Added `filterGroup` and `filterQuotaType` state and logic
* Updated PricingTable columns & sidebar reset logic to respect new states
* Ensured backward compatibility via re-export in `index.jsx`
* Polished styling, icons and i18n keys
2025-07-23 01:58:51 +08:00
t0ng7u
0c5c5823bf ♻️ refactor: restructure ModelPricing component into modular architecture
- Break down monolithic ModelPricing.js (685 lines) into focused components:
  * ModelPricingHeader.jsx - top status card with pricing information
  * ModelPricingTabs.jsx - model category navigation tabs
  * ModelPricingFilters.jsx - search and action controls
  * ModelPricingTable.jsx - data table with pricing details
  * ModelPricingColumnDefs.js - table column definitions and renderers

- Create custom hook useModelPricingData.js for centralized state management:
  * Consolidate all business logic and API calls
  * Manage pricing calculations and data transformations
  * Handle search, filtering, and UI interactions

- Follow project conventions matching other table components:
  * Adopt same file structure as channels/, users/, tokens/ modules
  * Maintain consistent naming patterns and component organization
  * Preserve all original functionality including responsive design

- Update import paths:
  * Remove obsolete ModelPricing.js file
  * Update Pricing page to use new ModelPricingPage component
  * Fix missing import references

Benefits:
- Improved maintainability with single-responsibility components
- Enhanced code reusability and testability
- Better team collaboration with modular structure
- Consistent codebase architecture across all table components
2025-07-22 12:08:35 +08:00
t0ng7u
0eaeef5723 📚 refactor(dashboard): modularize dashboard page into reusable hooks and components
## Overview
Refactored the monolithic dashboard page (~1200 lines) into a modular architecture following the project's global layout pattern. The main `Detail/index.js` is now simplified to match other page entry files like `Midjourney/index.js`.

## Changes Made

### 🏗️ Architecture Changes
- **Before**: Single large file `pages/Detail/index.js` containing all dashboard logic
- **After**: Modular structure with dedicated hooks, components, and helpers

### 📁 New Files Created
- `hooks/dashboard/useDashboardData.js` - Core data management and API calls
- `hooks/dashboard/useDashboardStats.js` - Statistics computation and memoization
- `hooks/dashboard/useDashboardCharts.js` - Chart specifications and data processing
- `constants/dashboard.constants.js` - UI config, time options, and chart defaults
- `helpers/dashboard.js` - Utility functions for data processing and UI helpers
- `components/dashboard/index.jsx` - Main dashboard component integrating all modules
- `components/dashboard/modals/SearchModal.jsx` - Search modal component

### 🔧 Updated Files
- `constants/index.js` - Added dashboard constants export
- `helpers/index.js` - Added dashboard helpers export
- `pages/Detail/index.js` - Simplified to minimal wrapper (~20 lines)

### 🐛 Bug Fixes
- Fixed SearchModal DatePicker onChange to properly convert Date objects to timestamp strings
- Added missing localStorage update for `data_export_default_time` persistence
- Corrected data flow between search confirmation and chart updates
- Ensured proper chart data refresh after search parameter changes

###  Key Improvements
- **Separation of Concerns**: Data, stats, and charts logic isolated into dedicated hooks
- **Reusability**: Components and hooks can be easily reused across the application
- **Maintainability**: Smaller, focused files easier to understand and modify
- **Consistency**: Follows established project patterns for global folder organization
- **Performance**: Proper memoization and callback optimization maintained

### 🎯 Functional Verification
-  All dashboard panels (model analysis, resource consumption, performance metrics) update correctly
-  Search functionality works with proper parameter validation
-  Chart data refreshes properly after search/filter operations
-  User interface remains identical to original implementation
-  All existing features preserved without regression

### 🔄 Data Flow
```
User Input → SearchModal → useDashboardData → API Call → useDashboardCharts → UI Update
```

## Breaking Changes
None. All existing functionality preserved.

## Migration Notes
The refactored dashboard maintains 100% API compatibility and identical user experience while providing a cleaner, more maintainable codebase structure.
2025-07-20 15:47:02 +08:00
t0ng7u
4d7562fd79 🐛 fix(ui): prevent pagination flicker when tables have no data
Fix pagination component flickering issue across multiple table views
by initializing count states to 0 instead of ITEMS_PER_PAGE. This
prevents the pagination component from briefly appearing and then
disappearing when tables are empty.

Changes:
- usage-logs: logCount initial value 0 (was ITEMS_PER_PAGE)
- users: userCount initial value 0 (was ITEMS_PER_PAGE)
- tokens: tokenCount initial value 0 (was ITEMS_PER_PAGE)
- channels: channelCount initial value 0 (was ITEMS_PER_PAGE)
- redemptions: tokenCount initial value 0 (was ITEMS_PER_PAGE)

The createCardProPagination function already handles total <= 0 by
returning null, so this ensures consistent behavior across all table
components and improves user experience by eliminating visual flicker.

Affected files:
- web/src/hooks/usage-logs/useUsageLogsData.js
- web/src/hooks/users/useUsersData.js
- web/src/hooks/tokens/useTokensData.js
- web/src/hooks/channels/useChannelsData.js
- web/src/hooks/redemptions/useRedemptionsData.js
2025-07-20 12:36:38 +08:00
t0ng7u
252fddf3de 🚀 feat: Enhance table UX & fix reset actions across Users / Tokens / Redemptions
Users table (UsersColumnDefs.js)
• Merged “Status” into the “Statistics” tag: unified text-color logic, removed duplicate renderStatus / renderOverallStatus helpers.
• Switch now disabled for deleted users.
• Replaced dropdown “More” menu with explicit action buttons (Edit / Promote / Demote / Delete) and set column width to 200 px.
• Deleted unused Dropdown & IconMore imports and tidied redundant code.

Users filters & hooks
• UsersFilters.jsx – store formApi in a ref; reset button clears form then reloads data after 100 ms.
• useUsersData.js – call setLoading(true) at the start of loadUsers so the Query button shows loading on reset / reload.

TokensFilters.jsx & RedemptionsFilters.jsx
• Same ref-based reset pattern with 100 ms debounce to restore working “Reset” buttons.

Other clean-ups
• Removed repeated status strings and unused helper functions.
• Updated import lists to reflect component changes.

Result
– Reset buttons now reliably clear filters and reload data with proper loading feedback.
– Users table shows concise status information and all operation buttons without extra clicks.
2025-07-20 01:21:06 +08:00
t0ng7u
39079e7aff 💄 refactor: Users table UI & state handling
Summary of changes
1. UI clean-up
   • Removed all `prefixIcon` props from `Tag` components in `UsersColumnDefs.js`.
   • Corrected i18n string in invite info (`${t('邀请人')}: …`).

2. “Statistics” column overhaul
   • Added a Switch (enable / disable) and quota Progress bar, mirroring the Tokens table design.
   • Moved enable / disable action out of the “More” dropdown; user status is now toggled directly via the Switch.
   • Disabled the Switch for deleted (注销) users.
   • Restored column title to “Statistics” to avoid duplication.

3. State consistency / refresh
   • Updated `manageUser` in `useUsersData.js` to:
     – set `loading` while processing actions;
     – update users list immutably (new objects & array) to trigger React re-render.

4. Imports / plumbing
   • Added `Progress` and `Switch` to UI imports in `UsersColumnDefs.js`.

These changes streamline the user table’s appearance, align interaction patterns with the token table, and ensure immediate visual feedback after user status changes.
2025-07-20 01:00:53 +08:00
t0ng7u
38e72e1af7 🎨 chore: integrate ESLint header automation with AGPL-3.0 notice
• Added `.eslintrc.cjs`
  - Enables `header` + `react-hooks` plugins
  - Inserts standardized AGPL-3.0 license banner for © 2025 QuantumNous
  - JS/JSX parsing & JSX support configured

• Installed dev-deps: `eslint`, `eslint-plugin-header`, `eslint-plugin-react-hooks`

• Updated `web/package.json` scripts
  - `eslint` → lint with cache
  - `eslint:fix` → auto-insert/repair license headers

• Executed `eslint --fix` to prepend license banner to all JS/JSX files

• Ignored runtime cache
  - Added `.eslintcache` to `.gitignore` & `.dockerignore`

Result: consistent AGPL-3.0 license headers, reproducible linting across local dev & CI.
2025-07-19 03:30:44 +08:00
t0ng7u
d762da9141 ♻️ refactor(users): modularize UsersTable component into microcomponent architecture
BREAKING CHANGE: Removed standalone user edit routes (/console/user/edit, /console/user/edit/:id)

- Decompose 673-line monolithic UsersTable.js into 8 specialized components
- Extract column definitions to UsersColumnDefs.js with render functions
- Create dedicated UsersActions.jsx for action buttons
- Create UsersFilters.jsx for search and filtering logic
- Create UsersDescription.jsx for description area
- Extract all data management logic to useUsersData.js hook
- Move AddUser.js and EditUser.js to users/modals/ folder as modal components
- Create 4 new confirmation modal components (Promote, Demote, EnableDisable, Delete)
- Implement pure UsersTable.jsx component for table rendering only
- Create main container component users/index.jsx to compose all subcomponents
- Update import paths in pages/User/index.js to use new modular structure
- Remove obsolete EditUser imports and routes from App.js
- Delete original monolithic files: UsersTable.js, AddUser.js, EditUser.js

The new architecture follows the same modular pattern as tokens and redemptions modules:
- Consistent file organization across all table modules
- Better separation of concerns and maintainability
- Enhanced reusability and testability
- Unified modal management approach

All existing functionality preserved with improved code organization.
2025-07-19 00:32:56 +08:00
t0ng7u
c05d6f7cdf ♻️ refactor(components): restructure RedemptionsTable to modular architecture
Refactor the monolithic RedemptionsTable component (614 lines) into a clean,
modular structure following the established tokens component pattern.

### Changes Made:

**New Components:**
- `RedemptionsColumnDefs.js` - Extract table column definitions and render logic
- `RedemptionsActions.jsx` - Extract action buttons (add, batch copy, clear invalid)
- `RedemptionsFilters.jsx` - Extract search and filter form components
- `RedemptionsDescription.jsx` - Extract description area component
- `redemptions/index.jsx` - Main container component managing state and composition

**New Hook:**
- `useRedemptionsData.js` - Extract all data management, CRUD operations, and business logic

**New Constants:**
- `redemption.constants.js` - Extract redemption status, actions, and form constants

**Architecture Changes:**
- Transform RedemptionsTable.jsx into pure table rendering component
- Move state management and component composition to index.jsx
- Implement consistent prop drilling pattern matching tokens module
- Add memoization for performance optimization
- Centralize translation function distribution

### Benefits:
- **Maintainability**: Each component has single responsibility
- **Reusability**: Components and hooks can be used elsewhere
- **Testability**: Individual modules can be unit tested
- **Team Collaboration**: Multiple developers can work on different modules
- **Consistency**: Follows established architectural patterns

### File Structure:
```
redemptions/
├── index.jsx                    # Main container (state + composition)
├── RedemptionsTable.jsx        # Pure table component
├── RedemptionsActions.jsx      # Action buttons
├── RedemptionsFilters.jsx      # Search/filter form
├── RedemptionsDescription.jsx  # Description area
└── RedemptionsColumnDefs.js    # Column definitions
2025-07-19 00:12:04 +08:00
t0ng7u
42a26f076a ♻️ refactor: modularize TokensTable component into maintainable architecture
- Split monolithic 922-line TokensTable.js into modular components:
  * useTokensData.js: Custom hook for centralized state and logic management
  * TokensColumnDefs.js: Column definitions and rendering functions
  * TokensTable.jsx: Pure table component for rendering
  * TokensActions.jsx: Actions area (add, copy, delete tokens)
  * TokensFilters.jsx: Search form component with keyword and token filters
  * TokensDescription.jsx: Description area with compact mode toggle
  * index.jsx: Main orchestrator component

- Features preserved:
  * Token status management with switch controls
  * Quota progress bars and visual indicators
  * Model limitations display with vendor avatars
  * IP restrictions handling and display
  * Chat integrations with dropdown menu
  * Batch operations (copy, delete) with confirmations
  * Key visibility toggle and copy functionality
  * Compact mode for responsive layouts
  * Search and filtering capabilities
  * Pagination and loading states

- Improvements:
  * Better separation of concerns
  * Enhanced reusability and testability
  * Simplified maintenance and debugging
  * Consistent modular architecture pattern
  * Performance optimizations with useMemo
  * Backward compatibility maintained

This refactoring follows the same successful pattern used for LogsTable, MjLogsTable, and TaskLogsTable, significantly improving code maintainability while preserving all existing functionality.
2025-07-18 22:56:34 +08:00
t0ng7u
3b67759730 ♻️ refactor: restructure TaskLogsTable into modular component architecture
Refactor the monolithic TaskLogsTable component (802 lines) into a modular,
maintainable architecture following the established pattern from LogsTable
and MjLogsTable refactors.

## What Changed

### 🏗️ Architecture
- Split large single file into focused, single-responsibility components
- Introduced custom hook `useTaskLogsData` for centralized state management
- Created dedicated column definitions file for better organization
- Implemented modal components for user interactions

### 📁 New Structure
```
web/src/components/table/task-logs/
├── index.jsx                       # Main page component orchestrator
├── TaskLogsTable.jsx              # Pure table rendering component
├── TaskLogsActions.jsx            # Actions area (task records + compact mode)
├── TaskLogsFilters.jsx            # Search form component
├── TaskLogsColumnDefs.js          # Column definitions and renderers
└── modals/
    ├── ColumnSelectorModal.jsx    # Column visibility settings
    └── ContentModal.jsx           # Content viewer for JSON data

web/src/hooks/task-logs/
└── useTaskLogsData.js             # Custom hook for state & logic
```

### 🎯 Key Improvements
- **Maintainability**: Clear separation of concerns, easier to understand
- **Reusability**: Modular components can be reused independently
- **Performance**: Optimized with `useMemo` for column rendering
- **Testing**: Single-responsibility components easier to test
- **Developer Experience**: Better code organization and readability

### 🎨 Task-Specific Features Preserved
- All task type rendering with icons (MUSIC, LYRICS, video generation)
- Platform-specific rendering (Suno, Kling, Jimeng) with distinct colors
- Progress indicators for task completion status
- Video preview links for successful video generation tasks
- Admin-only columns for channel information
- Status rendering with appropriate colors and icons

### 🔧 Technical Details
- Centralized all business logic in `useTaskLogsData` custom hook
- Extracted comprehensive column definitions with Lucide React icons
- Split complex UI into focused components (table, actions, filters, modals)
- Maintained responsive design patterns for mobile compatibility
- Preserved admin permission handling for restricted features
- Optimized spacing and layout (reduced gap from 4 to 2 for better density)

### 🎮 Platform Support
- **Suno**: Music and lyrics generation with music icons
- **Kling**: Video generation with video icons
- **Jimeng**: Video generation with distinct purple styling

### 🐛 Fixes
- Improved component prop passing patterns
- Enhanced type safety through better state management
- Optimized rendering performance with proper memoization
- Streamlined export pattern using `export { default }`

## Breaking Changes
None - all existing imports and functionality preserved.
2025-07-18 22:33:05 +08:00
t0ng7u
5407a8345f ♻️ refactor: restructure MjLogsTable into modular component architecture
Refactor the monolithic MjLogsTable component (971 lines) into a modular,
maintainable architecture following the same pattern as LogsTable refactor.

## What Changed

### 🏗️ Architecture
- Split large single file into focused, single-responsibility components
- Introduced custom hook `useMjLogsData` for centralized state management
- Created dedicated column definitions file for better organization
- Implemented specialized modal components for Midjourney-specific features

### 📁 New Structure
```
web/src/components/table/mj-logs/
├── index.jsx                    # Main page component orchestrator
├── MjLogsTable.jsx             # Pure table rendering component
├── MjLogsActions.jsx           # Actions area (banner + compact mode)
├── MjLogsFilters.jsx           # Search form component
├── MjLogsColumnDefs.js         # Column definitions and renderers
└── modals/
    ├── ColumnSelectorModal.jsx # Column visibility settings
    └── ContentModal.jsx        # Content viewer (text + image preview)

web/src/hooks/mj-logs/
└── useMjLogsData.js            # Custom hook for state & logic
```

### 🎯 Key Improvements
- **Maintainability**: Clear separation of concerns, easier to understand
- **Reusability**: Modular components can be reused independently
- **Performance**: Optimized with `useMemo` for column rendering
- **Testing**: Single-responsibility components easier to test
- **Developer Experience**: Better code organization and readability

### 🎨 Midjourney-Specific Features Preserved
- All task type rendering with icons (IMAGINE, UPSCALE, VARIATION, etc.)
- Status rendering with appropriate colors and icons
- Image preview functionality for generated artwork
- Progress indicators for task completion
- Admin-only columns for channel and submission results
- Banner notification system for callback settings

### 🔧 Technical Details
- Centralized all business logic in `useMjLogsData` custom hook
- Extracted comprehensive column definitions with Lucide React icons
- Split complex UI into focused components (table, actions, filters, modals)
- Maintained responsive design patterns for mobile compatibility
- Preserved admin permission handling for restricted features

### 🐛 Fixes
- Improved component prop passing patterns
- Enhanced type safety through better state management
- Optimized rendering performance with proper memoization

## Breaking Changes
None - all existing imports and functionality preserved.
2025-07-18 22:19:58 +08:00
t0ng7u
3fe509757b ♻️ refactor: restructure LogsTable into modular component architecture
Refactor the monolithic LogsTable component (1453 lines) into a modular,
maintainable architecture following the channels table pattern.

## What Changed

### 🏗️ Architecture
- Split single large file into focused, single-responsibility components
- Introduced custom hook `useLogsData` for centralized state management
- Created dedicated column definitions file for better organization
- Implemented modal components for user interactions

### 📁 New Structure
```
web/src/components/table/usage-logs/
├── index.jsx                    # Main page component orchestrator
├── LogsTable.jsx               # Pure table rendering component
├── LogsActions.jsx             # Actions area (stats + compact mode)
├── LogsFilters.jsx             # Search form component
├── LogsColumnDefs.js           # Column definitions and renderers
└── modals/
    ├── ColumnSelectorModal.jsx # Column visibility settings
    └── UserInfoModal.jsx       # User information display

web/src/hooks/logs/
└── useLogsData.js              # Custom hook for state & logic
```

### 🎯 Key Improvements
- **Maintainability**: Clear separation of concerns, easier to understand
- **Reusability**: Modular components can be reused independently
- **Performance**: Optimized with `useMemo` for column rendering
- **Testing**: Single-responsibility components easier to test
- **Developer Experience**: Better code organization and readability

### 🔧 Technical Details
- Preserved all existing functionality and user experience
- Maintained backward compatibility through existing import path
- Centralized all business logic in `useLogsData` custom hook
- Extracted column definitions to separate module with render functions
- Split complex UI into focused components (table, actions, filters, modals)

### 🐛 Fixes
- Fixed Semi UI component import issues (`Typography.Paragraph`)
- Resolved module export dependencies
- Maintained consistent prop passing patterns

## Breaking Changes
None - all existing imports and functionality preserved.
2025-07-18 22:04:54 +08:00
t0ng7u
6799daacd1 🚀 feat(web/channels): Deep modular refactor of Channels table
1. Split monolithic `ChannelsTable` (2200+ LOC) into focused components
   • `channels/index.jsx` – composition entry
   • `ChannelsTable.jsx` – pure `<Table>` rendering
   • `ChannelsActions.jsx` – bulk & settings toolbar
   • `ChannelsFilters.jsx` – search / create / column-settings form
   • `ChannelsTabs.jsx` – type tabs
   • `ChannelsColumnDefs.js` – column definitions & render helpers
   • `modals/` – BatchTag, ColumnSelector, ModelTest modals

2. Extract domain hook
   • Moved `useChannelsData.js` → `src/hooks/channels/useChannelsData.js`
     – centralises state, API calls, pagination, filters, batch ops
     – now exports `setActivePage`, fixing tab / status switch errors

3. Update wiring
   • All sub-components consume data via `useChannelsData` props
   • Adjusted import paths after hook relocation

4. Clean legacy file
   • Legacy `components/table/ChannelsTable.js` now re-exports new module

5. Bug fixes
   • Tab switching, status filter & tag aggregation restored
   • Column selector & batch actions operate via unified hook

This commit completes the first phase of modularising the Channels feature, laying groundwork for consistent, maintainable table architecture across the app.
2025-07-18 21:05:36 +08:00
t0ng7u
3360b34af9 🐛 fix: SSR hydration mismatch in mobile detection & clean up sidebar style
- Added a server-snapshot fallback (`() => false`) to `useIsMobile` to ensure
  consistent results between server-side rendering and the browser, preventing
  hydration mismatches.
- Removed a redundant ternary in `PageLayout` sidebar styles, replacing
  `isMobile ? 'fixed' : 'fixed'` with a single `'fixed'` value for clarity.

These changes improve SSR reliability and tidy up inline styles without
affecting runtime functionality.
2025-07-16 04:46:31 +08:00
t0ng7u
a44fc51007 📱 refactor(web): remove legacy isMobile util and migrate to useIsMobile hook
BREAKING CHANGE:
helpers/utils.js no longer exports `isMobile()`.
Any external code that relied on this function must switch to the `useIsMobile` React hook.

Summary
-------
1. Deleted the obsolete `isMobile()` function from helpers/utils.js.
2. Introduced `MOBILE_BREAKPOINT` constant and `matchMedia`-based detection for non-React contexts.
3. Reworked toast positioning logic in utils.js to rely on `matchMedia`.
4. Updated render.js:
   • Removed isMobile import.
   • Added MOBILE_BREAKPOINT detection in `truncateText`.
5. Migrated every page/component to the `useIsMobile` hook:
   • Layout: HeaderBar, PageLayout, SiderBar
   • Pages: Home, Detail, Playground, User (Add/Edit), Token, Channel, Redemption, Ratio Sync
   • Components: ChannelsTable, ChannelSelectorModal, ConflictConfirmModal
6. Purged all remaining `isMobile()` calls and legacy imports.
7. Added missing `const isMobile = useIsMobile()` declarations where required.

Benefits
--------
• Unifies mobile detection with a React-friendly hook.
• Eliminates duplicated logic and improves maintainability.
• Keeps non-React helpers lightweight by using `matchMedia` directly.
2025-07-16 02:54:58 +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
RedwindA
bdb7c9cbd7 🔧 fix(useApiRequest): improve playground SSE error handling and stream completion tracking 2025-06-11 02:05:16 +08:00
CaIon
7bced6b236 chore: update CI workflow to use latest Bun version and adjust build environment variables 2025-06-08 03:28:36 +08:00
Apple\Apple
ce88b75f61 🎨 refactor(ui): modernize setup page
- Refactored system initialization page using TailwindCSS 3 and SemiUI components
- Changed layout from step navigation to single page display for all configurations
- Modified top area from vertical to more compact horizontal layout
- Updated gradient color scheme from blue/purple to orange/pink
- Fixed form field name duplication issues and optimized Form implementation
- Changed usage mode selection from three-column grid to vertical layout
- Replaced usage mode card icons from settings to more appropriate Layers icon
- Added specific prompts for different database types (SQLite/MySQL/PostgreSQL)
- Removed configuration summary section while keeping the initialization button
- Fixed useSetupCheck issue by using SetupCheck as a direct component for proper redirection
2025-06-04 08:15:48 +08:00
Apple\Apple
943f21f3cb ♻️ refactor: refactor the logic of fetchTokenKeys and SetupCheck 2025-06-04 01:00:48 +08:00
Apple\Apple
64b565dc15 ♻️ refactor(helpers): refactor the helpers folder and related imports 2025-06-03 23:56:39 +08:00
Apple\Apple
a7535aab99 ♻️ refactor(helpers): standardize file naming conventions and improve code organization
- Rename files to follow camelCase naming convention:
  • auth-header.js → authUtils.js
  • other.js → logUtils.js
  • rehypeSplitWordsIntoSpans.js → textAnimationUtils.js

- Update import paths in affected components:
  • Update exports in helpers/index.js
  • Fix import in LogsTable.js for logUtils
  • Fix import in MarkdownRenderer.js for textAnimationUtils

- Remove old files after successful migration

- Improve file naming clarity:
  • authUtils.js better describes authentication utilities
  • logUtils.js clearly indicates log processing functions
  • textAnimationUtils.js concisely describes text animation functionality

This refactoring enhances code maintainability and follows consistent naming patterns throughout the helpers directory.
2025-06-03 16:13:50 +08:00
Apple\Apple
fe7cd5aa8d 🐛 fix(message): prevent history loss when editing messages with duplicate IDs
- Store editing message object reference using useRef to avoid ID conflicts
- Use object reference comparison first before falling back to ID matching
- Apply fix to both save and cancel operations in message editing
- Clear reference after edit completion to prevent stale object issues

Previously, when editing imported messages that contained duplicate IDs,
the findIndex operation would match the first occurrence rather than the
intended message, causing conversation history truncation when saving
edits. This change stores and uses object references for accurate message
identification during the editing process.
2025-06-03 00:37:10 +08:00
Apple\Apple
d459b03e84 🐛 fix(message): prevent history loss when retrying imported messages with duplicate IDs
- Use object reference comparison first before falling back to ID matching
- Prevent incorrect message index lookup when duplicate IDs exist
- Apply fix to both handleMessageReset and handleMessageDelete functions
- Maintain backward compatibility with ID-based message identification

Previously, when importing messages that contained duplicate IDs, the
findIndex operation would match the first occurrence rather than the
intended message, causing history truncation on retry. This change uses
object reference comparison as the primary method, ensuring accurate
message identification and preserving conversation history.
2025-06-03 00:32:42 +08:00
Apple\Apple
e5d0f26fb9 🐛 fix(message): enable retry functionality for system role messages
- Extend handleMessageReset condition to include 'system' role messages
- Allow system messages to trigger regeneration like assistant messages
- Fix disabled retry button issue when message role is switched to system
- Maintain consistent user experience across different message roles

Previously, when an assistant message was switched to system role,
the retry button became non-functional. This change ensures that
system messages can be regenerated by finding the previous user
message and resending it, maintaining feature parity with assistant
messages.
2025-06-03 00:22:11 +08:00
Apple\Apple
f422a0588b 🔧 fix(playground): resolve message state issues after page refresh and config reset
**Problem 1: Chat interface not refreshing when resetting imported messages**
- The "reset messages simultaneously" option during config import failed to
  update the chat interface properly
- Normal conversation resets worked correctly

**Problem 2: Messages stuck in loading state after page refresh**
- When AI was generating a response and user refreshed the page, the message
  remained in loading state indefinitely
- Stop button had no effect on these orphaned loading messages

**Changes Made:**

1. **Fixed config reset message refresh** (`usePlaygroundState.js`):
   ```javascript
   // Clear messages first, then set defaults to force component re-render
   setMessage([]);
   setTimeout(() => {
     setMessage(DEFAULT_MESSAGES);
   }, 0);
   ```

2. **Enhanced stop generator functionality** (`useApiRequest.js`):
   ```javascript
   // Handle orphaned loading messages even without active SSE connection
   const onStopGenerator = useCallback(() => {
     // Close active SSE if exists
     if (sseSourceRef.current) {
       sseSourceRef.current.close();
       sseSourceRef.current = null;
     }

     // Always attempt to complete any loading/incomplete messages
     // ... processing logic
   }, [setMessage, applyAutoCollapseLogic, saveMessages]);
   ```

3. **Added automatic message state recovery** (`usePlaygroundState.js`):
   ```javascript
   // Auto-fix loading/incomplete messages on page load
   useEffect(() => {
     const lastMsg = message[message.length - 1];
     if (lastMsg.status === MESSAGE_STATUS.LOADING ||
         lastMsg.status === MESSAGE_STATUS.INCOMPLETE) {
       // Process incomplete content and mark as complete
       // Save corrected message state
     }
   }, []);
   ```

**Root Cause:**
- Config reset: Direct state assignment didn't trigger component refresh
- Loading state: No recovery mechanism for interrupted SSE connections after refresh

**Impact:**
-  Config reset now properly refreshes chat interface
-  Stop button works on orphaned loading messages
-  Page refresh automatically recovers incomplete messages
-  No more permanently stuck loading states
2025-06-02 23:56:58 +08:00
Apple\Apple
0bafdf3381 🐛 fix(playground): ensure chat interface refreshes when resetting imported messages
When using the "reset messages simultaneously" option during config import,
the conversation messages in the chat interface were not being properly reset,
while normal conversation resets worked correctly.

**Changes:**
- Modified `handleConfigReset` in `usePlaygroundState.js` to clear messages
  before setting default examples
- Added asynchronous message update to force Chat component re-render
- Ensures immediate UI refresh when resetting imported conversation data

**Root Cause:**
The direct assignment to DEFAULT_MESSAGES didn't trigger a complete
component refresh, causing the chat interface to display stale data.

**Solution:**
```javascript
// Before
setMessage(DEFAULT_MESSAGES);

// After
setMessage([]);
setTimeout(() => {
  setMessage(DEFAULT_MESSAGES);
}, 0);
```

This two-step approach forces the Chat component to unmount and remount
with fresh data, resolving the display inconsistency.
2025-06-02 23:24:50 +08:00
Apple\Apple
18c2e5cd98 🐛fix: Fix message saving missing the last conversation
- Modify saveMessagesImmediately to accept messages parameter
- Pass updated message list to all save calls instead of relying on closure
- Ensure complete message history is saved including the last message
- Fix timing issue where old message state was being saved

This fixes the issue where the last conversation was not being persisted to localStorage.
2025-06-02 21:39:51 +08:00
Apple\Apple
07ffc36678 perf: Optimize message persistence and reduce localStorage operations
- Refactor message saving strategy from automatic to manual saving
  - Save messages only on key operations: send, complete, edit, delete, role toggle, clear
  - Prevent frequent localStorage writes during streaming responses

- Remove excessive console logging
  - Remove all console.log statements from save/load operations
  - Clean up debug logs to reduce console noise

- Optimize initial state loading with lazy initialization
  - Replace useRef with useState lazy initialization for config and messages
  - Ensure loadConfig and loadMessages are called only once on mount
  - Prevent redundant localStorage reads during re-renders

- Update hooks to support new save strategy
  - Pass saveMessages callback through component hierarchy
  - Add saveMessagesImmediately to relevant hooks (useApiRequest, useMessageActions, useMessageEdit)
  - Trigger saves at appropriate lifecycle points

This significantly improves performance by reducing localStorage I/O operations
from continuous writes during streaming to discrete saves at meaningful points.
2025-06-02 21:21:46 +08:00
Apple\Apple
1d37867f39 🐛 fix(playground): ensure proper streaming updates & safeguard message handling
Summary
This commit addresses two critical issues affecting the real-time chat experience in the Playground:

1. Optimized re-rendering of reasoning content
   • Added `reasoningContent` to the comparison function of `OptimizedMessageContent` (`web/src/components/playground/OptimizedComponents.js`).
   • Ensures the component re-renders while reasoning text streams, resolving the bug where only the first characters (“好,”) were shown until the stream finished.

2. Defensive checks for SSE message updates
   • Added early-return guards in `streamMessageUpdate` (`web/src/hooks/useApiRequest.js`).
   • Skips updates when `lastMessage` is undefined or the last message isn’t from the assistant, preventing `TypeError: Cannot read properties of undefined (reading 'status')` during rapid SSE responses.

Impact
• Real-time reasoning content now appears progressively, enhancing user feedback.
• Eliminates runtime crashes caused by undefined message references, improving overall stability.
2025-06-02 06:21:05 +08:00
Apple\Apple
26ef7aae38 🐛 fix: resolve duplicate toast notifications when toggling message roles
- Remove duplicate onRoleToggle prop passing to ChatArea component in Playground/index.js
- Move Toast notification outside setMessage callback in useMessageActions hook
- Prevent multiple event bindings that caused repeated role switch notifications
- Add early return validation for role toggle eligibility

This fixes the issue where users would see multiple success toasts when switching
between Assistant and System roles in the chat interface.

Files changed:
- web/src/pages/Playground/index.js
- web/src/hooks/useMessageActions.js
2025-06-01 17:44:36 +08:00
Apple\Apple
5107f1b84a feat: Add custom request body editor with persistent message storage
- Add CustomRequestEditor component with JSON validation and real-time formatting
- Implement bidirectional sync between chat messages and custom request body
- Add persistent local storage for chat messages (separate from config)
- Remove redundant System Prompt field in custom mode
- Refactor configuration storage to separate messages and settings

New Features:
• Custom request body mode with JSON editor and syntax highlighting
• Real-time bidirectional synchronization between chat UI and custom request body
• Persistent message storage that survives page refresh
• Enhanced configuration export/import including message data
• Improved parameter organization with collapsible sections

Technical Changes:
• Add loadMessages/saveMessages functions in configStorage
• Update usePlaygroundState hook to handle message persistence
• Refactor SettingsPanel to remove System Prompt in custom mode
• Add STORAGE_KEYS constants for better storage key management
• Implement debounced auto-save for both config and messages
• Add hash-based change detection to prevent unnecessary updates

UI/UX Improvements:
• Disabled state styling for parameters in custom mode
• Warning banners and visual feedback for mode switching
• Mobile-responsive design for custom request editor
• Consistent styling with existing design system
2025-06-01 17:07:36 +08:00