feat: add domain rules management feature

- Introduced a new DomainRulesPage component for managing custom and global equivalent domains.
- Updated AppMainRoutes to include a route for domain rules.
- Added API functions to fetch and save domain rules.
- Enhanced localization with new strings for domain rules in multiple languages.
- Updated styles for the new domain rules interface and ensured responsiveness.
- Added types for domain rules in the TypeScript definitions.
This commit is contained in:
shuaiplus
2026-05-06 00:33:09 +08:00
parent 246c73a3d3
commit 0a001bebcc
32 changed files with 2045 additions and 32 deletions
+62
View File
@@ -0,0 +1,62 @@
import { t } from '@/lib/i18n';
import type { DomainRules, TokenError } from '@/lib/types';
import { parseErrorMessage, parseJson, type AuthedFetch } from './shared';
function normalizeDomainsResponse(body: Partial<DomainRules> & Record<string, unknown>): DomainRules {
const equivalentDomains = Array.isArray(body.equivalentDomains)
? body.equivalentDomains
: Array.isArray(body.EquivalentDomains)
? body.EquivalentDomains as string[][]
: [];
const globalEquivalentDomains = Array.isArray(body.globalEquivalentDomains)
? body.globalEquivalentDomains
: Array.isArray(body.GlobalEquivalentDomains)
? body.GlobalEquivalentDomains as DomainRules['globalEquivalentDomains']
: [];
const customEquivalentDomains = Array.isArray(body.customEquivalentDomains)
? body.customEquivalentDomains as DomainRules['customEquivalentDomains']
: Array.isArray(body.CustomEquivalentDomains)
? body.CustomEquivalentDomains as DomainRules['customEquivalentDomains']
: equivalentDomains.map((domains, index) => ({
id: `custom:${index}`,
domains,
excluded: false,
}));
return {
equivalentDomains,
customEquivalentDomains,
globalEquivalentDomains,
object: 'domains',
};
}
export async function getDomainRules(authedFetch: AuthedFetch): Promise<DomainRules> {
const resp = await authedFetch('/api/settings/domains');
if (!resp.ok) throw new Error(await parseErrorMessage(resp, t('txt_domain_rules_load_failed')));
const body = await parseJson<Partial<DomainRules> & Record<string, unknown>>(resp);
if (!body) throw new Error(t('txt_domain_rules_invalid_response'));
return normalizeDomainsResponse(body);
}
export async function saveDomainRules(
authedFetch: AuthedFetch,
payload: {
customEquivalentDomains: DomainRules['customEquivalentDomains'];
equivalentDomains: string[][];
excludedGlobalEquivalentDomains: number[];
}
): Promise<DomainRules> {
const resp = await authedFetch('/api/settings/domains', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
});
if (!resp.ok) {
const body = await parseJson<TokenError>(resp);
throw new Error(body?.error_description || body?.error || t('txt_domain_rules_save_failed'));
}
const body = await parseJson<Partial<DomainRules> & Record<string, unknown>>(resp);
if (!body) throw new Error(t('txt_domain_rules_invalid_response'));
return normalizeDomainsResponse(body);
}