Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 19 additions & 7 deletions static/app/views/settings/components/settingsPageHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import {Fragment} from 'react';
import styled from '@emotion/styled';

import * as Layout from 'sentry/components/layouts/thirds';
import {useRoutes} from 'sentry/utils/useRoutes';
import {TopBar} from 'sentry/views/navigation/topBar';
import {useHasPageFrameFeature} from 'sentry/views/navigation/useHasPageFrameFeature';
import {BreadcrumbTitle} from 'sentry/views/settings/components/settingsBreadcrumb/breadcrumbTitle';

type Props = {
/**
Expand Down Expand Up @@ -42,12 +45,27 @@ function UnstyledSettingsPageHeader({
noTitleStyles = false,
...props
}: Props) {
const routes = useRoutes();
const hasPageFrame = useHasPageFrameFeature();
// If Header is narrow, use align-items to center <Action>.
// Otherwise, use a fixed margin to prevent an odd alignment.
// This is needed as Actions could be a button or a dropdown.
const isNarrow = !subtitle;

// In page frame mode the breadcrumb in the TopBar serves as the page title.
// Sync the last breadcrumb label with the actual page title and skip
// rendering the title heading so it doesn't appear twice.
if (hasPageFrame) {
return (
<Fragment>
{typeof title === 'string' && <BreadcrumbTitle routes={routes} title={title} />}
{action && <TopBar.Slot name="actions">{action}</TopBar.Slot>}
{body && <BodyWrapper>{body}</BodyWrapper>}
{tabs && <TabsWrapper>{tabs}</TabsWrapper>}
</Fragment>
);
}

return (
<div {...props}>
<TitleAndActions isNarrow={isNarrow}>
Expand All @@ -60,13 +78,7 @@ function UnstyledSettingsPageHeader({
</Title>
)}
</TitleWrapper>
{action ? (
hasPageFrame ? (
<TopBar.Slot name="actions">{action}</TopBar.Slot>
) : (
<Action isNarrow={isNarrow}>{action}</Action>
)
) : null}
{action && <Action isNarrow={isNarrow}>{action}</Action>}
</TitleAndActions>

{body && <BodyWrapper>{body}</BodyWrapper>}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {useApi} from 'sentry/utils/useApi';
import {useNavigate} from 'sentry/utils/useNavigate';
import {useOrganization} from 'sentry/utils/useOrganization';
import {useProjects} from 'sentry/utils/useProjects';
import {useHasPageFrameFeature} from 'sentry/views/navigation/useHasPageFrameFeature';
import {SettingsPageHeader} from 'sentry/views/settings/components/settingsPageHeader';
import {TextBlock} from 'sentry/views/settings/components/text/textBlock';
import {OrganizationPermissionAlert} from 'sentry/views/settings/organization/organizationPermissionAlert';
Expand All @@ -36,6 +37,7 @@ export default function OrganizationGeneralSettings() {
const organization = useOrganization();
const {projects} = useProjects();
const navigate = useNavigate();
const hasPageFrameFeature = useHasPageFrameFeature();

const removeConfirmMessage = (
<Fragment>
Expand Down Expand Up @@ -113,7 +115,7 @@ export default function OrganizationGeneralSettings() {
<div>
<SettingsPageHeader
title={t('Organization Settings')}
action={organizationRegionInfo}
action={hasPageFrameFeature ? undefined : organizationRegionInfo}
/>
<OrganizationPermissionAlert />

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ import {
setFieldErrors,
useScrapsForm,
} from '@sentry/scraps/form';
import {Container, Flex} from '@sentry/scraps/layout';
import {Container, Flex, Stack} from '@sentry/scraps/layout';
import {ExternalLink} from '@sentry/scraps/link';
import {Text} from '@sentry/scraps/text';

import {addErrorMessage} from 'sentry/actionCreators/indicator';
import {updateOrganization} from 'sentry/actionCreators/organizations';
Expand All @@ -30,10 +31,13 @@ import {ConfigStore} from 'sentry/stores/configStore';
import type {MembershipSettingsProps} from 'sentry/types/hooks';
import type {Organization} from 'sentry/types/organization';
import {fetchMutation, useMutation} from 'sentry/utils/queryClient';
import {getRegionDataFromOrganization, getRegions} from 'sentry/utils/regions';
import {RequestError} from 'sentry/utils/requestError/requestError';
import {slugify} from 'sentry/utils/slugify';
import {useMembers} from 'sentry/utils/useMembers';
import {useOrganization} from 'sentry/utils/useOrganization';
import {useHasPageFrameFeature} from 'sentry/views/navigation/useHasPageFrameFeature';
import {DATA_STORAGE_DOCS_LINK} from 'sentry/views/organizationCreate';

const HookCodecovSettingsLink = HookOrDefault({
hookName: 'component:codecov-integration-settings-link',
Expand Down Expand Up @@ -415,10 +419,13 @@ function OrganizationMembershipSettingsBase({
export function OrganizationSettingsForm({initialData, onSave}: Props) {
const organization = useOrganization();
const endpoint = `/organizations/${organization.slug}/`;
const hasPageFrameFeature = useHasPageFrameFeature();

const access = useMemo(() => new Set(organization.access), [organization]);
const hasWriteAccess = access.has('org:write');
const hasGenAiFeatureFlag = organization.features.includes('gen-ai-features');
const regionData =
getRegions().length > 1 ? getRegionDataFromOrganization(organization) : null;

const aiEnabled = hasGenAiFeatureFlag ? (initialData.hideAiFeatures ?? false) : false;

Expand Down Expand Up @@ -545,6 +552,23 @@ export function OrganizationSettingsForm({initialData, onSave}: Props) {
)}
</AutoSaveForm>

{/* Data Storage Region — read-only, only shown when multiple regions exist */}
{hasPageFrameFeature && regionData && (
<Flex direction="row" gap="xl" align="center" justify="between" flexGrow={1}>
<Stack width="50%" gap="xs">
<Text>{t('Data Storage Region')}</Text>
<Text size="sm" variant="muted">
{tct("Your organization's data storage location. [link:Learn More]", {
link: <ExternalLink href={DATA_STORAGE_DOCS_LINK} />,
})}
</Text>
</Stack>
<Container flexGrow={1}>
<Text>{`${regionData.flag} ${regionData.displayName}`}</Text>
</Container>
</Flex>
)}

{/* Early Adopter — hidden for self-hosted errors-only */}
{!ConfigStore.get('isSelfHostedErrorsOnly') && (
<AutoSaveForm
Expand Down
Loading