Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
169 changes: 43 additions & 126 deletions web/src/pages/RulesPage/RulesTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
getCoreRowModel,
useReactTable,
} from '@tanstack/react-table';
import { cloneDeep, flat } from 'radashi';
import { cloneDeep } from 'radashi';
import { useCallback, useMemo, useState } from 'react';
import './RulesTable.scss';
import { m } from '../../paraglide/messages';
Expand All @@ -16,12 +16,9 @@ import {
type AclRule,
AclStatus,
type AclStatusValue,
type GroupInfo,
type LicenseInfo,
type NetworkDevice,
type NetworkLocation,
type ResourceById,
type User,
} from '../../shared/api/types';
import { TableValuesListCell } from '../../shared/components/TableValuesListCell/TableValuesListCell';
import { Badge } from '../../shared/defguard-ui/components/Badge/Badge';
Expand All @@ -40,18 +37,8 @@ import { TableCell } from '../../shared/defguard-ui/components/table/TableCell/T
import { TableEditCell } from '../../shared/defguard-ui/components/table/TableEditCell/TableEditCell';
import { TableTop } from '../../shared/defguard-ui/components/table/TableTop/TableTop';
import { Snackbar } from '../../shared/defguard-ui/providers/snackbar/snackbar';
import { isPresent } from '../../shared/defguard-ui/utils/isPresent';
import { canUseBusinessFeature, licenseActionCheck } from '../../shared/utils/license';

const displayUser = (user?: User): string => {
if (!isPresent(user)) return '';

if (user.first_name || user.last_name) {
return `${user.first_name} ${user.last_name}`.trim();
}
return user.username;
};

type RowData = AclRule;

const columnHelper = createColumnHelper<RowData>();
Expand All @@ -60,9 +47,6 @@ type Props = {
license: LicenseInfo | null;
aliases: ResourceById<AclAlias>;
destinations: ResourceById<AclDestination>;
groups: ResourceById<GroupInfo>;
users: ResourceById<User>;
devices: ResourceById<NetworkDevice>;
locations: ResourceById<NetworkLocation>;
data: AclRule[];
title: string;
Expand All @@ -83,16 +67,26 @@ export const RulesTable = ({
enableSearch,
aliases,
destinations,
devices,
groups,
users,
locations,
data,
license,
variant,
}: Props) => {
const navigate = useNavigate();

const renderResourceBadge = useCallback(
(marker: 'A' | 'D', key: string, text: string) => (
<Badge
className="rules-table-destination-badge"
data-marker={marker}
variant={BadgeVariant.Neutral}
text={text}
key={key}
/>
),
[],
);

const { mutate: deleteRule } = useMutation({
mutationFn: api.acl.rule.deleteRule,
meta: {
Expand All @@ -119,53 +113,6 @@ export const RulesTable = ({

const [search, setSearch] = useState('');

const renderPermissionCell = useCallback(
(
permission: 'deny' | 'allow',
permissionUsers: boolean,
permissionGroup: boolean,
permissionDevice: boolean,
includedUsers: number[],
includedGroups: number[],
includedDevices: number[],
) => {
if (permissionDevice && permissionGroup && permissionUsers) {
return (
<TableCell>
{permission === 'allow' && (
<Badge
variant={BadgeVariant.Success}
icon="check-filled"
text="All allowed"
/>
)}
{permission === 'deny' && (
<Badge
variant={BadgeVariant.Warning}
icon="status-important"
text="All denied"
/>
)}
</TableCell>
);
}
const display = flat([
permissionUsers
? ['All users']
: includedUsers.map((userId) => displayUser(users[userId])),
permissionGroup
? ['All groups']
: includedGroups.map((groupId) => groups[groupId]?.name ?? ''),
permissionDevice
? ['All network devices']
: includedDevices.map((deviceId) => devices[deviceId]?.name ?? ''),
]).filter((value) => value.length > 0);

return <TableValuesListCell values={display} />;
},
[users, devices, groups],
);

const renderStatusCell = useCallback(
(ruleState: AclStatusValue, isEnabled: boolean) => {
// handle applied rules first
Expand Down Expand Up @@ -212,79 +159,49 @@ export const RulesTable = ({
),
}),
columnHelper.display({
id: 'destination',
header: 'Destination',
minSize: 350,
id: 'predefined-destinations',
header: 'Predefined destinations',
minSize: 300,
cell: (info) => {
const row = info.row.original;
const manualAddresses = row.addresses.trim();
const hasManualAddresses = manualAddresses.length > 0;

return (
<TableCell>
<TableCell className="rules-table-destination-cell">
{row.destinations.map((destinationId) => {
const destination = destinations[destinationId];
if (!destination) return null;
return (
<Badge
className="rules-table-destination-badge"
data-marker="D"
variant={BadgeVariant.Neutral}
text={destination.name}
key={destinationId}
/>
);
})}
{hasManualAddresses && <span>{manualAddresses}</span>}
{row.aliases.map((aliasId) => {
const alias = aliases[aliasId];
if (!alias) return null;

return (
<Badge
className="rules-table-destination-badge"
data-marker="A"
variant={BadgeVariant.Neutral}
text={alias.name}
key={aliasId}
/>
return renderResourceBadge(
'D',
`destination-${destinationId}`,
destination.name,
);
})}
</TableCell>
);
},
}),
columnHelper.display({
id: 'permissions',
header: 'Permissions',
minSize: 220,
id: 'manual-destinations',
header: 'Manually configured destination',
minSize: 300,
cell: (info) => {
const row = info.row.original;
return renderPermissionCell(
'allow',
row.allow_all_users,
row.allow_all_groups,
row.allow_all_network_devices,
row.allowed_users,
row.allowed_groups,
row.allowed_network_devices,
);
},
}),
columnHelper.display({
id: 'restrictions',
header: 'Restrictions',
minSize: 220,
cell: (info) => {
const row = info.row.original;
return renderPermissionCell(
'deny',
row.deny_all_users,
row.deny_all_groups,
row.deny_all_network_devices,
row.denied_users,
row.denied_groups,
row.denied_network_devices,

if (!row.use_manual_destination_settings) {
return <TableCell className="rules-table-destination-cell" />;
}

const manualAddresses = row.addresses.trim();
const hasManualAddresses = manualAddresses.length > 0;

return (
<TableCell>
{hasManualAddresses && <span>{manualAddresses}</span>}
{row.aliases.map((aliasId) => {
const alias = aliases[aliasId];
if (!alias) return null;
return renderResourceBadge('A', `alias-${aliasId}`, alias.name);
})}
</TableCell>
);
},
}),
Expand Down Expand Up @@ -408,11 +325,11 @@ export const RulesTable = ({
[
aliases,
destinations,
renderPermissionCell,
deleteRule,
locations,
navigate,
renderStatusCell,
renderResourceBadge,
license,
variant,
toggleRule,
Expand Down
9 changes: 1 addition & 8 deletions web/src/pages/RulesPage/tabs/RulesDeployedTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ export const RulesDeployedTab = () => {

const navigate = useNavigate();

const { aliases, destinations, groups, locations, users, devices, license, loading } =
useRuleDeps();
const { aliases, destinations, locations, license, loading } = useRuleDeps();

const buttonProps = useMemo(
(): ButtonProps => ({
Expand Down Expand Up @@ -55,10 +54,7 @@ export const RulesDeployedTab = () => {
{!isEmpty &&
isPresent(aliases) &&
isPresent(destinations) &&
isPresent(groups) &&
isPresent(locations) &&
isPresent(users) &&
isPresent(devices) &&
license !== undefined && (
<RulesTable
variant="deployed"
Expand All @@ -67,9 +63,6 @@ export const RulesDeployedTab = () => {
data={rules}
aliases={aliases}
destinations={destinations}
groups={groups}
devices={devices}
users={users}
locations={locations}
license={license}
enableSearch
Expand Down
9 changes: 1 addition & 8 deletions web/src/pages/RulesPage/tabs/RulesPendingTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@ export const RulesPendingTab = () => {
},
});

const { aliases, destinations, groups, locations, users, devices, license, loading } =
useRuleDeps();
const { aliases, destinations, locations, license, loading } = useRuleDeps();

const buttonProps = useMemo(
(): ButtonProps => ({
Expand Down Expand Up @@ -59,10 +58,7 @@ export const RulesPendingTab = () => {
{!isEmpty &&
isPresent(aliases) &&
isPresent(destinations) &&
isPresent(groups) &&
isPresent(locations) &&
isPresent(users) &&
isPresent(devices) &&
license !== undefined && (
<RulesTable
variant="pending"
Expand All @@ -71,9 +67,6 @@ export const RulesPendingTab = () => {
data={rules}
aliases={aliases}
destinations={destinations}
groups={groups}
devices={devices}
users={users}
locations={locations}
license={license}
/>
Expand Down
Loading