From f434a1f7c150161897016b8feda5c0ba3173b1a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20=C5=9Al=C4=99zak?= Date: Thu, 12 Mar 2026 12:51:33 +0100 Subject: [PATCH] ui fixes --- web/messages/en/profile.json | 1 + web/package.json | 6 +- web/pnpm-lock.yaml | 79 ++--- web/src/pages/CERulePage/CERulePage.tsx | 276 +++++++++--------- web/src/pages/CERulePage/style.scss | 41 --- .../ProfileDevicesTable.tsx | 111 +++---- .../components/ProfileDevicesTable/style.scss | 6 + .../components/Navigation/Navigation.tsx | 29 +- .../shared/components/Navigation/style.scss | 14 + .../components/SelectMultiple/style.scss | 1 + 10 files changed, 277 insertions(+), 287 deletions(-) create mode 100644 web/src/pages/user-profile/UserProfilePage/tabs/ProfileDevicesTab/components/ProfileDevicesTable/style.scss diff --git a/web/messages/en/profile.json b/web/messages/en/profile.json index 5acb1af4ed..a77bddf060 100644 --- a/web/messages/en/profile.json +++ b/web/messages/en/profile.json @@ -38,6 +38,7 @@ "profile_devices_col_never_connected": "Never connected", "profile_devices_menu_show_config": "Show configuration", "profile_devices_menu_ip_settings": "Device IP settings", + "profile_devices_tooltip_biometric": "Biometric is enabled for this device", "profile_auth_keys_no_data_title": "You don't have any added keys.", "profile_auth_keys_no_data_subtitle": "To add one, click the button below", "profile_auth_keys_no_data_cta": "Add new key", diff --git a/web/package.json b/web/package.json index 580bbcaadd..87603b8e9e 100644 --- a/web/package.json +++ b/web/package.json @@ -29,7 +29,7 @@ "axios": "^1.13.6", "byte-size": "^9.0.1", "clsx": "^2.1.1", - "dayjs": "^1.11.19", + "dayjs": "^1.11.20", "easy-file-picker": "^1.2.0", "humanize-duration": "^3.33.2", "ipaddr.js": "^2.3.0", @@ -53,8 +53,8 @@ "devDependencies": { "@biomejs/biome": "2.4.6", "@inlang/paraglide-js": "2.14.0", - "@tanstack/devtools-vite": "^0.5.3", - "@tanstack/react-devtools": "^0.9.10", + "@tanstack/devtools-vite": "^0.5.5", + "@tanstack/react-devtools": "^0.9.13", "@tanstack/react-query-devtools": "^5.91.3", "@tanstack/react-router-devtools": "^1.166.7", "@tanstack/router-plugin": "^1.166.7", diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml index aed786dce3..c71736e81c 100644 --- a/web/pnpm-lock.yaml +++ b/web/pnpm-lock.yaml @@ -57,8 +57,8 @@ importers: specifier: ^2.1.1 version: 2.1.1 dayjs: - specifier: ^1.11.19 - version: 1.11.19 + specifier: ^1.11.20 + version: 1.11.20 easy-file-picker: specifier: ^1.2.0 version: 1.2.0 @@ -121,11 +121,11 @@ importers: specifier: 2.4.6 version: 2.4.6 '@tanstack/devtools-vite': - specifier: ^0.5.3 - version: 0.5.3(vite@7.3.1(@types/node@25.4.0)(sass@1.98.0)(tsx@4.21.0)) + specifier: ^0.5.5 + version: 0.5.5(vite@7.3.1(@types/node@25.4.0)(sass@1.98.0)(tsx@4.21.0)) '@tanstack/react-devtools': - specifier: ^0.9.10 - version: 0.9.10(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(solid-js@1.9.9) + specifier: ^0.9.13 + version: 0.9.13(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(solid-js@1.9.9) '@tanstack/react-query-devtools': specifier: ^5.91.3 version: 5.91.3(@tanstack/react-query@5.90.21(react@19.2.4))(react@19.2.4) @@ -386,8 +386,8 @@ packages: peerDependencies: postcss-selector-parser: ^7.1.1 - '@emnapi/runtime@1.8.1': - resolution: {integrity: sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==} + '@emnapi/runtime@1.9.0': + resolution: {integrity: sha512-QN75eB0IH2ywSpRpNddCRfQIhmJYBCJ1x5Lb3IscKAL8bMnVAKnRg8dCoXbHzVLLH7P38N2Z3mtulB7W0J0FKw==} '@esbuild/aix-ppc64@0.27.3': resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==} @@ -1190,9 +1190,10 @@ packages: resolution: {integrity: sha512-cNnJ89Q021Zf883rlbBTfsaxTfi2r73/qejGtyTa7ksErF3hyDyAq1aTbo5crK9dAL7zSHh9viKY1BtMls1QOA==} engines: {node: '>=18'} - '@tanstack/devtools-event-client@0.4.1': - resolution: {integrity: sha512-GRxmPw4OHZ2oZeIEUkEwt/NDvuEqzEYRAjzUVMs+I0pd4C7k1ySOiuJK2CqF+K/yEAR3YZNkW3ExrpDarh9Vwg==} + '@tanstack/devtools-event-client@0.4.3': + resolution: {integrity: sha512-OZI6QyULw0FI0wjgmeYzCIfbgPsOEzwJtCpa69XrfLMtNXLGnz3d/dIabk7frg0TmHo+Ah49w5I4KC7Tufwsvw==} engines: {node: '>=18'} + hasBin: true '@tanstack/devtools-ui@0.5.0': resolution: {integrity: sha512-nNZ14054n31fWB61jtWhZYLRdQ3yceCE3G/RINoINUB0RqIGZAIm9DnEDwOTAOfqt4/a/D8vNk8pJu6RQUp74g==} @@ -1200,15 +1201,17 @@ packages: peerDependencies: solid-js: '>=1.9.7' - '@tanstack/devtools-vite@0.5.3': - resolution: {integrity: sha512-S7VK2GthBrEkto0UVODx31IAvxTFUK0RGH6aZEZixsohYTytTdrwcLmPKEREwFrRN8Qc2mIqfBhENPbRG1RFXA==} + '@tanstack/devtools-vite@0.5.5': + resolution: {integrity: sha512-vtXZ3LipEknVg0X6yejgWzZXIJSrvlBMWB1lDJKW6GWztEV+uCAoqLAJS+Jk3c2mTXp/u+aI/jfE0gqT4zHTNw==} engines: {node: '>=18'} + hasBin: true peerDependencies: vite: ^6.0.0 || ^7.0.0 - '@tanstack/devtools@0.10.11': - resolution: {integrity: sha512-Nk1rHsv6S/5Krzz+uL5jldW9gKb3s6rkkVl1L9oVYHNClKthbrk2hGef4Di6yj449QIOqVExTdDujjQ4roq1dg==} + '@tanstack/devtools@0.10.14': + resolution: {integrity: sha512-bg1e0PyjmMMsc9VSOGb9etu15CpFdAwlQ5DD2xS6N93iTPgCPWXiZQFZygrEDoKnnx1x7BM6QTaiukizaejgSA==} engines: {node: '>=18'} + hasBin: true peerDependencies: solid-js: '>=1.9.7' @@ -1229,8 +1232,8 @@ packages: '@tanstack/query-devtools@5.93.0': resolution: {integrity: sha512-+kpsx1NQnOFTZsw6HAFCW3HkKg0+2cepGtAWXjiiSOJJ1CtQpt72EE2nyZb+AjAbLRPoeRmPJ8MtQd8r8gsPdg==} - '@tanstack/react-devtools@0.9.10': - resolution: {integrity: sha512-WKFU8SXN7DLM7EyD2aUAhmk7JGNeONWhQozAH2qDCeOjyc3Yzxs4BxeoyKMYyEiX/eCp8ZkMTf/pJX6vm2LGeA==} + '@tanstack/react-devtools@0.9.13': + resolution: {integrity: sha512-O9YXTEe2dlnw2pPNKFZ4Wk7zC4qrDvc0SAALKfMVedeZ2Dyd0LEJUabYS6GPm+DmnrBhc7nJx6Zqc9aDjFrj4g==} engines: {node: '>=18'} peerDependencies: '@types/react': '>=16.8' @@ -1556,8 +1559,8 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} - caniuse-lite@1.0.30001777: - resolution: {integrity: sha512-tmN+fJxroPndC74efCdp12j+0rk0RHwV5Jwa1zWaFVyw2ZxAuPeG8ZgWC3Wz7uSjT3qMRQ5XHZ4COgQmsCMJAQ==} + caniuse-lite@1.0.30001778: + resolution: {integrity: sha512-PN7uxFL+ExFJO61aVmP1aIEG4i9whQd4eoSCebav62UwDyp5OHh06zN4jqKSMePVgxHifCw1QJxdRkA1Pisekg==} ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} @@ -1694,8 +1697,8 @@ packages: resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} engines: {node: '>=12'} - dayjs@1.11.19: - resolution: {integrity: sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==} + dayjs@1.11.20: + resolution: {integrity: sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==} debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} @@ -1746,8 +1749,8 @@ packages: easy-file-picker@1.2.0: resolution: {integrity: sha512-GJxOW5s+g/pBr8Ha86a768yx0UZ6fYw+iAOrxK5HOzQ8q9hZxEJF0C8ztdAsH0mcze58FSpzv/d9flRCAuUKHg==} - electron-to-chromium@1.5.307: - resolution: {integrity: sha512-5z3uFKBWjiNR44nFcYdkcXjKMbg5KXNdciu7mhTPo9tB7NbqSNP2sSnGR+fqknZSCwKkBN+oxiiajWs4dT6ORg==} + electron-to-chromium@1.5.313: + resolution: {integrity: sha512-QBMrTWEf00GXZmJyx2lbYD45jpI3TUFnNIzJ5BBc8piGUDwMPa1GV6HJWTZVvY/eiN3fSopl7NRbgGp9sZ9LTA==} emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -3146,7 +3149,7 @@ snapshots: dependencies: postcss-selector-parser: 7.1.1 - '@emnapi/runtime@1.8.1': + '@emnapi/runtime@1.9.0': dependencies: tslib: 2.8.1 optional: true @@ -3338,7 +3341,7 @@ snapshots: '@img/sharp-wasm32@0.34.5': dependencies: - '@emnapi/runtime': 1.8.1 + '@emnapi/runtime': 1.9.0 optional: true '@img/sharp-win32-arm64@0.34.5': @@ -3720,7 +3723,7 @@ snapshots: '@tanstack/devtools-client@0.0.6': dependencies: - '@tanstack/devtools-event-client': 0.4.1 + '@tanstack/devtools-event-client': 0.4.3 '@tanstack/devtools-event-bus@0.4.1': dependencies: @@ -3729,18 +3732,18 @@ snapshots: - bufferutil - utf-8-validate - '@tanstack/devtools-event-client@0.4.1': {} + '@tanstack/devtools-event-client@0.4.3': {} '@tanstack/devtools-ui@0.5.0(csstype@3.2.3)(solid-js@1.9.9)': dependencies: clsx: 2.1.1 - dayjs: 1.11.19 + dayjs: 1.11.20 goober: 2.1.18(csstype@3.2.3) solid-js: 1.9.9 transitivePeerDependencies: - csstype - '@tanstack/devtools-vite@0.5.3(vite@7.3.1(@types/node@25.4.0)(sass@1.98.0)(tsx@4.21.0))': + '@tanstack/devtools-vite@0.5.5(vite@7.3.1(@types/node@25.4.0)(sass@1.98.0)(tsx@4.21.0))': dependencies: '@babel/core': 7.29.0 '@babel/generator': 7.29.1 @@ -3758,7 +3761,7 @@ snapshots: - supports-color - utf-8-validate - '@tanstack/devtools@0.10.11(csstype@3.2.3)(solid-js@1.9.9)': + '@tanstack/devtools@0.10.14(csstype@3.2.3)(solid-js@1.9.9)': dependencies: '@solid-primitives/event-listener': 2.4.5(solid-js@1.9.9) '@solid-primitives/keyboard': 1.3.5(solid-js@1.9.9) @@ -3776,7 +3779,7 @@ snapshots: '@tanstack/form-core@1.28.4': dependencies: - '@tanstack/devtools-event-client': 0.4.1 + '@tanstack/devtools-event-client': 0.4.3 '@tanstack/pacer-lite': 0.1.1 '@tanstack/store': 0.9.2 @@ -3788,9 +3791,9 @@ snapshots: '@tanstack/query-devtools@5.93.0': {} - '@tanstack/react-devtools@0.9.10(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(solid-js@1.9.9)': + '@tanstack/react-devtools@0.9.13(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(solid-js@1.9.9)': dependencies: - '@tanstack/devtools': 0.10.11(csstype@3.2.3)(solid-js@1.9.9) + '@tanstack/devtools': 0.10.14(csstype@3.2.3)(solid-js@1.9.9) '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) react: 19.2.4 @@ -4066,7 +4069,7 @@ snapshots: autoprefixer@10.4.27(postcss@8.5.8): dependencies: browserslist: 4.28.1 - caniuse-lite: 1.0.30001777 + caniuse-lite: 1.0.30001778 fraction.js: 5.3.4 picocolors: 1.1.1 postcss: 8.5.8 @@ -4102,8 +4105,8 @@ snapshots: browserslist@4.28.1: dependencies: baseline-browser-mapping: 2.10.0 - caniuse-lite: 1.0.30001777 - electron-to-chromium: 1.5.307 + caniuse-lite: 1.0.30001778 + electron-to-chromium: 1.5.313 node-releases: 2.0.36 update-browserslist-db: 1.2.3(browserslist@4.28.1) @@ -4129,7 +4132,7 @@ snapshots: callsites@3.1.0: {} - caniuse-lite@1.0.30001777: {} + caniuse-lite@1.0.30001778: {} ccount@2.0.1: {} @@ -4246,7 +4249,7 @@ snapshots: d3-timer@3.0.1: {} - dayjs@1.11.19: {} + dayjs@1.11.20: {} debug@4.4.3: dependencies: @@ -4280,7 +4283,7 @@ snapshots: easy-file-picker@1.2.0: {} - electron-to-chromium@1.5.307: {} + electron-to-chromium@1.5.313: {} emoji-regex@8.0.0: {} diff --git a/web/src/pages/CERulePage/CERulePage.tsx b/web/src/pages/CERulePage/CERulePage.tsx index 8e4b93cf2c..76efb24fd4 100644 --- a/web/src/pages/CERulePage/CERulePage.tsx +++ b/web/src/pages/CERulePage/CERulePage.tsx @@ -894,167 +894,151 @@ const Content = ({ rule: initialRule }: Props) => { {isPresent(usersOptions) && ( -
-
- { - setRestrictUsers((current) => !current); - }} - text="Limit access for users" - /> -
+ <> + { + setRestrictUsers((current) => !current); + }} + text="Limit access for users" + /> -
-
- - {(field) => ( - - )} - - - {(field) => ( - + + + {(field) => } + + + + {(field) => ( + + )} + + s.values.deny_all_users === false && restrictUsers} + > + {(open) => ( + + + {isPresent(usersOptions) && ( + + {(field) => ( + {}} + counterText={(counter) => `Users ${counter}`} + editText="Edit users" + modalTitle="Select restricted users" + options={usersOptions} + /> + )} + )} - -
- s.values.deny_all_users === false && restrictUsers} - > - {(open) => ( - - {isPresent(usersOptions) && ( - - {(field) => ( - {}} - counterText={(counter) => `Users ${counter}`} - editText="Edit users" - modalTitle="Select restricted users" - options={usersOptions} - /> - )} - - )} - - )} - -
+
+ )} + -
+ )} {isPresent(groupsOptions) && ( -
-
- { - setRestrictGroups((current) => !current); - }} - text="Limit access for groups" - /> -
+ <> + { + setRestrictGroups((current) => !current); + }} + text="Limit access for groups" + /> -
-
- - {(field) => ( - - )} - - - {(field) => ( - + + + {(field) => } + + + + {(field) => ( + + )} + + s.values.deny_all_groups === false && restrictGroups} + > + {(open) => ( + + + {isPresent(groupsOptions) && ( + + {(field) => ( + {}} + counterText={(counter) => `Groups ${counter}`} + editText="Edit groups" + modalTitle="Select restricted groups" + options={groupsOptions} + /> + )} + )} - -
- s.values.deny_all_groups === false && restrictGroups} - > - {(open) => ( - - {isPresent(groupsOptions) && ( - - {(field) => ( - {}} - counterText={(counter) => `Groups ${counter}`} - editText="Edit groups" - modalTitle="Select restricted groups" - options={groupsOptions} - /> - )} - - )} - - )} - -
+
+ )} + -
+ )} {isPresent(networkDevicesOptions) && ( -
-
- { - setRestrictDevices((current) => !current); - }} - text="Limit access for network devices" - /> -
+ <> + { + setRestrictDevices((current) => !current); + }} + text="Limit access for network devices" + /> -
-
- - {(field) => ( - - )} - - - {(field) => ( - + + + {(field) => ( + + )} + + + + {(field) => ( + + )} + + + s.values.deny_all_network_devices === false && restrictDevices + } + > + {(open) => ( + + + {isPresent(networkDevicesOptions) && ( + + {(field) => ( + {}} + counterText={(counter) => `Network devices ${counter}`} + editText="Edit network devices" + modalTitle="Select restricted network devices" + options={networkDevicesOptions} + /> + )} + )} - -
- - s.values.deny_all_network_devices === false && restrictDevices - } - > - {(open) => ( - - {isPresent(networkDevicesOptions) && ( - - {(field) => ( - {}} - counterText={(counter) => `Network devices ${counter}`} - editText="Edit network devices" - modalTitle="Select restricted network devices" - options={networkDevicesOptions} - /> - )} - - )} - - )} - -
+
+ )} + -
+ )} diff --git a/web/src/pages/CERulePage/style.scss b/web/src/pages/CERulePage/style.scss index bd39d367c9..7e0c4db899 100644 --- a/web/src/pages/CERulePage/style.scss +++ b/web/src/pages/CERulePage/style.scss @@ -75,47 +75,6 @@ } } } - - .restriction-block { - display: flex; - flex-direction: column; - - .fold.folded .fold-content { - padding: 0; - } - - & > .fold { - margin-top: var(--spacing-lg); - } - - & > .fold.folded { - margin-top: 0; - } - } - - .restriction-toggle { - display: flex; - align-items: center; - } - - .restriction-body { - display: flex; - flex-direction: column; - - & > .fold { - margin-top: var(--spacing-md); - } - - & > .fold.folded { - margin-top: 0; - } - } - - .restriction-radio { - display: flex; - flex-direction: column; - gap: var(--spacing-md); - } } .selection-section .item .destination-selection-item { diff --git a/web/src/pages/user-profile/UserProfilePage/tabs/ProfileDevicesTab/components/ProfileDevicesTable/ProfileDevicesTable.tsx b/web/src/pages/user-profile/UserProfilePage/tabs/ProfileDevicesTab/components/ProfileDevicesTable/ProfileDevicesTable.tsx index 197fc9701a..94e85ebcd7 100644 --- a/web/src/pages/user-profile/UserProfilePage/tabs/ProfileDevicesTab/components/ProfileDevicesTable/ProfileDevicesTable.tsx +++ b/web/src/pages/user-profile/UserProfilePage/tabs/ProfileDevicesTab/components/ProfileDevicesTable/ProfileDevicesTable.tsx @@ -1,3 +1,4 @@ +import './style.scss'; import { useMutation } from '@tanstack/react-query'; import { createColumnHelper, @@ -31,6 +32,9 @@ import { TableFlexCell } from '../../../../../../../shared/defguard-ui/component import { TableRowContainer } from '../../../../../../../shared/defguard-ui/components/table/TableRowContainer/TableRowContainer'; import { TableTop } from '../../../../../../../shared/defguard-ui/components/table/TableTop/TableTop'; import { Snackbar } from '../../../../../../../shared/defguard-ui/providers/snackbar/snackbar'; +import { TooltipContent } from '../../../../../../../shared/defguard-ui/providers/tooltip/TooltipContent'; +import { TooltipProvider } from '../../../../../../../shared/defguard-ui/providers/tooltip/TooltipContext'; +import { TooltipTrigger } from '../../../../../../../shared/defguard-ui/providers/tooltip/TooltipTrigger'; import { isPresent } from '../../../../../../../shared/defguard-ui/utils/isPresent'; import { openModal } from '../../../../../../../shared/hooks/modalControls/modalsSubjects'; import { ModalName } from '../../../../../../../shared/hooks/modalControls/modalTypes'; @@ -40,11 +44,18 @@ import { displayDate } from '../../../../../../../shared/utils/displayDate'; import { useUserProfile } from '../../../../hooks/useUserProfilePage'; interface RowData extends UserDevice { - connected_at: string; - connected_ip: string; - network_name: string; + connected_at: string | null; + connected_ip: string | null; + network_name: string | null; } +const displayDateOrNull = (value?: string | number | null): string | null => { + if (isPresent(value)) { + return displayDate(value); + } + return null; +}; + export const ProfileDevicesTable = () => { const devices = useUserProfile((s) => s.devices); @@ -55,16 +66,13 @@ export const ProfileDevicesTable = () => { ['last_connected_at'], ['desc'], ); - const fallbackValue = m.profile_devices_col_never_connected(); const latestConnection = ordered.at(0); const row: RowData = { ...device, - connected_at: latestConnection?.last_connected_at - ? displayDate(latestConnection.last_connected_at) - : fallbackValue, - connected_ip: latestConnection?.last_connected_ip ?? fallbackValue, - network_name: latestConnection?.network_name ?? fallbackValue, + connected_at: displayDateOrNull(latestConnection?.last_connected_at), + connected_ip: latestConnection?.last_connected_ip ?? null, + network_name: latestConnection?.network_name ?? null, }; return row; }); @@ -176,51 +184,45 @@ const DevicesTable = ({ rowData }: { rowData: RowData[] }) => { () => [ columnHelper.accessor('name', { header: m.profile_devices_col_name(), + size: 700, + minSize: 300, + enableSorting: true, cell: (info) => ( - {info.row.original.biometry_enabled && } + {info.row.original.biometry_enabled && ( + + + + + +

{m.profile_devices_tooltip_biometric()}

+
+
+ )} {info.getValue()}
), - enableSorting: true, - meta: { - flex: true, - }, }), columnHelper.accessor('connected_ip', { id: 'public_ip', header: m.profile_devices_col_pub_ip(), enableSorting: false, - size: 350, - cell: (info) => ( - - {info.getValue() ?? m.profile_devices_col_never_connected()} - - ), + minSize: 350, + cell: (info) => CellWithFallback(info.getValue()), }), columnHelper.accessor('network_name', { id: 'connected_through', header: m.profile_devices_col_location(), enableSorting: false, - size: 175, - cell: (info) => ( - - {info.getValue() ?? m.profile_devices_col_never_connected()} - - ), + minSize: 200, + cell: (info) => CellWithFallback(info.getValue()), }), columnHelper.accessor('connected_at', { id: 'connected_at', header: m.profile_devices_col_connected(), enableSorting: false, - size: 175, - cell: (info) => { - return ( - - {info.getValue()} - - ); - }, + minSize: 200, + cell: (info) => CellWithFallback(info.getValue()), }), columnHelper.display({ id: 'edit', @@ -256,24 +258,13 @@ const DevicesTable = ({ rowData }: { rowData: RowData[] }) => { )} - - - {network.device_wireguard_ips.join(', ') ?? - m.profile_devices_col_never_connected()} - - - - - {network.last_connected_ip ?? m.profile_devices_col_never_connected()} - - - - - {!network.last_connected_at && m.profile_devices_col_never_connected()} - {isPresent(network.last_connected_at) && - displayDate(network.last_connected_at)} - - + {CellWithFallback( + network.device_wireguard_ips.length > 0 + ? network.device_wireguard_ips.join(', ') + : null, + )} + {CellWithFallback(network.last_connected_ip)} + {CellWithFallback(displayDateOrNull(network.last_connected_at))} @@ -330,6 +321,7 @@ const DevicesTable = ({ rowData }: { rowData: RowData[] }) => {