+
+ {t('common.trustedDevices_title')}
+
+
{t('common.trustedDevicesHint')}
+
+ {!isFetched && isFetching &&
}
+
+ {isFetched && items.length === 0 &&
}
+
+ {items.length > 0 && (
+
+ {items.map((device) => {
+ const isDeleting = deletingIds.includes(device.id);
+ const primary = buildPrimaryLabel(device, t);
+ const secondary = buildSecondaryLabel(device);
+ return (
+
+
+
+
+
+
+ {primary}
+
+ {secondary && (
+
+ {secondary}
+
+ )}
+
+
+ {t('common.lastUsed')}: {formatLastUsed(device.lastUsedAt, t)}
+
+ {' · '}
+
+ {t('common.expires')}: {new Date(device.expiresAt).toLocaleDateString()}
+
+
+
+
+ );
+ })}
+
+ )}
+
+ );
+});
+
+export default TrustedDevicesSection;
diff --git a/client/src/components/users/UserSettingsModal/SecurityPane/TrustedDevicesSection.module.scss b/client/src/components/users/UserSettingsModal/SecurityPane/TrustedDevicesSection.module.scss
new file mode 100644
index 00000000..096a3931
--- /dev/null
+++ b/client/src/components/users/UserSettingsModal/SecurityPane/TrustedDevicesSection.module.scss
@@ -0,0 +1,45 @@
+/*!
+ * Copyright (c) 2024 PLANKA Software GmbH
+ * Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
+ */
+
+:global(#app) {
+ .wrapper {
+ margin-top: 24px;
+ }
+
+ .heading {
+ margin-bottom: 8px !important;
+ }
+
+ .hint {
+ color: var(--text-tertiary);
+ margin-bottom: 12px;
+ }
+
+ .list {
+ margin: 0 !important;
+ }
+
+ .deviceHeader {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ }
+
+ .devicePrimary {
+ font-weight: 600;
+ }
+
+ .deviceSecondary {
+ color: var(--text-secondary) !important;
+ font-size: 13px;
+ margin-top: 2px !important;
+ }
+
+ .meta {
+ color: var(--text-tertiary) !important;
+ font-size: 12px;
+ margin-top: 4px;
+ }
+}
diff --git a/client/src/components/users/UserSettingsModal/SecurityPane/index.js b/client/src/components/users/UserSettingsModal/SecurityPane/index.js
new file mode 100644
index 00000000..1023f27c
--- /dev/null
+++ b/client/src/components/users/UserSettingsModal/SecurityPane/index.js
@@ -0,0 +1,8 @@
+/*!
+ * Copyright (c) 2024 PLANKA Software GmbH
+ * Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
+ */
+
+import SecurityPane from './SecurityPane';
+
+export default SecurityPane;
diff --git a/client/src/components/users/UserSettingsModal/UserSettingsModal.jsx b/client/src/components/users/UserSettingsModal/UserSettingsModal.jsx
index 6f4c12b8..7ab14165 100644
--- a/client/src/components/users/UserSettingsModal/UserSettingsModal.jsx
+++ b/client/src/components/users/UserSettingsModal/UserSettingsModal.jsx
@@ -13,6 +13,7 @@ import { useClosableModal } from '../../../hooks';
import AccountPane from './AccountPane';
import PreferencesPane from './PreferencesPane';
import NotificationsPane from './NotificationsPane';
+import SecurityPane from './SecurityPane';
const UserSettingsModal = React.memo(() => {
const dispatch = useDispatch();
@@ -43,6 +44,12 @@ const UserSettingsModal = React.memo(() => {
}),
render: () =>