Move trust center profile onto the page

Store website, email, and headquarters on the trust center so
public and admin surfaces read branding from one place. Drop the
trust API organization type and wire console, MCP, CLI, and apps
through the updated schema.

Signed-off-by: Bryan Frimin <bryan@probo.com>
This commit is contained in:
Bryan Frimin
2026-07-13 14:17:22 +02:00
parent ec80798243
commit ba53c94bdc
36 changed files with 167 additions and 155 deletions

View File

@@ -44,9 +44,7 @@ const topBarFragment = graphql`
}
currentTrustCenter @required(action: THROW) {
themedLogoUrl
organization {
name
}
title
}
}
`;
@@ -66,7 +64,7 @@ export function TopBar({ queryKey }: TopBarProps) {
const { openSignIn } = useSignInDialog();
const { currentTrustCenter } = data;
const organizationName = currentTrustCenter.organization.name;
const title = currentTrustCenter.title;
const logoUrl = currentTrustCenter.themedLogoUrl ?? undefined;
const slots = topBar();
@@ -81,11 +79,11 @@ export function TopBar({ queryKey }: TopBarProps) {
color="neutral"
radius="small"
src={logoUrl}
fallback={organizationName.charAt(0) || "?"}
fallback={title.charAt(0) || "?"}
className={slots.logo()}
/>
<Text size={2} weight="medium" color="neutral" highContrast className={slots.brandName()}>
{organizationName}
{title}
</Text>
<Text size={2} color="neutral" className={slots.tagline()}>
{t("topBar.tagline")}

View File

@@ -34,9 +34,7 @@ import type { HomePageQuery } from "./__generated__/HomePageQuery.graphql";
export const homePageQuery = graphql`
query HomePageQuery @throwOnFieldError {
currentTrustCenter @required(action: THROW) {
organization {
name
}
title
...TrustCenterContactInfo_trustCenter
...ComplianceFrameworksSection_trustCenter
...SecurityCommitmentsSection_trustCenter
@@ -54,12 +52,12 @@ export function HomePage({ queryRef }: HomePageProps) {
const { t } = useTranslation();
const data = usePreloadedQuery<HomePageQuery>(homePageQuery, queryRef);
const { currentTrustCenter } = data;
const { organization } = currentTrustCenter;
const { title } = currentTrustCenter;
return (
<>
<Hero
title={t("home.heroTitle", { name: organization.name })}
title={t("home.heroTitle", { name: title })}
description={t("home.heroDescription")}
>
<TrustCenterContactInfo trustCenterKey={currentTrustCenter} />

View File

@@ -32,6 +32,7 @@ const updateCompliancePageMutation = graphql`
id
active
searchEngineIndexing
title
description
websiteUrl
email

View File

@@ -25,6 +25,7 @@ import { useFormWithSchema } from "#/hooks/useFormWithSchema";
const compliancePageFragment = graphql`
fragment CompliancePageProfileSection_compliancePageFragment on TrustCenter {
id
title
description
websiteUrl
email
@@ -34,6 +35,7 @@ const compliancePageFragment = graphql`
`;
const profileSchema = z.object({
title: z.string().min(1),
description: z.string().optional(),
websiteUrl: z.string().optional(),
email: z.string().optional(),
@@ -56,6 +58,7 @@ export function CompliancePageProfileSection(props: {
const { formState, handleSubmit, register } = useFormWithSchema(profileSchema, {
defaultValues: {
title: compliancePage.title,
description: compliancePage.description || "",
websiteUrl: compliancePage.websiteUrl || "",
email: compliancePage.email || "",
@@ -70,6 +73,7 @@ export function CompliancePageProfileSection(props: {
variables: {
input: {
trustCenterId: compliancePage.id,
title: data.title,
description: data.description || null,
websiteUrl: data.websiteUrl || null,
email: data.email || null,
@@ -91,6 +95,13 @@ export function CompliancePageProfileSection(props: {
{formState.isSubmitting && <Spinner />}
</div>
<Card padded className="space-y-4">
<Field
{...register("title")}
readOnly={readOnly}
name="title"
label={__("Title")}
placeholder={__("Your company or product name")}
/>
<div>
<Label>{__("Description")}</Label>
<Textarea

View File

@@ -185,7 +185,7 @@ export function CompliancePageVisualIdentitySection(props: CompliancePageVisualI
<div>
<h2 className="text-base font-medium">{__("Visual identity")}</h2>
<p className="text-sm text-txt-tertiary">
{__("Logos displayed on your public compliance page.")}
{__("Square logos displayed on your public compliance page.")}
</p>
</div>
{isUpdating && <Spinner />}
@@ -196,7 +196,7 @@ export function CompliancePageVisualIdentitySection(props: CompliancePageVisualI
<div className="flex-1">
<Label>{__("Logo")}</Label>
<p className="text-sm text-txt-tertiary mb-3">
{__("This logo will be displayed on your public compliance page.")}
{__("Upload a square logo for your public compliance page.")}
</p>
<div className="flex items-center gap-4">
@@ -211,7 +211,7 @@ export function CompliancePageVisualIdentitySection(props: CompliancePageVisualI
</div>
)
: (
<div className="flex h-16 w-28 shrink-0 items-center justify-center rounded-md border border-dashed border-border-solid bg-surface-secondary text-xs text-txt-tertiary">
<div className="flex size-16 shrink-0 items-center justify-center rounded-md border border-dashed border-border-solid bg-surface-secondary text-xs text-txt-tertiary">
{__("No logo")}
</div>
)}
@@ -230,7 +230,7 @@ export function CompliancePageVisualIdentitySection(props: CompliancePageVisualI
</FileButton>
{!currentLogoUrl && (
<p className="text-xs text-txt-tertiary">
{__("PNG, JPG, SVG, or WEBP up to 5MB")}
{__("Square format. PNG, JPG, SVG, or WEBP up to 5MB")}
</p>
)}
</div>
@@ -250,7 +250,7 @@ export function CompliancePageVisualIdentitySection(props: CompliancePageVisualI
<div className="flex-1">
<Label>{__("Dark mode logo")}</Label>
<p className="text-sm text-txt-tertiary mb-3">
{__("This logo will be used when dark mode is enabled.")}
{__("Upload a square logo for use when dark mode is enabled.")}
</p>
<div className="flex items-center gap-4">
@@ -265,7 +265,7 @@ export function CompliancePageVisualIdentitySection(props: CompliancePageVisualI
</div>
)
: (
<div className="flex h-16 w-28 shrink-0 items-center justify-center rounded-md border border-dashed border-border-solid bg-gray-900 text-xs text-txt-tertiary">
<div className="flex size-16 shrink-0 items-center justify-center rounded-md border border-dashed border-border-solid bg-gray-900 text-xs text-txt-tertiary">
{__("No logo")}
</div>
)}
@@ -284,7 +284,7 @@ export function CompliancePageVisualIdentitySection(props: CompliancePageVisualI
</FileButton>
{!currentDarkLogoUrl && (
<p className="text-xs text-txt-tertiary">
{__("PNG, JPG, SVG, or WEBP up to 5MB")}
{__("Square format. PNG, JPG, SVG, or WEBP up to 5MB")}
</p>
)}
</div>

View File

@@ -42,6 +42,9 @@ const compliancePageFragment = graphql`
edges {
node {
id
framework {
id
}
...CompliancePageFrameworkListItem_complianceFramework
}
}
@@ -82,7 +85,7 @@ export function CompliancePageFrameworkList(props: CompliancePageFrameworkListPr
<div className="grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-4">
{edges.map(edge => (
<CompliancePageFrameworkListItem
key={edge.node.id}
key={edge.node.framework.id}
complianceFrameworkKey={edge.node}
compliancePageKey={compliancePage}
onRefetch={handleRefetch}

View File

@@ -233,7 +233,7 @@ export function OrganizationSidebar({
: (
<div className="size-24 rounded-2xl border border-border-mid shadow-mid bg-level-1" />
)}
<h1 className="text-2xl mt-6">{trustCenter.organization.name}</h1>
<h1 className="text-2xl mt-6">{trustCenter.title}</h1>
<p className="text-sm text-txt-secondary mt-1">
{trustCenter.description}
</p>

View File

@@ -24,7 +24,7 @@ import { TrustCenterContext } from "#/providers/TrustCenterProvider";
export function useTrustCenter(): {
id: string;
organization: { name: string };
title: string;
} {
const context = useContext(TrustCenterContext);
if (!context) {

View File

@@ -47,9 +47,7 @@ export const ndaPageQuery = graphql`
id
}
currentTrustCenter @required(action: THROW) {
organization {
name
}
title
nonDisclosureAgreement {
fileName
fileUrl
@@ -246,7 +244,7 @@ export function NDAPage(props: {
__(
"%s requires you to sign an NDA before accessing compliance documents.",
),
trustCenter.organization.name,
trustCenter.title,
)}
</p>
{isMobile && nda?.fileUrl && (

View File

@@ -107,7 +107,7 @@ export function OverviewPage() {
url={getTrustCenterUrl("documents")}
/>
<Subprocessors
organizationName={trustCenter.organization.name}
title={trustCenter.title}
subprocessors={fragment.subprocessors.edges}
url={getTrustCenterUrl("subprocessors")}
/>
@@ -187,11 +187,11 @@ function Documents({
function Subprocessors({
subprocessors,
url,
organizationName,
title,
}: {
subprocessors: OverviewPageFragment$data["subprocessors"]["edges"];
url: string;
organizationName: string;
title: string;
}) {
const { __ } = useTranslate();
if (subprocessors.length === 0) {
@@ -209,7 +209,7 @@ function Subprocessors({
<p className="text-sm text-txt-secondary mb-4">
{sprintf(
__("Third-party subprocessors %s work with:"),
organizationName,
title,
)}
</p>
<Rows className="mb-8 *:py-5">

View File

@@ -45,7 +45,7 @@ export function SubprocessorsPage({ queryRef }: Props) {
<p className="text-sm text-txt-secondary mb-4">
{sprintf(
__("Third-party subprocessors %s work with:"),
data.currentTrustCenter?.organization.name ?? "",
data.currentTrustCenter?.title ?? "",
)}
</p>
<Rows>

View File

@@ -38,9 +38,7 @@ import { OIDCButton } from "./_components/OIDCButton";
export const connectPageQuery = graphql`
query ConnectPageQuery {
currentTrustCenter @required(action: THROW) {
organization @required(action: THROW) {
name
}
title
}
oidcProviders {
...OIDCButtonFragment
@@ -77,7 +75,7 @@ export function ConnectPage(props: {
const safeContinueUrl = useSafeContinueUrl();
const {
currentTrustCenter: { organization },
currentTrustCenter: { title },
oidcProviders,
} = usePreloadedQuery<ConnectPageQuery>(connectPageQuery, queryRef);
@@ -98,7 +96,7 @@ export function ConnectPage(props: {
};
}, [magicLinkSent]);
usePageTitle(__(`Connect to ${organization.name}'s Compliance Page`));
usePageTitle(__(`Connect to ${title}'s Compliance Page`));
const {
handleSubmit: handleSubmitWrapper,
@@ -164,7 +162,7 @@ export function ConnectPage(props: {
<div className="space-y-6 w-full max-w-md mx-auto pt-8">
<div className="space-y-2 text-center">
<h1 className="text-3xl font-bold">
{__(`Connect to ${organization.name}'s Compliance Page`)}
{__(`Connect to ${title}'s Compliance Page`)}
</h1>
<p className="text-txt-tertiary">
{__(

View File

@@ -31,6 +31,7 @@ export const currentTrustGraphQuery = graphql`
currentTrustCenter @required(action: THROW) {
id
slug
title
description
websiteUrl
email
@@ -54,9 +55,6 @@ export const currentTrustGraphQuery = graphql`
status
}
}
organization {
name
}
customLinks(first: 20) {
edges {
node {
@@ -96,9 +94,7 @@ export const currentTrustDocumentsQuery = graphql`
query TrustGraphCurrentDocumentsQuery {
currentTrustCenter {
id
organization {
name
}
title
documents(first: 50) {
edges {
node {
@@ -125,9 +121,7 @@ export const currentTrustSubprocessorsQuery = graphql`
query TrustGraphCurrentSubprocessorsQuery {
currentTrustCenter {
id
organization {
name
}
title
subprocessors(first: 50) {
edges {
node {