On macOS, WKWebView applies system auto-capitalization to text inputs, so
typing a lowercase rule payload (e.g. a domain) in the rule editor dialog
turned its first letter into uppercase and required a manual correction.
Apply the same input-hint attributes already used by other text fields in
the app (autoComplete/autoCorrect/autoCapitalize/spellCheck) to the rule
content field.
Fixes#8038
* feat(contract): export wire contract from backend and generate frontend types
Adds a zero-dependency `frontend-contract` bin that serializes the real
NoticeStatus variants and FrontendEvent payloads, scripts/gen-contract.mjs
which emits the committed src/services/contract.ts, and a CI job that
regenerates it and fails on a non-empty diff. events.ts now derives its
event map from the generated contract instead of hand-typed shapes.
* feat(events): route all backend events through a single event bus and store
Adds src/services/bus (the only listen/emit site: one handler per contract
event plus the frontend-internal test-all event) and the React
context/reducer app store. Migrates the five scattered subscriptions
(layout events, pending failures, proxy refresh, profile update/timer,
test-all), deletes the old glue (events.ts, use-listen, use-layout-events,
LoadingCacheProvider), moves run state into the store, and adds an
architecture gate script wired into CI. Behavior is unchanged; the
run-state query's poll/focus safety net is preserved by the store
provider.
* refactor(notice): make the notice table exhaustive and drop dead wire entries
D5 cleanup, frontend and backend in one commit: removes the six
config_validate::* statuses that never receive a backend send and the
set_config::ok send (enum variants, golden list 41→34, send point in
restart_clash_core), their frontend handlers, and the five i18n keys only
those handlers used. The notice table is now typed as a Record over the
generated NoticeStatus union, so a status without a frontend entry fails
to compile. The info status (sent by the silent updater for breaking
change notices, previously dropped with a console warning) now shows an
info toast — the one deliberate behavior delta.
* feat(mutate): single funnel for user-intent commands and invoke gate
Adds src/services/mutate.ts: one path for optimistic apply, services-layer
invoke, Busy handling, failure rollback, and the error toast, with busy
bookkeeping mirrored into the app store. The patch hooks (verge, clash,
profiles) now route through it. Moves the remaining direct invokes
(unlock ×3, DNS ×4) into cmds.ts and turns on the invoke-only-in-services
architecture gate in CI.
* refactor(settings): route settings-domain commands through the mutate funnel
Ports port saving, webdav/local backup operations, core change/restart/
upgrade, service install/uninstall/repair flows, the system-proxy toggle
queue, the DNS override toggle, and app lifecycle commands onto the single
funnel. Bespoke flows keep their own error handling via errorNotice:false;
simple flows gain the funnel's default error toast and revalidation.
* refactor(profiles): route profile operations through the mutate funnel
Ports profile create/import/reorder/delete/update/patch/save-file and
enhance calls onto the funnel; retry and editor flows keep their own
error handling with errorNotice:false. Per-uid ids keep the update
worker pool concurrent under the funnel's in-flight dedupe.
* refactor(proxies): route proxy/home/misc commands through the mutate funnel
Ports mode switching (page and home card), chain runtime updates, node
selection with tray sync, selection recording, provider updates and
syncs, and lightweight-mode entry onto the funnel; every site keeps its
existing optimistic/revert and error-handling behavior.
* docs: add frontend architecture guardrails for src
Layering rules for the contract flow: generated contract as the only
wire-typing source, event bus as the only listen/emit site, pure-reducer
store for event-derived state, the mutate funnel for user intent, and
invoke only in the services layer — each backed by the CI gates.
* fix(events): close run-state race and restore single error toasts
Self-review findings: the bus now re-reads the run-state snapshot in
onSubscribed so an event racing the store's initial read cannot leave a
stale snapshot (the ordering the old layout listener guaranteed), and the
patch hooks pass errorNotice:false so GuardState/page handlers remain the
only error toast, matching the pre-migration behavior.
* fix(frontend): preserve queued intents and fresh runtime snapshots
* refactor(frontend): trim unused mutation and busy state APIs
* docs(frontend): focus guardrails on architecture ownership
* fix(rules): disable auto-capitalization in rule content input
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(rules): pass input hints to the rule content input element
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: wonfen <eiwonfen@gmail.com>
* fix(profile): virtualize editor lists for rule/proxy/group editors
* refactor(list): remove feedbackClone from sortable item and list integration
* refactor(profile): use type instead of export type for category
* refactor(ui): rename measureElementRef to measureElement in sortable components
- Remove hardcoded body font-family from index.scss, use MUI theme dt.font_family instead
- Extract monospace font stack to shared MONACO_FONT_FAMILY constant in utils/font-family.ts
- Add platform check for twemoji mozilla in ip-info-card.tsx
- Consolidate 5 Monaco Editor font-family declarations into single constant
* refactor: migrate to @dnd-kit/react and simplify sortable components
* chore: enable css formatting in biome.json
* refactor(profile): simplify icon rendering logic and add alt text
* style(profiles): add overflow hidden to profile grid container
* refactor(profile): add radix for parseInt and improve type safety in profiles
* docs: update changelog with drag-and-drop styling improvements
* refactor(profile): move hasValidName function out of ProxiesEditorViewer
* refactor(proxy): refactor proxy chain into sortable components
* feat(proxy): add drop state styling and arrow animations to proxy chain
* style(profiles): reduce horizontal padding in profile grid
* feat(profile): add vertical margin to editor viewer items
* chore: refresh pnpm lockfile
* fix: preserve drag and drop behavior
---------
Co-authored-by: Tunglies <77394545+Tunglies@users.noreply.github.com>
- Replace boolean/string validation results with structured ValidationOutcome values across config validation, profile switching, DNS validation, and script validation. Callers can now distinguish valid, invalid, skipped, and busy states, with invalid results carrying an error kind and message.
- Route core config updates through structured outcomes and checked forced updates. Generation and validation failures now discard runtime drafts and surface validation failures instead of relying on empty success messages.
- Preserve existing frontend ergonomics by keeping boolean service wrappers where callers only need success, while direct DNS and script validation consumers receive ValidationOutcome. Failed profile editor saves reload the backend-restored file content and synchronize Monaco models so reopened editors show the restored state.
- Dispose Monaco editor instances on dialog close to prevent cycle leak
- Replace gcTime: Infinity with finite TTLs and evict orphaned subscription queryKeys
- Add missing useEffect cleanup for timers, move setTimeout out of useMemo
* feat: migrate from react-monaco-editor to @monaco-editor/react and update editor components
* chore: add acknowledgments for contributors in update log
* feat: enhance frontend information editing component for improved performance
- Reorganized import statements in various components to ensure consistent ordering and grouping.
- Removed unnecessary imports and added missing ones where applicable.
- Improved readability and maintainability of the codebase by standardizing import styles.
- Consolidated and reordered imports in various files for better readability and maintainability.
- Removed unused imports and ensured consistent import styles.
- Enhanced the structure of components by grouping related imports together.
- Updated the layout and organization of hooks to streamline functionality.
- Improved the overall code quality by following best practices in import management.
fix: add missing showNotice error handling and improve async UI feedback
- Add showNotice error notifications to unlock page async error branches
- Restore showNotice for YAML serialization errors in rules/groups/proxies editor
- Ensure all user-facing async errors are surfaced via showNotice
- Add fade-in animation to layout for smoother theme transition and reduce white screen
- Use requestIdleCallback/setTimeout for heavy UI state updates to avoid UI blocking
- Minor: remove window.showNotice usage, use direct import instead