fix(history): unify History filter bar with Jail and IP inputs
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
|
||||
import {
|
||||
Divider,
|
||||
Input,
|
||||
Text,
|
||||
ToggleButton,
|
||||
Toolbar,
|
||||
@@ -35,6 +36,14 @@ export interface DashboardFilterBarProps {
|
||||
originFilter: BanOriginFilter;
|
||||
/** Called when the user selects a different origin filter. */
|
||||
onOriginFilterChange: (value: BanOriginFilter) => void;
|
||||
/** Jail filter value (optional). */
|
||||
jail?: string;
|
||||
/** Called when the jail filter text changes (optional). */
|
||||
onJailChange?: (value: string) => void;
|
||||
/** IP address filter value (optional). */
|
||||
ip?: string;
|
||||
/** Called when the IP address filter text changes (optional). */
|
||||
onIpChange?: (value: string) => void;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -92,6 +101,10 @@ export function DashboardFilterBar({
|
||||
onTimeRangeChange,
|
||||
originFilter,
|
||||
onOriginFilterChange,
|
||||
jail,
|
||||
onJailChange,
|
||||
ip,
|
||||
onIpChange,
|
||||
}: DashboardFilterBarProps): React.JSX.Element {
|
||||
const styles = useStyles();
|
||||
const cardStyles = useCardStyles();
|
||||
@@ -146,6 +159,48 @@ export function DashboardFilterBar({
|
||||
))}
|
||||
</Toolbar>
|
||||
</div>
|
||||
|
||||
{onJailChange && (
|
||||
<>
|
||||
<div className={styles.divider}>
|
||||
<Divider vertical />
|
||||
</div>
|
||||
<div className={styles.group}>
|
||||
<Text weight="semibold" size={300}>
|
||||
Jail
|
||||
</Text>
|
||||
<Input
|
||||
placeholder="e.g. sshd"
|
||||
size="small"
|
||||
value={jail ?? ""}
|
||||
onChange={(_ev, data): void => {
|
||||
onJailChange(data.value);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{onIpChange && (
|
||||
<>
|
||||
<div className={styles.divider}>
|
||||
<Divider vertical />
|
||||
</div>
|
||||
<div className={styles.group}>
|
||||
<Text weight="semibold" size={300}>
|
||||
IP Address
|
||||
</Text>
|
||||
<Input
|
||||
placeholder="e.g. 192.168"
|
||||
size="small"
|
||||
value={ip ?? ""}
|
||||
onChange={(_ev, data): void => {
|
||||
onIpChange(data.value);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -125,4 +125,47 @@ describe("DashboardFilterBar", () => {
|
||||
expect(onTimeRangeChange).toHaveBeenCalledOnce();
|
||||
expect(onTimeRangeChange).toHaveBeenCalledWith("24h");
|
||||
});
|
||||
|
||||
it("renders jail and ip input controls when provided", async () => {
|
||||
const onJailChange = vi.fn();
|
||||
const onIpChange = vi.fn();
|
||||
|
||||
render(
|
||||
<FluentProvider theme={webLightTheme}>
|
||||
<DashboardFilterBar
|
||||
timeRange="24h"
|
||||
onTimeRangeChange={vi.fn()}
|
||||
originFilter="all"
|
||||
onOriginFilterChange={vi.fn()}
|
||||
jail=""
|
||||
onJailChange={onJailChange}
|
||||
ip=""
|
||||
onIpChange={onIpChange}
|
||||
/>
|
||||
</FluentProvider>,
|
||||
);
|
||||
|
||||
expect(screen.getByText(/Jail/i)).toBeInTheDocument();
|
||||
expect(screen.getByText(/IP Address/i)).toBeInTheDocument();
|
||||
expect(screen.getByPlaceholderText(/e.g. sshd/i)).toBeInTheDocument();
|
||||
expect(screen.getByPlaceholderText(/e.g. 192.168/i)).toBeInTheDocument();
|
||||
|
||||
const jailInput = screen.getByPlaceholderText(/e.g. sshd/i);
|
||||
const ipInput = screen.getByPlaceholderText(/e.g. 192.168/i);
|
||||
const user = userEvent.setup();
|
||||
|
||||
await user.clear(jailInput);
|
||||
await user.type(jailInput, "x");
|
||||
expect(onJailChange).toHaveBeenLastCalledWith("x");
|
||||
|
||||
await user.clear(ipInput);
|
||||
await user.type(ipInput, "1");
|
||||
expect(onIpChange).toHaveBeenLastCalledWith("1");
|
||||
});
|
||||
|
||||
it("does not render jail or ip inputs when handlers are missing", () => {
|
||||
renderBar();
|
||||
expect(screen.queryByText(/Jail/i)).toBeNull();
|
||||
expect(screen.queryByText(/IP Address/i)).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -16,7 +16,6 @@ import {
|
||||
DataGridHeader,
|
||||
DataGridHeaderCell,
|
||||
DataGridRow,
|
||||
Input,
|
||||
MessageBar,
|
||||
MessageBarBody,
|
||||
Spinner,
|
||||
@@ -82,11 +81,6 @@ const useStyles = makeStyles({
|
||||
gap: tokens.spacingHorizontalM,
|
||||
flexWrap: "wrap",
|
||||
},
|
||||
filterLabel: {
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: tokens.spacingVerticalXS,
|
||||
},
|
||||
tableWrapper: {
|
||||
overflow: "auto",
|
||||
borderRadius: tokens.borderRadiusMedium,
|
||||
@@ -390,7 +384,6 @@ function IpDetailView({ ip, onBack }: IpDetailViewProps): React.JSX.Element {
|
||||
|
||||
export function HistoryPage(): React.JSX.Element {
|
||||
const styles = useStyles();
|
||||
const cardStyles = useCardStyles();
|
||||
|
||||
// Filter state
|
||||
const [range, setRange] = useState<TimeRange>("24h");
|
||||
@@ -483,32 +476,15 @@ export function HistoryPage(): React.JSX.Element {
|
||||
onOriginFilterChange={(value) => {
|
||||
setOriginFilter(value);
|
||||
}}
|
||||
jail={jailFilter}
|
||||
onJailChange={(value) => {
|
||||
setJailFilter(value);
|
||||
}}
|
||||
ip={ipFilter}
|
||||
onIpChange={(value) => {
|
||||
setIpFilter(value);
|
||||
}}
|
||||
/>
|
||||
|
||||
<div className={`${styles.filterLabel} ${cardStyles.card}`}>
|
||||
<Text size={200}>Jail</Text>
|
||||
<Input
|
||||
placeholder="e.g. sshd"
|
||||
value={jailFilter}
|
||||
onChange={(_ev, data): void => {
|
||||
setJailFilter(data.value);
|
||||
}}
|
||||
size="small"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={`${styles.filterLabel} ${cardStyles.card}`}>
|
||||
<Text size={200}>IP Address</Text>
|
||||
<Input
|
||||
placeholder="e.g. 192.168"
|
||||
value={ipFilter}
|
||||
onChange={(_ev, data): void => {
|
||||
setIpFilter(data.value);
|
||||
}}
|
||||
size="small"
|
||||
/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{/* ---------------------------------------------------------------- */}
|
||||
|
||||
Reference in New Issue
Block a user