Add shared credential envelope infrastructure

This commit is contained in:
2026-07-28 19:32:41 +02:00
parent 3f5870281a
commit 13bc3d3b4e
17 changed files with 2094 additions and 4 deletions
+29 -3
View File
@@ -16,6 +16,7 @@ import { useUnsavedChanges, useUnsavedDraftGuard } from "../../components/Unsave
import { usePlatformUiCapabilities, usePlatformUiCapability } from "../../platform/ModuleContext";
import { hasAnyScope, hasScope } from "../../utils/permissions";
import { usePlatformLanguage } from "../../i18n/LanguageContext";
import CredentialEnvelopeManager from "../../components/CredentialEnvelopeManager";
type SettingsSection = "profile" | "mail-profiles" | "file-connectors" | "interface" | "workspace" | "local-connection" | string;
@@ -33,14 +34,15 @@ const UI_THEME_OPTIONS: Array<{ value: UserUiTheme; label: string }> = [
{ value: "dark", label: "i18n:govoplan-core.dark_theme.164a90d9" }
];
function settingsGroups(canUseMailProfiles: boolean, canUseFileConnectors: boolean, contributedSections: SettingsSectionContribution[]): ModuleSubnavGroup<SettingsSection>[] {
function settingsGroups(canUseMailProfiles: boolean, canUseFileConnectors: boolean, canUseCredentials: boolean, contributedSections: SettingsSectionContribution[]): ModuleSubnavGroup<SettingsSection>[] {
const groups: ModuleSubnavGroup<SettingsSection>[] = [
{
title: "i18n:govoplan-core.account.f967543b",
items: [
{ id: "profile", label: "i18n:govoplan-core.my_profile.2f3df0a9" },
...(canUseMailProfiles ? [{ id: "mail-profiles" as const, label: "i18n:govoplan-core.mail_profiles.8a8018b7" }] : []),
...(canUseFileConnectors ? [{ id: "file-connectors" as const, label: "i18n:govoplan-core.file_connections.1e362326" }] : [])]
...(canUseFileConnectors ? [{ id: "file-connectors" as const, label: "i18n:govoplan-core.file_connections.1e362326" }] : []),
...(canUseCredentials ? [{ id: "credentials" as const, label: "i18n:govoplan-core.credentials.dd097a22" }] : [])]
},
{
@@ -102,11 +104,19 @@ export default function SettingsPage({
"admin:policies:write"
]);
const canUseFileConnectors = Boolean(FileConnectorScopeManager) && hasAnyScope(auth, ["files:file:read", "files:file:admin", "admin:settings:read", "admin:settings:write"]);
const canUseCredentials = hasAnyScope(auth, [
"access:credential:read",
"access:credential:write",
"access:credential:manage_own",
"mail:secret:manage_own",
"admin:settings:read",
"admin:settings:write"
]);
const contributedSections = useMemo(
() => settingsSectionCapabilities.flatMap((capability) => capability.sections ?? []).filter((section) => canUseSettingsContribution(auth, section)),
[auth, settingsSectionCapabilities]
);
const settingsSubnav = useMemo(() => settingsGroups(canUseMailProfiles, canUseFileConnectors, contributedSections), [canUseFileConnectors, canUseMailProfiles, contributedSections]);
const settingsSubnav = useMemo(() => settingsGroups(canUseMailProfiles, canUseFileConnectors, canUseCredentials, contributedSections), [canUseCredentials, canUseFileConnectors, canUseMailProfiles, contributedSections]);
const availableSectionIds = useMemo(() => new Set(settingsSubnav.flatMap((group) => group.items.flatMap((item) => "id" in item ? [item.id] : []))), [settingsSubnav]);
const requestedSection = searchParams.get("section");
const active: SettingsSection = settingsSectionAvailable(availableSectionIds, requestedSection) ? requestedSection : "interface";
@@ -343,6 +353,21 @@ export default function SettingsPage({
}
{active === "credentials" &&
<CredentialEnvelopeManager
settings={settings}
scopeType="user"
scopeId={auth.user.id}
title="My reusable credentials"
canWrite={hasAnyScope(auth, [
"access:credential:write",
"access:credential:manage_own",
"mail:secret:manage_own",
"admin:settings:write"
])} />
}
{active === "interface" &&
<div className="dashboard-grid settings-dashboard-grid">
<Card title="i18n:govoplan-core.interface_preferences.b82b39a7">
@@ -505,6 +530,7 @@ function sectionOrder(sectionId: string, contributedSections: SettingsSectionCon
profile: 10,
"mail-profiles": 20,
"file-connectors": 30,
"credentials": 40,
interface: 10,
workspace: 20,
"local-connection": 30