import { useReducer, useState } from "react"; import { useMutation, useQueryClient } from "@tanstack/react-query"; import * as stylex from "@stylexjs/stylex"; import { clientPrefixesPutMutation } from "@/lib/queries"; import type { ClientPrefix, Group } from "@/lib/types"; import { defaultGroupId } from "@/lib/defaultGroup"; import { firstProblem, initPrefixEditor, isDirty, prefixEditorReducer, toInputs } from "./prefixEditor"; import InlineError from "@/lib/InlineError"; import Select from "@/ui/Select"; import { styles as shared } from "@/ui/styles"; import { colors } from "@/ui/tokens.stylex"; import { READ_ONLY_HINT, useReadOnlyConfig } from "@/features/settings/authority"; interface Props { prefixes: ClientPrefix[]; groups: Group[]; } const styles = stylex.create({ section: { marginTop: "2.5rem", }, heading: { fontSize: "1.25rem", lineHeight: "1.75rem", fontWeight: 600, }, intro: { marginTop: "0.25rem", fontSize: "0.875rem", lineHeight: "1.25rem", color: colors.textMuted, }, empty: { marginTop: "1rem", fontSize: "0.875rem", lineHeight: "1.25rem", color: colors.textMuted, }, rows: { display: "flex", flexDirection: "column", gap: "0.5rem", marginTop: "1rem", listStyleType: "none", padding: 0, }, row: { display: "flex", flexWrap: "wrap", alignItems: "center", gap: "0.5rem", }, prefixInput: { width: "13rem", }, priorityInput: { width: "5rem", }, removeButton: { borderRadius: "0.25rem", borderWidth: 1, borderStyle: "solid", borderColor: colors.borderStrong, backgroundColor: "transparent", paddingInline: "0.5rem", paddingBlock: "0.375rem", fontSize: "0.875rem", lineHeight: "1.25rem", color: colors.danger, }, validation: { marginTop: "0.5rem", fontSize: "0.875rem", lineHeight: "1.25rem", color: colors.danger, }, actions: { display: "flex", gap: "0.5rem", marginTop: "1rem", }, }); export default function PrefixesEditor({ prefixes, groups }: Props) { const queryClient = useQueryClient(); const mutation = useMutation(clientPrefixesPutMutation(queryClient)); const [state, dispatch] = useReducer(prefixEditorReducer, prefixes, initPrefixEditor); const [validation, setValidation] = useState(null); const dirty = isDirty(state); const fallbackGroupId = defaultGroupId(groups); const readOnly = useReadOnlyConfig(); const groupOptions = groups.map((group) => ({ value: String(group.id), label: group.name })); const save = () => { const problem = firstProblem(state.rows); setValidation(problem); if (problem !== null) return; mutation.mutate(toInputs(state.rows), { onSuccess: (stored) => dispatch({ type: "reset", prefixes: stored }), }); }; return (

Client prefixes

Prefixes assign a group to whole address ranges. The list is saved as a whole; the highest priority match wins.

{state.rows.length === 0 ? (

No prefixes configured.

) : ( )} {validation !== null && (

{validation}

)}
{dirty && ( )}
); }