From f7eccc70ad035481c5b5a4f7092c0ac3ec932bb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20W=C3=B3jcik?= Date: Thu, 24 Jul 2025 15:38:35 +0200 Subject: [PATCH 1/2] also handle assigned IPs --- .../LocationCardInfo/LocationCardInfo.tsx | 33 ++++++++++++++++++- .../components/LocationCardInfo/style.scss | 28 ++++++++++++++++ .../LocationCardTitle/LocationCardTitle.tsx | 6 ++-- .../components/LocationCardTitle/style.scss | 1 - 4 files changed, 63 insertions(+), 5 deletions(-) diff --git a/src/pages/client/pages/ClientInstancePage/components/LocationsList/components/LocationCardInfo/LocationCardInfo.tsx b/src/pages/client/pages/ClientInstancePage/components/LocationsList/components/LocationCardInfo/LocationCardInfo.tsx index c4395c72..ee2c4662 100644 --- a/src/pages/client/pages/ClientInstancePage/components/LocationsList/components/LocationCardInfo/LocationCardInfo.tsx +++ b/src/pages/client/pages/ClientInstancePage/components/LocationsList/components/LocationCardInfo/LocationCardInfo.tsx @@ -1,8 +1,12 @@ import './style.scss'; import dayjs from 'dayjs'; +import { useMemo } from 'react'; import { useI18nContext } from '../../../../../../../../i18n/i18n-react'; +import { FloatingMenu } from '../../../../../../../../shared/defguard-ui/components/Layout/FloatingMenu/FloatingMenu'; +import { FloatingMenuProvider } from '../../../../../../../../shared/defguard-ui/components/Layout/FloatingMenu/FloatingMenuProvider'; +import { FloatingMenuTrigger } from '../../../../../../../../shared/defguard-ui/components/Layout/FloatingMenu/FloatingMenuTrigger'; import { CommonWireguardFields, Connection } from '../../../../../../types'; type Props = { @@ -28,8 +32,35 @@ export const LocationCardInfo = ({ location, connection }: Props) => {
-

{location?.address}

+
); }; + +type AssignedIpProps = { + // comma-separated list of addresses + address: string; +}; + +const AssignedIp = ({ address }: AssignedIpProps) => { + // split into separate addreses to show in tooltip + const addresses = useMemo(() => address.split(','), [address]); + + return ( + + +
+

{address}

+
+
+ +
    + {addresses.map((d) => ( +
  • {d}
  • + ))} +
+
+
+ ); +}; diff --git a/src/pages/client/pages/ClientInstancePage/components/LocationsList/components/LocationCardInfo/style.scss b/src/pages/client/pages/ClientInstancePage/components/LocationsList/components/LocationCardInfo/style.scss index 4dc78022..e3b77e15 100644 --- a/src/pages/client/pages/ClientInstancePage/components/LocationsList/components/LocationCardInfo/style.scss +++ b/src/pages/client/pages/ClientInstancePage/components/LocationsList/components/LocationCardInfo/style.scss @@ -23,4 +23,32 @@ color: var(--text-body-primary); text-align: left; } + + & > .assigned-ip-container { + cursor: help; + + & > label { + text-align: right; + } + + & > p { + @include typography(app-button-xl); + + color: var(--text-body-primary); + text-align: right; + max-width: 120px; + overflow: hidden; + text-overflow: ellipsis; + } + } +} + +.location-card-info-ip { + justify-items: flex-end; + justify-content: flex-end; + align-items: flex-end; + + & > label { + text-align: right; + } } diff --git a/src/pages/client/pages/ClientInstancePage/components/LocationsList/components/LocationCardTitle/LocationCardTitle.tsx b/src/pages/client/pages/ClientInstancePage/components/LocationsList/components/LocationCardTitle/LocationCardTitle.tsx index 8a297f46..80a623f5 100644 --- a/src/pages/client/pages/ClientInstancePage/components/LocationsList/components/LocationCardTitle/LocationCardTitle.tsx +++ b/src/pages/client/pages/ClientInstancePage/components/LocationsList/components/LocationCardTitle/LocationCardTitle.tsx @@ -24,17 +24,17 @@ export const LocationCardTitle = ({ location }: Props) => { {location?.name} - + ); }; type AddressBadgeProps = { // comma-separated list of addresses - addresses: string; + address: string; }; -const AddressBadge = ({ addresses: address }: AddressBadgeProps) => { +const AddressBadge = ({ address }: AddressBadgeProps) => { // split into separate addreses to show in tooltip const addresses = useMemo(() => address.split(','), [address]); diff --git a/src/pages/client/pages/ClientInstancePage/components/LocationsList/components/LocationCardTitle/style.scss b/src/pages/client/pages/ClientInstancePage/components/LocationsList/components/LocationCardTitle/style.scss index 7b5c7cde..272e63f7 100644 --- a/src/pages/client/pages/ClientInstancePage/components/LocationsList/components/LocationCardTitle/style.scss +++ b/src/pages/client/pages/ClientInstancePage/components/LocationsList/components/LocationCardTitle/style.scss @@ -32,7 +32,6 @@ } & > .addresses-badge-container { - position: relative; cursor: help; & > .client-addresses { From d21370e73c46500f52913482449a16f0b8820c69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20W=C3=B3jcik?= Date: Thu, 24 Jul 2025 16:01:40 +0200 Subject: [PATCH 2/2] add clipboard translation --- src/i18n/en/index.ts | 5 +++++ src/i18n/i18n-types.ts | 28 ++++++++++++++++++++++++++++ src/shared/hooks/useClipboard.ts | 11 +++++++---- 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/src/i18n/en/index.ts b/src/i18n/en/index.ts index 59616332..81b50df7 100644 --- a/src/i18n/en/index.ts +++ b/src/i18n/en/index.ts @@ -55,6 +55,11 @@ const en = { deadConDropped: 'Detected that the {con_type: string} {interface_name: string} has disconnected, trying to reconnect...', noCookie: 'No defguard_proxy set-cookie received', + insecureContext: 'Context is not secure.', + clipboard: { + error: 'Clipboard is not accessible.', + success: 'Content copied to clipboard.', + }, }, }, components: { diff --git a/src/i18n/i18n-types.ts b/src/i18n/i18n-types.ts index 265a1cd4..da6d2feb 100644 --- a/src/i18n/i18n-types.ts +++ b/src/i18n/i18n-types.ts @@ -170,6 +170,20 @@ type RootTranslation = { * N​o​ ​d​e​f​g​u​a​r​d​_​p​r​o​x​y​ ​s​e​t​-​c​o​o​k​i​e​ ​r​e​c​e​i​v​e​d */ noCookie: string + /** + * C​o​n​t​e​x​t​ ​i​s​ ​n​o​t​ ​s​e​c​u​r​e​. + */ + insecureContext: string + clipboard: { + /** + * C​l​i​p​b​o​a​r​d​ ​i​s​ ​n​o​t​ ​a​c​c​e​s​s​i​b​l​e​. + */ + error: string + /** + * C​o​n​t​e​n​t​ ​c​o​p​i​e​d​ ​t​o​ ​c​l​i​p​b​o​a​r​d​. + */ + success: string + } } } components: { @@ -1827,6 +1841,20 @@ export type TranslationFunctions = { * No defguard_proxy set-cookie received */ noCookie: () => LocalizedString + /** + * Context is not secure. + */ + insecureContext: () => LocalizedString + clipboard: { + /** + * Clipboard is not accessible. + */ + error: () => LocalizedString + /** + * Content copied to clipboard. + */ + success: () => LocalizedString + } } } components: { diff --git a/src/shared/hooks/useClipboard.ts b/src/shared/hooks/useClipboard.ts index 964a8b4c..0d257d26 100644 --- a/src/shared/hooks/useClipboard.ts +++ b/src/shared/hooks/useClipboard.ts @@ -1,8 +1,11 @@ import { useCallback } from 'react'; +import { useI18nContext } from '../../i18n/i18n-react'; import { useToaster } from '../defguard-ui/hooks/toasts/useToaster'; export const useClipboard = () => { + const { LL } = useI18nContext(); + const toaster = useToaster(); const writeToClipboard = useCallback( @@ -13,17 +16,17 @@ export const useClipboard = () => { if (customMessage) { toaster.success(customMessage); } else { - toaster.success('Content copied to clipboard'); + toaster.success(LL.common.messages.clipboard.success()); } } catch (e) { - toaster.error('Writing to clipboard failed !'); + toaster.error(LL.common.messages.clipboard.error()); console.error(e); } } else { - toaster.warning('Cannot access clipboard in insecure contexts'); + toaster.warning(LL.common.messages.insecureContext()); } }, - [toaster], + [LL.common.messages, toaster], ); return {