1 import { c, msgid } from 'ttag';
3 import Copy from '@proton/components/components/button/Copy';
4 import TableRow from '@proton/components/components/table/TableRow';
5 import useNotifications from '@proton/components/hooks/useNotifications';
6 import clsx from '@proton/utils/clsx';
8 import { type CountryOptions, getLocalizedCountryByAbbr } from '../../../helpers/countries';
9 import { CountryFlagAndName } from './CountryFlagAndName';
10 import type { Gateway } from './Gateway';
11 import type { GatewayLogical } from './GatewayLogical';
12 import GatewayManageButton from './GatewayManageButton';
13 import type { GatewayServer } from './GatewayServer';
14 import type { GatewayUser } from './GatewayUser';
15 import { getFormattedLoad, getMembers } from './helpers';
19 showDeleted?: boolean;
24 isDeleted: (logical: GatewayLogical) => boolean;
25 users: readonly GatewayUser[];
26 countryOptions: CountryOptions;
27 provisioningDuration: string;
28 deletingLogicals: readonly string[];
29 deletedLogicals: Record<string, boolean>;
30 renameGateway: (id: string, name: string) => () => any;
31 editGatewayServers: (gateway: Gateway, logical: GatewayLogical) => () => any;
32 editGatewayUsers: (gateway: Gateway, logical: GatewayLogical) => () => any;
33 deleteGateway: (gateway: Gateway) => () => any;
36 export const GatewayRow = ({
54 const { createNotification } = useNotifications();
56 let provisioningCounter = 0;
57 const allLogicals = gateway.Logicals || [];
58 const deleted = allLogicals.every(isDeleted);
60 if (deleted && !showDeleted) {
64 const logicals = allLogicals.filter((logical) => {
65 if (isDeleted(logical)) {
69 if (!logical.Servers?.length) {
70 provisioningCounter++;
77 const provisionedLogicals = [...logicals.filter((l) => l.Visible), ...logicals.filter((l) => !l.Visible)];
78 const hasPendingServers = provisioningCounter > 0;
79 const main = provisionedLogicals[0] || allLogicals[0];
80 const [statusClasses, statusText] = provisionedLogicals.length
81 ? ['bg-success', /** translator: status of the gateway: people can connect to it */ c('Info').t`active`]
84 /** translator: status of the gateway: people cannot connect to it */ c('Info').t`inactive`,
87 const getIpsCell = (servers: GatewayServer[]) =>
90 ...(showIPv4 ? [servers[0].ExitIPv4] : []),
91 ...(showIPv6 ? [servers[0].ExitIPv6] : []),
92 ...(showLoad ? [getFormattedLoad(servers)] : []),
94 : c('Action').t`Your server will be provisioned in the next days`;
98 className={deleted ? 'opacity-50' : undefined}
101 <span className={clsx(['py-1 px-2 rounded text-uppercase', statusClasses])}>{statusText}</span>,
103 {provisionedLogicals.length < 1 && !hasPendingServers && '0'}
104 {provisionedLogicals.map((logical) => {
105 const title = getLocalizedCountryByAbbr(logical.ExitCountry, countryOptions);
107 <div key={'logical-' + logical.ID}>
108 <span className="text-nowrap bg-weak py-1 px-2 rounded">
110 countryCode={logical.ExitCountry}
114 <span className="color-weak"> • </span>
115 {getIpsCell(logical.Servers)}
117 value={logical.Servers[0].ExitIPv4}
121 text: c('Notification').t`IP Address copied to clipboard`,
129 {hasPendingServers && (
130 <div className="color-weak">
132 msgid`${provisioningCounter} server is still being set up. This usually takes around ${provisioningDuration}.`,
133 `${provisioningCounter} servers are still being set up. This usually takes around ${provisioningDuration}.`,
141 getMembers(users, main),
145 renameGateway={renameGateway}
146 editGatewayServers={editGatewayServers}
147 editGatewayUsers={editGatewayUsers}
148 deleteGateway={deleteGateway}
149 deletingLogicals={deletingLogicals}
150 deletedLogicals={deletedLogicals}
160 export default GatewayRow;