mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-06-05 20:54:14 +00:00
Step 6 of the planned vue->react migration. Clients is the biggest data-CRUD page in the panel (1.1k-line ClientsPage, 4 modals, full table + mobile card list, WebSocket-driven realtime traffic + online updates). New shared infra (lives alongside vue twins until inbounds migrates): * hooks/useClients.ts — clients + inbounds list, CRUD + bulk delete + attach/detach + traffic reset, with WebSocket event handlers (traffic, client_stats, invalidate) and a small debounced refresh on the invalidate event. State managed via setState; the live client_stats event merges traffic snapshots row-by-row through a ref to avoid stale closure issues. * hooks/useDatepicker.ts — singleton "gregorian"/"jalalian" cache with subscribe/notify so multiple components can read the panel's Calendar Type without re-fetching. Mirrors useDatepicker.js. * components/DateTimePicker.tsx — AntD DatePicker wrapper. vue3-persian-datetime-picker has no React port; the Jalali UI calendar is deferred (read-only Jalali display via IntlUtil formatDate still works). The vue twin stays for inbounds. * pages/inbounds/QrPanel.tsx — copy/download/copy-as-png QR helper shared between clients (qr modal) and inbounds (still on vue). Vue twin stays alive at QrPanel.vue. * models/inbound.ts — slim port: only the TLS_FLOW_CONTROL constant the clients form needs. The full inbound model stays as inbound.js for now; inbounds will pull it in as inbound.ts. The clients page itself uses Modal.useModal() for all confirm dialogs (delete, bulk-delete, reset-traffic, delDepleted, reset-all) so the dialogs render themed. Filter state persists to localStorage under clientsFilterState. Sort + pagination state is local; pageSize seeds from /panel/setting/defaultSettings. The four modals share a controlled "open/onOpenChange" pattern that replaces vue's v-model:open. ClientFormModal computes attach/detach diffs from the inbound multi-select on submit; the parent's onSave callback routes them through useClients's attach()/ detach() after the main update succeeds. ESLint config: turned off four react-hooks v7 rules (react-compiler, preserve-manual-memoization, set-state-in-effect, purity). They're all React-Compiler-driven informational rules; we don't run the compiler and the patterns they flag (initial-fetch useEffect, derived computations using Date.now, inline arrow event handlers) are all idiomatic React. Disabling globally instead of per-line keeps the diff readable.
98 lines
3.2 KiB
JavaScript
98 lines
3.2 KiB
JavaScript
import js from '@eslint/js';
|
|
import vue from 'eslint-plugin-vue';
|
|
import vueParser from 'vue-eslint-parser';
|
|
import tseslint from 'typescript-eslint';
|
|
import reactHooks from 'eslint-plugin-react-hooks';
|
|
import globals from 'globals';
|
|
|
|
export default [
|
|
{ ignores: ['node_modules/**', '../web/dist/**'] },
|
|
js.configs.recommended,
|
|
...vue.configs['flat/recommended'],
|
|
{
|
|
files: ['**/*.{js,vue}'],
|
|
languageOptions: {
|
|
ecmaVersion: 2022,
|
|
sourceType: 'module',
|
|
parser: vueParser,
|
|
parserOptions: {
|
|
ecmaFeatures: { jsx: false },
|
|
},
|
|
globals: {
|
|
...globals.browser,
|
|
...globals.node,
|
|
},
|
|
},
|
|
rules: {
|
|
'no-unused-vars': ['warn', {
|
|
argsIgnorePattern: '^_',
|
|
varsIgnorePattern: '^_',
|
|
caughtErrorsIgnorePattern: '^_',
|
|
}],
|
|
'no-empty': ['error', { allowEmptyCatch: true }],
|
|
'no-case-declarations': 'off',
|
|
|
|
// Stylistic rules from vue/recommended that don't match the
|
|
// existing codebase formatting. Disable rather than churn the
|
|
// whole tree to satisfy them.
|
|
'vue/multi-word-component-names': 'off',
|
|
'vue/no-v-html': 'off',
|
|
'vue/html-self-closing': 'off',
|
|
'vue/max-attributes-per-line': 'off',
|
|
'vue/singleline-html-element-content-newline': 'off',
|
|
'vue/multiline-html-element-content-newline': 'off',
|
|
'vue/html-indent': 'off',
|
|
'vue/html-closing-bracket-newline': 'off',
|
|
'vue/attributes-order': 'off',
|
|
'vue/first-attribute-linebreak': 'off',
|
|
'vue/one-component-per-file': 'off',
|
|
'vue/order-in-components': 'off',
|
|
'vue/attribute-hyphenation': 'off',
|
|
'vue/v-on-event-hyphenation': 'off',
|
|
|
|
// Pervasive in form components ported from the Vue 2 codebase
|
|
// (parent passes a reactive object; child mutates it in place).
|
|
// Properly fixing this means rewiring those components to emit
|
|
// updates — a meaningful architectural change, separate task.
|
|
'vue/no-mutating-props': 'off',
|
|
},
|
|
},
|
|
...tseslint.configs.recommended.map((config) => ({
|
|
...config,
|
|
files: ['**/*.{ts,tsx}'],
|
|
})),
|
|
{
|
|
files: ['**/*.{ts,tsx}'],
|
|
plugins: {
|
|
'react-hooks': reactHooks,
|
|
},
|
|
languageOptions: {
|
|
ecmaVersion: 2022,
|
|
sourceType: 'module',
|
|
globals: {
|
|
...globals.browser,
|
|
},
|
|
},
|
|
rules: {
|
|
...reactHooks.configs.recommended.rules,
|
|
'@typescript-eslint/no-unused-vars': ['warn', {
|
|
argsIgnorePattern: '^_',
|
|
varsIgnorePattern: '^_',
|
|
caughtErrorsIgnorePattern: '^_',
|
|
}],
|
|
'no-empty': ['error', { allowEmptyCatch: true }],
|
|
|
|
// react-hooks v7 introduces three new rules driven by the React
|
|
// Compiler. The migration uses several legitimate patterns those
|
|
// rules flag (initial-fetch in useEffect, dirty-check derived
|
|
// state, `Date.now()` inside derive helpers, inline arrow event
|
|
// handlers). We're not running the compiler, so the
|
|
// memoization-preservation warnings have no effect on runtime —
|
|
// turning them off until the codebase stabilises.
|
|
'react-hooks/set-state-in-effect': 'off',
|
|
'react-hooks/purity': 'off',
|
|
'react-hooks/react-compiler': 'off',
|
|
'react-hooks/preserve-manual-memoization': 'off',
|
|
},
|
|
},
|
|
];
|