Files
3x-ui/frontend/src/schemas/subBalancer.ts
T
MHSanaei 89e200ead4 fix(frontend): key geo entries by page position and clear test-suite noise
Zod 4: use the `error` param instead of the deprecated `message`.
lint:deprecated missed these because tsgolint's no-deprecated does not
resolve object-literal properties on a `string | Params` union.

Geodata: key geo entry rows by page position. antd deprecates rowKey's
index argument, and kind:value repeats within a page because the reader
drops domain attributes (22 pairs in geosite_IR.dat, 108 in geosite_RU).

Nord/PIA: the "All cities/regions" option used a null value, which antd
warns on. Map it through a sentinel at the Select boundary so form state
stays null, with tests that fail when the sentinel is not mapped back.

Tests:
- Run the oxlint guard through node; .bin/oxlint is a sh shim Windows
  cannot spawn, and the swallowed error left both guard cases vacuous.
- Start unit workers with --no-experimental-webstorage; msw's localStorage
  probe made Node 25+ warn once per forked worker.
- Set IS_REACT_ACT_ENVIRONMENT, which RTL never sets with globals: false,
  and settle the async updates it exposed inside act(). The row-cells
  memo test now fails when memo is removed.
- Disable antd's click wave in Storybook; it re-rendered inside the next
  story's act() and tripped "not configured to support act".
- Assert InboundFormModal's validation log instead of leaking it, and
  give the rule-form test a well-formed clients/list response.
2026-09-25 21:21:03 +02:00

47 lines
1.6 KiB
TypeScript

import { z } from 'zod';
export const SubBalancerStrategySchema = z.enum(['leastLoad', 'leastPing', 'random', 'roundRobin']);
export type SubBalancerStrategy = z.infer<typeof SubBalancerStrategySchema>;
export const SubBalancerSchema = z.object({
id: z.number(),
remark: z.string(),
strategy: SubBalancerStrategySchema,
inboundIds: z.array(z.number()),
memberWeights: z.record(z.string(), z.number()).nullish(),
sortOrder: z.number(),
enabled: z.boolean(),
createdAt: z.number().optional(),
updatedAt: z.number().optional(),
});
export type SubBalancer = z.infer<typeof SubBalancerSchema>;
export const SubBalancerListSchema = z.array(SubBalancerSchema);
export const SubBalancerFormSchema = z.object({
remark: z
.string()
.trim()
.min(1, 'pages.settings.subBalancers.errRemarkRequired')
.max(256, 'pages.settings.subBalancers.errRemarkRequired'),
strategy: SubBalancerStrategySchema,
inboundIds: z
.array(z.number().int().positive())
.min(1, 'pages.settings.subBalancers.errInboundsRequired'),
// inboundId (stringified) -> leastLoad weight; absent members weigh 1.0.
memberWeights: z
.record(
z.string(),
z
.number({ error: 'pages.settings.subBalancers.errWeightPositive' })
.positive('pages.settings.subBalancers.errWeightPositive'),
)
.optional(),
sortOrder: z
.number({ error: 'pages.settings.subBalancers.errSortOrder' })
.int('pages.settings.subBalancers.errSortOrder')
.min(1, 'pages.settings.subBalancers.errSortOrder'),
enabled: z.boolean(),
});
export type SubBalancerFormValues = z.infer<typeof SubBalancerFormSchema>;