diff --git a/static/app/components/profiling/continuousProfileHeader.tsx b/static/app/components/profiling/continuousProfileHeader.tsx
index f675bc1a9b8b5d..63039c9ac0bb2d 100644
--- a/static/app/components/profiling/continuousProfileHeader.tsx
+++ b/static/app/components/profiling/continuousProfileHeader.tsx
@@ -1,4 +1,4 @@
-import {useCallback, useMemo} from 'react';
+import {Fragment, useCallback, useMemo} from 'react';
import styled from '@emotion/styled';
import {LinkButton} from '@sentry/scraps/button';
@@ -53,20 +53,33 @@ export function ContinuousProfileHeader({transaction}: ContinuousProfileHeader)
-
- {hasPageFrameFeature ? (
+ {hasPageFrameFeature ? (
+
+ {transactionTarget && (
+
+
+ {t('Go to Trace')}
+
+
+ )}
{null}
- ) : (
+
+ ) : (
+
- )}
- {transactionTarget && (
-
- {t('Go to Trace')}
-
- )}
-
+ {transactionTarget && (
+
+ {t('Go to Trace')}
+
+ )}
+
+ )}
);
}
diff --git a/static/app/components/profiling/profileHeader.tsx b/static/app/components/profiling/profileHeader.tsx
index 270561785dfbf3..6fd8134888fce6 100644
--- a/static/app/components/profiling/profileHeader.tsx
+++ b/static/app/components/profiling/profileHeader.tsx
@@ -1,4 +1,4 @@
-import {useCallback, useMemo} from 'react';
+import {Fragment, useCallback, useMemo} from 'react';
import styled from '@emotion/styled';
import {LinkButton} from '@sentry/scraps/button';
@@ -91,20 +91,33 @@ function ProfileHeader({transaction, projectId, eventId}: ProfileHeaderProps) {
-
- {hasPageFrameFeature ? (
+ {hasPageFrameFeature ? (
+
+ {transactionTarget && (
+
+
+ {t('Go to Trace')}
+
+
+ )}
{null}
- ) : (
+
+ ) : (
+
- )}
- {transactionTarget && (
-
- {t('Go to Trace')}
-
- )}
-
+ {transactionTarget && (
+
+ {t('Go to Trace')}
+
+ )}
+
+ )}
);
}
diff --git a/static/app/components/workflowEngine/layout/list.tsx b/static/app/components/workflowEngine/layout/list.tsx
index 428ff70ff34e63..936ac954010979 100644
--- a/static/app/components/workflowEngine/layout/list.tsx
+++ b/static/app/components/workflowEngine/layout/list.tsx
@@ -4,6 +4,8 @@ import * as Layout from 'sentry/components/layouts/thirds';
import {NoProjectMessage} from 'sentry/components/noProjectMessage';
import {PageHeadingQuestionTooltip} from 'sentry/components/pageHeadingQuestionTooltip';
import {useOrganization} from 'sentry/utils/useOrganization';
+import {TopBar} from 'sentry/views/navigation/topBar';
+import {useHasPageFrameFeature} from 'sentry/views/navigation/useHasPageFrameFeature';
interface WorkflowEngineListLayoutProps {
actions: React.ReactNode;
@@ -26,6 +28,7 @@ export function WorkflowEngineListLayout({
docsUrl,
}: WorkflowEngineListLayoutProps) {
const organization = useOrganization();
+ const hasPageFrameFeature = useHasPageFrameFeature();
return (
@@ -37,7 +40,11 @@ export function WorkflowEngineListLayout({
- {actions}
+ {hasPageFrameFeature ? (
+ {actions}
+ ) : (
+ {actions}
+ )}
diff --git a/static/app/views/alerts/list/header.tsx b/static/app/views/alerts/list/header.tsx
index 8575b98953b047..66f9e277ba4bb7 100644
--- a/static/app/views/alerts/list/header.tsx
+++ b/static/app/views/alerts/list/header.tsx
@@ -1,3 +1,5 @@
+import {Fragment} from 'react';
+
import {LinkButton} from '@sentry/scraps/button';
import {Grid} from '@sentry/scraps/layout';
import {TabList} from '@sentry/scraps/tabs';
@@ -66,38 +68,63 @@ export function AlertHeader({activeTab}: Props) {
/>
-
-
-
- {t('Create Alert')}
-
- {hasPageFrameFeature ? (
-
- {null}
-
- ) : (
+ {hasPageFrameFeature ? (
+
+
+
+ {t('Create Alert')}
+
+ }
+ aria-label={t('Settings')}
+ />
+
+
+ {null}
+
+
+ ) : (
+
+
+
+ {t('Create Alert')}
+
- )}
- }
- aria-label={t('Settings')}
- />
-
-
+ }
+ aria-label={t('Settings')}
+ />
+
+
+ )}
{alertRulesLink}
diff --git a/static/app/views/alerts/rules/issue/details/ruleDetails.tsx b/static/app/views/alerts/rules/issue/details/ruleDetails.tsx
index 47b2eede8bfbc1..c3cd309cb5fa45 100644
--- a/static/app/views/alerts/rules/issue/details/ruleDetails.tsx
+++ b/static/app/views/alerts/rules/issue/details/ruleDetails.tsx
@@ -45,6 +45,8 @@ import {APIUsageWarningBanner} from 'sentry/views/alerts/rules/APIUsageWarningBa
import {findIncompatibleRules} from 'sentry/views/alerts/rules/issue';
import {ALERT_DEFAULT_CHART_PERIOD} from 'sentry/views/alerts/rules/metric/details/constants';
import {UserSnoozeDeprecationBanner} from 'sentry/views/alerts/rules/userSnoozeDeprecationBanner';
+import {TopBar} from 'sentry/views/navigation/topBar';
+import {useHasPageFrameFeature} from 'sentry/views/navigation/useHasPageFrameFeature';
import {IssueAlertDetailsChart} from './alertChart';
import {AlertRuleIssuesList} from './issuesList';
@@ -78,6 +80,7 @@ const getIssueAlertDetailsQueryKey = ({
];
export default function AlertRuleDetails() {
+ const hasPageFrameFeature = useHasPageFrameFeature();
const queryClient = useQueryClient();
const organization = useOrganization();
const api = useApi();
@@ -422,8 +425,8 @@ export default function AlertRuleDetails() {
{rule.name}
-
-
+ {hasPageFrameFeature ? (
+
{({hasAccess}) => (
{rule.status === 'disabled' ? t('Edit to enable') : t('Edit Rule')}
-
-
+
+ ) : (
+
+
+
+ {({hasAccess}) => (
+
+ )}
+
+ }
+ to={duplicateLink}
+ disabled={rule.status === 'disabled'}
+ >
+ {t('Duplicate')}
+
+ }
+ to={makeAlertsPathname({
+ path: `/rules/${projectSlug}/${ruleId}/`,
+ organization,
+ })}
+ onClick={() =>
+ trackAnalytics('issue_alert_rule_details.edit_clicked', {
+ organization,
+ rule_id: parseInt(ruleId, 10),
+ })
+ }
+ >
+ {rule.status === 'disabled' ? t('Edit to enable') : t('Edit Rule')}
+
+
+
+ )}
diff --git a/static/app/views/alerts/rules/metric/details/header.tsx b/static/app/views/alerts/rules/metric/details/header.tsx
index 33136f361d40b3..90f413fa5634ad 100644
--- a/static/app/views/alerts/rules/metric/details/header.tsx
+++ b/static/app/views/alerts/rules/metric/details/header.tsx
@@ -24,6 +24,8 @@ import {
deprecateTransactionAlerts,
hasEAPAlerts,
} from 'sentry/views/insights/common/utils/hasEAPAlerts';
+import {TopBar} from 'sentry/views/navigation/topBar';
+import {useHasPageFrameFeature} from 'sentry/views/navigation/useHasPageFrameFeature';
type Props = {
hasMetricRuleDetailsError: boolean;
@@ -44,6 +46,7 @@ export function DetailsHeader({
project,
onSnooze,
}: Props) {
+ const hasPageFrameFeature = useHasPageFrameFeature();
const isRuleReady = !!rule && !hasMetricRuleDetailsError;
const ruleTitle = rule && !hasMetricRuleDetailsError ? rule.name : '';
const settingsLink = rule
@@ -111,8 +114,8 @@ export function DetailsHeader({
{ruleTitle}
-
-
+ {hasPageFrameFeature ? (
+
{rule && project && (
{({hasAccess}) => (
@@ -147,8 +150,47 @@ export function DetailsHeader({
} to={settingsLink}>
{t('Edit Rule')}
-
-
+
+ ) : (
+
+
+ {rule && project && (
+
+ {({hasAccess}) => (
+
+ )}
+
+ )}
+ }
+ to={duplicateLink}
+ disabled={deprecateTransactionsAlerts}
+ tooltipProps={{
+ title: deprecateTransactionsAlerts
+ ? hasEAPAlerts(organization)
+ ? t(
+ 'Transaction alerts are being deprecated. Please create Span alerts instead.'
+ )
+ : t('Transaction alerts are being deprecated.')
+ : undefined,
+ }}
+ >
+ {t('Duplicate')}
+
+ } to={settingsLink}>
+ {t('Edit Rule')}
+
+
+
+ )}
);
}
diff --git a/static/app/views/alerts/rules/uptime/details.tsx b/static/app/views/alerts/rules/uptime/details.tsx
index c96e533999faca..d09e3690d8f5bb 100644
--- a/static/app/views/alerts/rules/uptime/details.tsx
+++ b/static/app/views/alerts/rules/uptime/details.tsx
@@ -31,6 +31,8 @@ import {
useDetectorQuery,
} from 'sentry/views/detectors/hooks';
import {useUptimeMonitorSummaries} from 'sentry/views/insights/uptime/utils/useUptimeMonitorSummary';
+import {TopBar} from 'sentry/views/navigation/topBar';
+import {useHasPageFrameFeature} from 'sentry/views/navigation/useHasPageFrameFeature';
import {UptimeDetailsSidebar} from './detailsSidebar';
import {DetailsTimeline} from './detailsTimeline';
@@ -40,6 +42,7 @@ import {UptimeChecksTable} from './uptimeChecksTable';
import {UptimeIssues} from './uptimeIssues';
export default function UptimeAlertDetails() {
+ const hasPageFrameFeature = useHasPageFrameFeature();
const {detectorId, projectId} = useParams<{detectorId: string; projectId: string}>();
const api = useApi();
@@ -149,12 +152,12 @@ export default function UptimeAlertDetails() {
{detector.name}
-
-
+ {hasPageFrameFeature ? (
+
toggleStatus(data)}
- size="sm"
disabled={!canEdit}
{...(canEdit ? {} : {tooltipProps: {title: permissionTooltipText}})}
/>
@@ -170,8 +173,32 @@ export default function UptimeAlertDetails() {
>
{t('Edit Rule')}
-
-
+
+ ) : (
+
+
+ toggleStatus(data)}
+ size="sm"
+ disabled={!canEdit}
+ {...(canEdit ? {} : {tooltipProps: {title: permissionTooltipText}})}
+ />
+ }
+ disabled={!canEdit}
+ tooltipProps={{title: canEdit ? undefined : permissionTooltipText}}
+ to={makeAlertsPathname({
+ path: `/uptime-rules/${project.slug}/${detectorId}/`,
+ organization,
+ })}
+ >
+ {t('Edit Rule')}
+
+
+
+ )}
diff --git a/static/app/views/dashboards/detail.tsx b/static/app/views/dashboards/detail.tsx
index 47aed9a222d246..70b78b042ea79b 100644
--- a/static/app/views/dashboards/detail.tsx
+++ b/static/app/views/dashboards/detail.tsx
@@ -79,6 +79,8 @@ import {
import {convertWidgetToQueryParams} from 'sentry/views/dashboards/widgetBuilder/utils/convertWidgetToBuilderStateParams';
import {getDefaultWidget} from 'sentry/views/dashboards/widgetBuilder/utils/getDefaultWidget';
import {getTopNConvertedDefaultWidgets} from 'sentry/views/dashboards/widgetLibrary/data';
+import {TopBar} from 'sentry/views/navigation/topBar';
+import {useHasPageFrameFeature} from 'sentry/views/navigation/useHasPageFrameFeature';
import {generatePerformanceEventView} from 'sentry/views/performance/data';
import {MetricsDataSwitcher} from 'sentry/views/performance/landing/metricsDataSwitcher';
import {MetricsDataSwitcherAlert} from 'sentry/views/performance/landing/metricsDataSwitcherAlert';
@@ -147,6 +149,7 @@ type Props = {
router: InjectedRouter;
theme: Theme;
children?: React.ReactNode;
+ hasPageFrameFeature?: boolean;
onDashboardUpdate?: (updatedDashboard: DashboardDetails) => void;
storageNamespace?: string;
widgetInterval?: string;
@@ -1154,23 +1157,43 @@ class DashboardDetail extends Component {
/>
-
-
-
+ {this.props.hasPageFrameFeature ? (
+
+
+
+ ) : (
+
+
+
+ )}
)}
@@ -1464,6 +1487,7 @@ export function DashboardDetailWithInjectedProps(
const router = useRouter();
const [chartInterval] = useChartInterval();
const queryClient = useQueryClient();
+ const hasPageFrameFeature = useHasPageFrameFeature();
// Always use the validated chart interval so the UI dropdown and widget
// requests stay in sync. chartInterval is validated against the current page
// filter period (e.g. won't return 1m for a 30d range) and always has a value.
@@ -1484,6 +1508,7 @@ export function DashboardDetailWithInjectedProps(
router={router}
widgetInterval={widgetInterval}
queryClient={queryClient}
+ hasPageFrameFeature={hasPageFrameFeature}
/>
);
}
diff --git a/static/app/views/dashboards/manage/index.tsx b/static/app/views/dashboards/manage/index.tsx
index e64809dd3e8ec0..9530d76c8b13b7 100644
--- a/static/app/views/dashboards/manage/index.tsx
+++ b/static/app/views/dashboards/manage/index.tsx
@@ -1,4 +1,4 @@
-import {useEffect, useMemo, useRef, useState} from 'react';
+import {Fragment, useEffect, useMemo, useRef, useState} from 'react';
import styled from '@emotion/styled';
import * as Sentry from '@sentry/react';
import type {Query} from 'history';
@@ -635,121 +635,228 @@ function ManageDashboards() {
/>
-
-
- {!hasPrebuiltDashboards && (
-
- {t('Show Templates')}
-
-
- )}
-
- {hasPageFrameFeature ? (
-
- {null}
-
- ) : (
+ {hasPageFrameFeature ? (
+
+
+ {!hasPrebuiltDashboards && (
+
+ {t('Show Templates')}
+
+
+ )}
+
+ {({hasFeature: hasAiGenerate}) =>
+ hasAiGenerate && areAiFeaturesAllowed ? (
+
+ {({
+ hasReachedDashboardLimit,
+ isLoading: isLoadingDashboardsLimit,
+ limitMessage,
+ }) => (
+ onCreate(),
+ disabled:
+ hasReachedDashboardLimit ||
+ isLoadingDashboardsLimit,
+ details: limitMessage,
+ },
+ {
+ key: 'create-dashboard-agent',
+ textValue: t('Generate dashboard'),
+ label: (
+
+ {t('Generate dashboard')}
+
+
+ ),
+ onAction: () => onGenerateDashboard(),
+ },
+ ]}
+ trigger={triggerProps => (
+ }
+ >
+ {t('Create Dashboard')}
+
+ )}
+ />
+ )}
+
+ ) : (
+
+ {({
+ hasReachedDashboardLimit,
+ isLoading: isLoadingDashboardsLimit,
+ limitMessage,
+ }) => (
+
+ )}
+
+ )
+ }
+
+
+
+
+
+
+ {null}
+
+
+ ) : (
+
+
+ {!hasPrebuiltDashboards && (
+
+ {t('Show Templates')}
+
+
+ )}
+
- )}
-
- {({hasFeature: hasAiGenerate}) =>
- hasAiGenerate && areAiFeaturesAllowed ? (
-
- {({
- hasReachedDashboardLimit,
- isLoading: isLoadingDashboardsLimit,
- limitMessage,
- }) => (
- onCreate(),
- disabled:
- hasReachedDashboardLimit ||
- isLoadingDashboardsLimit,
- details: limitMessage,
- },
- {
- key: 'create-dashboard-agent',
- textValue: t('Generate dashboard'),
- label: (
-
- {t('Generate dashboard')}
-
-
- ),
- onAction: () => onGenerateDashboard(),
- },
- ]}
- trigger={triggerProps => (
- }
- >
- {t('Create Dashboard')}
-
- )}
- />
- )}
-
- ) : (
-
- {({
- hasReachedDashboardLimit,
- isLoading: isLoadingDashboardsLimit,
- limitMessage,
- }) => (
-
- )}
-
- )
- }
-
-
-
-
-
-
+
+ {({hasFeature: hasAiGenerate}) =>
+ hasAiGenerate && areAiFeaturesAllowed ? (
+
+ {({
+ hasReachedDashboardLimit,
+ isLoading: isLoadingDashboardsLimit,
+ limitMessage,
+ }) => (
+ onCreate(),
+ disabled:
+ hasReachedDashboardLimit ||
+ isLoadingDashboardsLimit,
+ details: limitMessage,
+ },
+ {
+ key: 'create-dashboard-agent',
+ textValue: t('Generate dashboard'),
+ label: (
+
+ {t('Generate dashboard')}
+
+
+ ),
+ onAction: () => onGenerateDashboard(),
+ },
+ ]}
+ trigger={triggerProps => (
+ }
+ >
+ {t('Create Dashboard')}
+
+ )}
+ />
+ )}
+
+ ) : (
+
+ {({
+ hasReachedDashboardLimit,
+ isLoading: isLoadingDashboardsLimit,
+ limitMessage,
+ }) => (
+
+ )}
+
+ )
+ }
+
+
+
+
+
+
+ )}
diff --git a/static/app/views/discover/landing.tsx b/static/app/views/discover/landing.tsx
index b216603d865c34..0d5c4b11cc2f92 100644
--- a/static/app/views/discover/landing.tsx
+++ b/static/app/views/discover/landing.tsx
@@ -30,6 +30,8 @@ import {useNavigate} from 'sentry/utils/useNavigate';
import {useOrganization} from 'sentry/utils/useOrganization';
import {makeDiscoverPathname} from 'sentry/views/discover/pathnames';
import {getSavedQueryWithDataset} from 'sentry/views/discover/savedQuery/utils';
+import {TopBar} from 'sentry/views/navigation/topBar';
+import {useHasPageFrameFeature} from 'sentry/views/navigation/useHasPageFrameFeature';
import QueryList from './queryList';
import {getPrebuiltQueries} from './utils';
@@ -132,6 +134,7 @@ const RENDER_PREBUILT_KEY = 'discover-render-prebuilt';
function DiscoverLanding() {
const navigate = useNavigate();
const organization = useOrganization();
+ const hasPageFrameFeature = useHasPageFrameFeature();
const location = useLocation();
const activeSort = useActiveSort();
const savedSearchQuery = useSavedSearchQuery();
@@ -201,21 +204,39 @@ function DiscoverLanding() {
]}
/>
-
- {
- trackAnalytics('discover_v2.build_new_query', {
- organization,
- });
- }}
- >
- {t('Build a new query')}
-
-
+ {hasPageFrameFeature ? (
+
+ {
+ trackAnalytics('discover_v2.build_new_query', {
+ organization,
+ });
+ }}
+ >
+ {t('Build a new query')}
+
+
+ ) : (
+
+ {
+ trackAnalytics('discover_v2.build_new_query', {
+ organization,
+ });
+ }}
+ >
+ {t('Build a new query')}
+
+
+ )}
diff --git a/static/app/views/discover/results.tsx b/static/app/views/discover/results.tsx
index 7857fa88e69e55..645c4f715a2ae6 100644
--- a/static/app/views/discover/results.tsx
+++ b/static/app/views/discover/results.tsx
@@ -67,7 +67,7 @@ import {
DEFAULT_EVENT_VIEW_MAP,
} from 'sentry/views/discover/results/data';
import ResultsChart from 'sentry/views/discover/results/resultsChart';
-import ResultsHeader from 'sentry/views/discover/results/resultsHeader';
+import {ResultsHeaderWrapper as ResultsHeader} from 'sentry/views/discover/results/resultsHeader';
import {ResultsSearchQueryBuilder} from 'sentry/views/discover/results/resultsSearchQueryBuilder';
import {SampleDataAlert} from 'sentry/views/discover/results/sampleDataAlert';
import Tags from 'sentry/views/discover/results/tags';
diff --git a/static/app/views/discover/results/resultsHeader.tsx b/static/app/views/discover/results/resultsHeader.tsx
index be4157d5b4a964..0dbd7aaf63dfd0 100644
--- a/static/app/views/discover/results/resultsHeader.tsx
+++ b/static/app/views/discover/results/resultsHeader.tsx
@@ -1,4 +1,4 @@
-import {Component, Fragment} from 'react';
+import {Component, Fragment, type ComponentProps} from 'react';
import styled from '@emotion/styled';
import type {Location} from 'history';
@@ -19,11 +19,14 @@ import {EventInputName} from 'sentry/views/discover/eventInputName';
import SavedQueryButtonGroup from 'sentry/views/discover/savedQuery';
import {DatasetSelectorTabs} from 'sentry/views/discover/savedQuery/datasetSelectorTabs';
import {getSavedQueryWithDataset} from 'sentry/views/discover/savedQuery/utils';
+import {TopBar} from 'sentry/views/navigation/topBar';
+import {useHasPageFrameFeature} from 'sentry/views/navigation/useHasPageFrameFeature';
type Props = {
api: Client;
errorCode: number;
eventView: EventView;
+ hasPageFrameFeature: boolean;
location: Location;
organization: Organization;
setSavedQuery: (savedQuery?: SavedQuery) => void;
@@ -123,6 +126,7 @@ class ResultsHeader extends Component {
setSavedQuery,
isHomepage,
splitDecision,
+ hasPageFrameFeature,
} = this.props;
const {savedQuery, loading, homepageQuery} = this.state;
const hasDiscoverQueryFeature = organization.features.includes('discover-query');
@@ -173,31 +177,59 @@ class ResultsHeader extends Component {
)}
{this.renderAuthor()}
-
- = 400 && errorCode < 500}
- updateCallback={() => this.fetchData()}
- yAxis={yAxis}
- isHomepage={isHomepage}
- setHomepageQuery={updatedHomepageQuery => {
- this.setState({
- homepageQuery: getSavedQueryWithDataset(
- updatedHomepageQuery
- ) as SavedQuery,
- });
- if (isHomepage) {
- setSavedQuery(updatedHomepageQuery);
- }
- }}
- homepageQuery={homepageQuery}
- />
-
+ {hasPageFrameFeature ? (
+
+ = 400 && errorCode < 500}
+ updateCallback={() => this.fetchData()}
+ yAxis={yAxis}
+ isHomepage={isHomepage}
+ setHomepageQuery={updatedHomepageQuery => {
+ this.setState({
+ homepageQuery: getSavedQueryWithDataset(
+ updatedHomepageQuery
+ ) as SavedQuery,
+ });
+ if (isHomepage) {
+ setSavedQuery(updatedHomepageQuery);
+ }
+ }}
+ homepageQuery={homepageQuery}
+ />
+
+ ) : (
+
+ = 400 && errorCode < 500}
+ updateCallback={() => this.fetchData()}
+ yAxis={yAxis}
+ isHomepage={isHomepage}
+ setHomepageQuery={updatedHomepageQuery => {
+ this.setState({
+ homepageQuery: getSavedQueryWithDataset(
+ updatedHomepageQuery
+ ) as SavedQuery,
+ });
+ if (isHomepage) {
+ setSavedQuery(updatedHomepageQuery);
+ }
+ }}
+ homepageQuery={homepageQuery}
+ />
+
+ )}
p.theme.space.xs} 0 0 0;
`;
-export default withApi(ResultsHeader);
+const ResultsHeaderWithApi = withApi(ResultsHeader);
+
+type ResultsHeaderWrapperProps = Omit<
+ ComponentProps,
+ 'hasPageFrameFeature'
+>;
+
+function ResultsHeaderWrapper(props: ResultsHeaderWrapperProps) {
+ const hasPageFrameFeature = useHasPageFrameFeature();
+ return ;
+}
+
+export {ResultsHeaderWrapper};
diff --git a/static/app/views/explore/logs/content.tsx b/static/app/views/explore/logs/content.tsx
index 628aca2aa2cc9f..891f73698ad949 100644
--- a/static/app/views/explore/logs/content.tsx
+++ b/static/app/views/explore/logs/content.tsx
@@ -1,3 +1,5 @@
+import {Fragment} from 'react';
+
import {LinkButton} from '@sentry/scraps/button';
import {Grid} from '@sentry/scraps/layout';
@@ -129,20 +131,25 @@ function LogsHeader() {
{title ? title : t('Logs')}
-
-
- {hasPageFrameFeature ? (
-
-
- {null}
-
+ {hasPageFrameFeature ? (
+
+ {defined(onboardingProject) && (
+
+
- ) : (
-
)}
- {defined(onboardingProject) && }
-
-
+
+ {null}
+
+
+ ) : (
+
+
+
+ {defined(onboardingProject) && }
+
+
+ )}
);
}
@@ -174,7 +181,7 @@ function SetupLogsButton() {
priority="primary"
href="https://docs.sentry.io/product/explore/logs/getting-started/"
external
- size="xs"
+ size="sm"
onClick={() => {
trackAnalytics('logs.explorer.setup_button_clicked', {
organization,
diff --git a/static/app/views/explore/multiQueryMode/index.tsx b/static/app/views/explore/multiQueryMode/index.tsx
index bff601aa6b4a01..1c7d11adb27c3e 100644
--- a/static/app/views/explore/multiQueryMode/index.tsx
+++ b/static/app/views/explore/multiQueryMode/index.tsx
@@ -1,3 +1,5 @@
+import {Fragment} from 'react';
+
import {Grid, Stack} from '@sentry/scraps/layout';
import Feature from 'sentry/components/acl/feature';
@@ -57,19 +59,29 @@ export default function MultiQueryMode() {
/>
{title ? title : t('Compare Queries')}
-
-
-
- {defined(id) && savedQuery?.isPrebuilt === false && }
- {hasPageFrameFeature ? (
-
- {null}
-
- ) : (
+ {hasPageFrameFeature ? (
+
+
+
+ {defined(id) && savedQuery?.isPrebuilt === false && (
+
+ )}
+
+
+ {null}
+
+
+ ) : (
+
+
+
+ {defined(id) && savedQuery?.isPrebuilt === false && (
+
+ )}
- )}
-
-
+
+
+ )}
diff --git a/static/app/views/explore/savedQueries/index.tsx b/static/app/views/explore/savedQueries/index.tsx
index 9881a1373569a6..e05c24319e5810 100644
--- a/static/app/views/explore/savedQueries/index.tsx
+++ b/static/app/views/explore/savedQueries/index.tsx
@@ -1,3 +1,4 @@
+import {Fragment} from 'react';
import {useNavigate} from 'react-router-dom';
import {Button, LinkButton} from '@sentry/scraps/button';
@@ -49,48 +50,83 @@ export default function SavedQueriesView() {
{t('All Queries')}
-
-
- {hasPageFrameFeature ? (
-
- {null}
-
- ) : (
+ {hasPageFrameFeature ? (
+
+
+ {hasLogsFeature ? (
+ (
+ }
+ size="sm"
+ aria-label={t('Save as')}
+ onClick={e => {
+ e.stopPropagation();
+ e.preventDefault();
+
+ triggerProps.onClick?.(e);
+ }}
+ >
+ {t('Create Query')}
+
+ )}
+ />
+ ) : (
+ }
+ size="sm"
+ to={getExploreUrl({organization, visualize: []})}
+ >
+ {t('Create Query')}
+
+ )}
+
+
+ {null}
+
+
+ ) : (
+
+
- )}
- {hasLogsFeature ? (
- (
- }
- size="sm"
- aria-label={t('Save as')}
- onClick={e => {
- e.stopPropagation();
- e.preventDefault();
+ {hasLogsFeature ? (
+ (
+ }
+ size="sm"
+ aria-label={t('Save as')}
+ onClick={e => {
+ e.stopPropagation();
+ e.preventDefault();
- triggerProps.onClick?.(e);
- }}
- >
- {t('Create Query')}
-
- )}
- />
- ) : (
- }
- size="sm"
- to={getExploreUrl({organization, visualize: []})}
- >
- {t('Create Query')}
-
- )}
-
-
+ triggerProps.onClick?.(e);
+ }}
+ >
+ {t('Create Query')}
+
+ )}
+ />
+ ) : (
+ }
+ size="sm"
+ to={getExploreUrl({organization, visualize: []})}
+ >
+ {t('Create Query')}
+
+ )}
+
+
+ )}
diff --git a/static/app/views/explore/spans/content.tsx b/static/app/views/explore/spans/content.tsx
index 4a35fe2a32c44f..f3705c6e421152 100644
--- a/static/app/views/explore/spans/content.tsx
+++ b/static/app/views/explore/spans/content.tsx
@@ -1,5 +1,5 @@
+import {Fragment, useMemo} from 'react';
import type {ReactNode} from 'react';
-import {useMemo} from 'react';
import * as Sentry from '@sentry/react';
import {Grid, Stack} from '@sentry/scraps/layout';
@@ -181,19 +181,25 @@ function SpansTabHeader() {
/>
-
-
-
- {defined(id) && savedQuery?.isPrebuilt === false && }
- {hasPageFrameFeature ? (
-
- {null}
-
- ) : (
+ {hasPageFrameFeature ? (
+
+
+
+ {defined(id) && savedQuery?.isPrebuilt === false && }
+
+
+ {null}
+
+
+ ) : (
+
+
+
+ {defined(id) && savedQuery?.isPrebuilt === false && }
- )}
-
-
+
+
+ )}
);
}
diff --git a/static/app/views/feedback/feedbackListPage.tsx b/static/app/views/feedback/feedbackListPage.tsx
index 081fe13f8a8d86..9678794f88ddf5 100644
--- a/static/app/views/feedback/feedbackListPage.tsx
+++ b/static/app/views/feedback/feedbackListPage.tsx
@@ -41,8 +41,8 @@ const userFeedbackFeedbackOptions = {
};
export default function FeedbackListPage() {
- const organization = useOrganization();
const hasPageFrameFeature = useHasPageFrameFeature();
+ const organization = useOrganization();
const {hasSetupOneFeedback} = useHaveSelectedProjectsSetupFeedback();
const pageFilters = usePageFilters();
@@ -161,40 +161,62 @@ export default function FeedbackListPage() {
/>
-
-
- {hasPageFrameFeature ? (
-
-
- {null}
-
-
- ) : (
+ {hasPageFrameFeature ? (
+
+
+ }
+ to={{
+ pathname: makeAlertsPathname({
+ path: '/new/issue/',
+ organization,
+ }),
+ query: {
+ alert_option: 'issues',
+ referrer: 'feedback-list-page',
+ detectorType: 'metric_issue',
+ ...(feedbackProjectSlug ? {project: feedbackProjectSlug} : {}),
+ },
+ }}
+ >
+ {t('Create Alert')}
+
+
+
+
+ {null}
+
+
+
+ ) : (
+
+
- )}
- }
- to={{
- pathname: makeAlertsPathname({
- path: '/new/issue/',
- organization,
- }),
- query: {
- alert_option: 'issues',
- referrer: 'feedback-list-page',
- detectorType: 'metric_issue',
- ...(feedbackProjectSlug ? {project: feedbackProjectSlug} : {}),
- },
- }}
- >
- {t('Create Alert')}
-
-
-
+ }
+ to={{
+ pathname: makeAlertsPathname({
+ path: '/new/issue/',
+ organization,
+ }),
+ query: {
+ alert_option: 'issues',
+ referrer: 'feedback-list-page',
+ detectorType: 'metric_issue',
+ ...(feedbackProjectSlug ? {project: feedbackProjectSlug} : {}),
+ },
+ }}
+ >
+ {t('Create Alert')}
+
+
+
+ )}
diff --git a/static/app/views/insights/crons/components/monitorHeader.tsx b/static/app/views/insights/crons/components/monitorHeader.tsx
index 5af89e2a441fda..6ae82295f8bd72 100644
--- a/static/app/views/insights/crons/components/monitorHeader.tsx
+++ b/static/app/views/insights/crons/components/monitorHeader.tsx
@@ -5,6 +5,8 @@ import {t} from 'sentry/locale';
import {useOrganization} from 'sentry/utils/useOrganization';
import {makeAlertsPathname} from 'sentry/views/alerts/pathnames';
import type {Monitor} from 'sentry/views/insights/crons/types';
+import {TopBar} from 'sentry/views/navigation/topBar';
+import {useHasPageFrameFeature} from 'sentry/views/navigation/useHasPageFrameFeature';
import {MonitorHeaderActions} from './monitorHeaderActions';
@@ -16,6 +18,7 @@ interface Props {
export function MonitorHeader({monitor, orgSlug, onUpdate}: Props) {
const organization = useOrganization();
+ const hasPageFrameFeature = useHasPageFrameFeature();
const crumbs = [
{
label: t('Alerts'),
@@ -41,9 +44,15 @@ export function MonitorHeader({monitor, orgSlug, onUpdate}: Props) {
{monitor.name}
-
-
-
+ {hasPageFrameFeature ? (
+
+
+
+ ) : (
+
+
+
+ )}
);
}
diff --git a/static/app/views/insights/crons/views/overview.tsx b/static/app/views/insights/crons/views/overview.tsx
index ac5ef38aac13ba..5505f7eb6b311e 100644
--- a/static/app/views/insights/crons/views/overview.tsx
+++ b/static/app/views/insights/crons/views/overview.tsx
@@ -100,35 +100,57 @@ function CronsOverview() {
/>
-
-
- {hasPageFrameFeature ? (
-
- {null}
-
- ) : (
+ {hasPageFrameFeature ? (
+
+
+ }
+ onClick={() =>
+ openBulkEditMonitorsModal({
+ onClose: () => refetch(),
+ })
+ }
+ analyticsEventKey="crons.bulk_edit_modal_button_clicked"
+ analyticsEventName="Crons: Bulk Edit Modal Button Clicked"
+ >
+ {t('Manage Monitors')}
+
+ {!guideVisible && (
+ }>
+ {t('Add Cron Monitor')}
+
+ )}
+
+
+ {null}
+
+
+ ) : (
+
+
- )}
- }
- size="sm"
- onClick={() =>
- openBulkEditMonitorsModal({
- onClose: () => refetch(),
- })
- }
- analyticsEventKey="crons.bulk_edit_modal_button_clicked"
- analyticsEventName="Crons: Bulk Edit Modal Button Clicked"
- >
- {t('Manage Monitors')}
-
- {!guideVisible && (
- }>
- {t('Add Cron Monitor')}
-
- )}
-
-
+ }
+ size="sm"
+ onClick={() =>
+ openBulkEditMonitorsModal({
+ onClose: () => refetch(),
+ })
+ }
+ analyticsEventKey="crons.bulk_edit_modal_button_clicked"
+ analyticsEventName="Crons: Bulk Edit Modal Button Clicked"
+ >
+ {t('Manage Monitors')}
+
+ {!guideVisible && (
+ }>
+ {t('Add Cron Monitor')}
+
+ )}
+
+
+ )}
diff --git a/static/app/views/insights/pages/domainViewHeader.tsx b/static/app/views/insights/pages/domainViewHeader.tsx
index ebd6cc660f5065..9939f3dc700f0d 100644
--- a/static/app/views/insights/pages/domainViewHeader.tsx
+++ b/static/app/views/insights/pages/domainViewHeader.tsx
@@ -62,11 +62,11 @@ export function DomainViewHeader({
}: Props) {
const organization = useOrganization();
const location = useLocation();
+ const hasPageFrameFeature = useHasPageFrameFeature();
const moduleURLBuilder = useModuleURLBuilder();
const isLaravelInsightsAvailable = useIsLaravelInsightsAvailable();
const isNextJsInsightsAvailable = useIsNextJsInsightsAvailable();
const {view, isInOverviewPage} = useDomainViewFilters();
- const hasPageFrameFeature = useHasPageFrameFeature();
const isLaravelInsights = isLaravelInsightsAvailable && isInOverviewPage;
const isNextJsInsights = isNextJsInsightsAvailable && isInOverviewPage;
@@ -136,18 +136,23 @@ export function DomainViewHeader({
{crumbs.length > 1 && }
{headerTitle || domainTitle}
-
-
- {hasPageFrameFeature ? (
-
- {null}
-
- ) : (
-
+ {hasPageFrameFeature ? (
+
+ {additonalHeaderActions && (
+ {additonalHeaderActions}
)}
- {additonalHeaderActions}
-
-
+
+ {null}
+
+
+ ) : (
+
+
+
+ {additonalHeaderActions}
+
+
+ )}
{!hideDefaultTabs && (
diff --git a/static/app/views/insights/uptime/views/overview.tsx b/static/app/views/insights/uptime/views/overview.tsx
index cc1c4154240d53..267dea159b2c26 100644
--- a/static/app/views/insights/uptime/views/overview.tsx
+++ b/static/app/views/insights/uptime/views/overview.tsx
@@ -85,27 +85,41 @@ export default function UptimeOverview() {
/>
-
-
- {hasPageFrameFeature ? (
-
- {null}
-
- ) : (
+ {hasPageFrameFeature ? (
+
+
+ }
+ disabled={!canCreateAlert}
+ tooltipProps={{title: canCreateAlert ? undefined : permissionTooltipText}}
+ >
+ {t('Add Uptime Monitor')}
+
+
+
+ {null}
+
+
+ ) : (
+
+
- )}
- }
- disabled={!canCreateAlert}
- tooltipProps={{title: canCreateAlert ? undefined : permissionTooltipText}}
- >
- {t('Add Uptime Monitor')}
-
-
-
+ }
+ disabled={!canCreateAlert}
+ tooltipProps={{title: canCreateAlert ? undefined : permissionTooltipText}}
+ >
+ {t('Add Uptime Monitor')}
+
+
+
+ )}
diff --git a/static/app/views/issueList/issueViews/issueViewsList/issueViewsList.tsx b/static/app/views/issueList/issueViews/issueViewsList/issueViewsList.tsx
index 818e0721493c8a..02cf283e1275ed 100644
--- a/static/app/views/issueList/issueViews/issueViewsList/issueViewsList.tsx
+++ b/static/app/views/issueList/issueViews/issueViewsList/issueViewsList.tsx
@@ -333,10 +333,10 @@ const issueViewsFeedbackOptions = {
};
export default function IssueViewsList() {
+ const hasPageFrameFeature = useHasPageFrameFeature();
const organization = useOrganization();
const navigate = useNavigate();
const location = useLocation();
- const hasPageFrameFeature = useHasPageFrameFeature();
const query = typeof location.query.query === 'string' ? location.query.query : '';
const {mutate: createGroupSearchView, isPending: isCreatingView} =
useCreateGroupSearchView();
@@ -375,56 +375,97 @@ export default function IssueViewsList() {
{t('All Views')}
-
-
- {hasPageFrameFeature ? (
-
-
- {null}
-
-
- ) : (
+ {hasPageFrameFeature ? (
+
+
+ (
+
+ }
+ >
+ {typeof props.children === 'function'
+ ? props.children(props)
+ : props.children}
+
+ )}
+ >
+ {({hasFeature}) => (
+ }
+ disabled={!hasFeature || isCreatingView}
+ busy={isCreatingView}
+ onClick={() => {
+ trackAnalytics('issue_views.table.create_view_clicked', {
+ organization,
+ });
+ handleCreateView();
+ }}
+ >
+ {t('Create View')}
+
+ )}
+
+
+
+
+ {null}
+
+
+
+ ) : (
+
+
- )}
- (
-
- }
- >
- {typeof props.children === 'function'
- ? props.children(props)
- : props.children}
-
- )}
- >
- {({hasFeature}) => (
- }
- size="sm"
- disabled={!hasFeature || isCreatingView}
- busy={isCreatingView}
- onClick={() => {
- trackAnalytics('issue_views.table.create_view_clicked', {
- organization,
- });
- handleCreateView();
- }}
- >
- {t('Create View')}
-
- )}
-
-
-
+ (
+
+ }
+ >
+ {typeof props.children === 'function'
+ ? props.children(props)
+ : props.children}
+
+ )}
+ >
+ {({hasFeature}) => (
+ }
+ size="sm"
+ disabled={!hasFeature || isCreatingView}
+ busy={isCreatingView}
+ onClick={() => {
+ trackAnalytics('issue_views.table.create_view_clicked', {
+ organization,
+ });
+ handleCreateView();
+ }}
+ >
+ {t('Create View')}
+
+ )}
+
+
+
+ )}
diff --git a/static/app/views/issueList/issueViewsHeader.tsx b/static/app/views/issueList/issueViewsHeader.tsx
index 37b6b0ebeaf190..e9d88d8129177d 100644
--- a/static/app/views/issueList/issueViewsHeader.tsx
+++ b/static/app/views/issueList/issueViewsHeader.tsx
@@ -28,6 +28,8 @@ import {useUpdateGroupSearchViewStarred} from 'sentry/views/issueList/mutations/
import {makeFetchGroupSearchViewKey} from 'sentry/views/issueList/queries/useFetchGroupSearchView';
import type {GroupSearchView} from 'sentry/views/issueList/types';
import {useHasIssueViews} from 'sentry/views/navigation/secondary/sections/issues/issueViews/useHasIssueViews';
+import {TopBar} from 'sentry/views/navigation/topBar';
+import {useHasPageFrameFeature} from 'sentry/views/navigation/useHasPageFrameFeature';
type IssueViewsHeaderProps = {
onRealtimeChange: (active: boolean) => void;
@@ -218,11 +220,38 @@ export function IssueViewsHeader({
headerActions,
}: IssueViewsHeaderProps) {
const {viewId} = useParams<{viewId?: string}>();
+ const hasPageFrameFeature = useHasPageFrameFeature();
const realtimeLabel = realtimeActive
? t('Pause real-time updates')
: t('Enable real-time updates');
+ if (hasPageFrameFeature) {
+ return (
+
+
+
+
+
+ {headerActions}
+ {!viewId && (
+
+ : }
+ onClick={() => onRealtimeChange(!realtimeActive)}
+ />
+
+ )}
+
+
+
+
+ );
+ }
+
return (
diff --git a/static/app/views/performance/transactionSummary/header.tsx b/static/app/views/performance/transactionSummary/header.tsx
index c5d9938c871685..2fbfc954111e3e 100644
--- a/static/app/views/performance/transactionSummary/header.tsx
+++ b/static/app/views/performance/transactionSummary/header.tsx
@@ -281,51 +281,95 @@ export function TransactionHeader({
-
-
-
- {({hasFeature}) =>
- hasFeature &&
- !metricsCardinality?.isLoading &&
- !deprecateTransactionAlerts(organization) ? (
-
- ) : null
- }
-
-
-
-
+
+
+ {({hasFeature}) =>
+ hasFeature &&
+ !metricsCardinality?.isLoading &&
+ !deprecateTransactionAlerts(organization) ? (
+
+ ) : null
+ }
+
+
+
+
+
+
+
+ {null}
+
+
+ ) : (
+
+
+
+ {({hasFeature}) =>
+ hasFeature &&
+ !metricsCardinality?.isLoading &&
+ !deprecateTransactionAlerts(organization) ? (
+
+ ) : null
+ }
+
+
-
- {hasPageFrameFeature ? (
-
- {null}
-
- ) : (
+
+
+
- )}
-
-
+
+
+ )}
-
-
- {hasPageFrameFeature ? (
-
-
- {null}
-
-
- ) : (
-
- )}
- }
- onClick={handleCompareClick}
- disabled={!areActionsEnabled}
- tooltipProps={{
- title: areActionsEnabled
- ? undefined
- : t('Size analysis must be completed to compare builds'),
- }}
- >
- {t('Compare Build')}
-
-
- {project && (
- }
- aria-label={t('Settings')}
- to={`/settings/${organization.slug}/projects/${project.slug}/mobile-builds/`}
- />
- )}
-
-
- {({open: openDeleteModal}) => {
- const menuItems: MenuItemProps[] = [
- {
- key: 'rerun-status-checks',
- label: (
-
-
- {t('Rerun Status Checks')}
-
- ),
- onAction: handleRerunStatusChecksAction,
- textValue: t('Rerun Status Checks'),
- disabled: !canRerunStatusChecks,
- tooltip: canRerunStatusChecks
- ? undefined
- : t('Size analysis must be completed to rerun status checks'),
- },
- {
- key: 'delete',
- label: (
-
-
- {t('Delete Build')}
-
- ),
- onAction: openDeleteModal,
- textValue: t('Delete Build'),
- },
- ];
+ {hasPageFrameFeature ? (
+
+
+ }
+ onClick={handleCompareClick}
+ disabled={!areActionsEnabled}
+ tooltipProps={{
+ title: areActionsEnabled
+ ? undefined
+ : t('Size analysis must be completed to compare builds'),
+ }}
+ >
+ {t('Compare Build')}
+
+
+ {project && (
+ }
+ aria-label={t('Settings')}
+ to={`/settings/${organization.slug}/projects/${project.slug}/mobile-builds/`}
+ />
+ )}
+
+
+ {({open: openDeleteModal}) => {
+ const menuItems: MenuItemProps[] = [
+ {
+ key: 'rerun-status-checks',
+ label: (
+
+
+ {t('Rerun Status Checks')}
+
+ ),
+ onAction: handleRerunStatusChecksAction,
+ textValue: t('Rerun Status Checks'),
+ disabled: !canRerunStatusChecks,
+ tooltip: canRerunStatusChecks
+ ? undefined
+ : t('Size analysis must be completed to rerun status checks'),
+ },
+ {
+ key: 'delete',
+ label: (
+
+
+ {t('Delete Build')}
+
+ ),
+ onAction: openDeleteModal,
+ textValue: t('Delete Build'),
+ },
+ ];
- if (isSentryEmployee) {
- menuItems.push({
- key: 'admin-section',
- label: t('Admin (Sentry Employees only)'),
- children: [
- {
- key: 'rerun',
- label: (
-
-
- {t('Rerun Analysis')}
-
- ),
- onAction: handleRerunAction,
- textValue: t('Rerun Analysis'),
- },
- {
- key: 'download',
- label: (
-
-
- {t('Download Build')}
-
- ),
- onAction: handleDownloadAction,
- textValue: t('Download Build'),
- },
- ],
- });
- }
+ if (isSentryEmployee) {
+ menuItems.push({
+ key: 'admin-section',
+ label: t('Admin (Sentry Employees only)'),
+ children: [
+ {
+ key: 'rerun',
+ label: (
+
+
+ {t('Rerun Analysis')}
+
+ ),
+ onAction: handleRerunAction,
+ textValue: t('Rerun Analysis'),
+ },
+ {
+ key: 'download',
+ label: (
+
+
+ {t('Download Build')}
+
+ ),
+ onAction: handleDownloadAction,
+ textValue: t('Download Build'),
+ },
+ ],
+ });
+ }
- return (
- (
-
-
-
- )}
+ return (
+ (
+
+
+
+ )}
+ />
+ );
+ }}
+
+
+
+
+ {null}
+
+
+
+ ) : (
+
+
+
+ }
+ onClick={handleCompareClick}
+ disabled={!areActionsEnabled}
+ tooltipProps={{
+ title: areActionsEnabled
+ ? undefined
+ : t('Size analysis must be completed to compare builds'),
+ }}
+ >
+ {t('Compare Build')}
+
+
+ {project && (
+ }
+ aria-label={t('Settings')}
+ to={`/settings/${organization.slug}/projects/${project.slug}/mobile-builds/`}
/>
- );
- }}
-
-
-
+ )}
+
+
+ {({open: openDeleteModal}) => {
+ const menuItems: MenuItemProps[] = [
+ {
+ key: 'rerun-status-checks',
+ label: (
+
+
+ {t('Rerun Status Checks')}
+
+ ),
+ onAction: handleRerunStatusChecksAction,
+ textValue: t('Rerun Status Checks'),
+ disabled: !canRerunStatusChecks,
+ tooltip: canRerunStatusChecks
+ ? undefined
+ : t('Size analysis must be completed to rerun status checks'),
+ },
+ {
+ key: 'delete',
+ label: (
+
+
+ {t('Delete Build')}
+
+ ),
+ onAction: openDeleteModal,
+ textValue: t('Delete Build'),
+ },
+ ];
+
+ if (isSentryEmployee) {
+ menuItems.push({
+ key: 'admin-section',
+ label: t('Admin (Sentry Employees only)'),
+ children: [
+ {
+ key: 'rerun',
+ label: (
+
+
+ {t('Rerun Analysis')}
+
+ ),
+ onAction: handleRerunAction,
+ textValue: t('Rerun Analysis'),
+ },
+ {
+ key: 'download',
+ label: (
+
+
+ {t('Download Build')}
+
+ ),
+ onAction: handleDownloadAction,
+ textValue: t('Download Build'),
+ },
+ ],
+ });
+ }
+
+ return (
+ (
+
+
+
+ )}
+ />
+ );
+ }}
+
+
+
+ )}
);
}
diff --git a/static/app/views/preprod/snapshots/snapshots.tsx b/static/app/views/preprod/snapshots/snapshots.tsx
index 0328df777a603a..d878d84d113272 100644
--- a/static/app/views/preprod/snapshots/snapshots.tsx
+++ b/static/app/views/preprod/snapshots/snapshots.tsx
@@ -16,6 +16,8 @@ import {useNavigate} from 'sentry/utils/useNavigate';
import {useOrganization} from 'sentry/utils/useOrganization';
import {useParams} from 'sentry/utils/useParams';
import {useResizableDrawer} from 'sentry/utils/useResizableDrawer';
+import {TopBar} from 'sentry/views/navigation/topBar';
+import {useHasPageFrameFeature} from 'sentry/views/navigation/useHasPageFrameFeature';
import {BuildError} from 'sentry/views/preprod/components/buildError';
import {BuildProcessing} from 'sentry/views/preprod/components/buildProcessing';
import {ComparisonState, getImageGroup} from 'sentry/views/preprod/types/snapshotTypes';
@@ -40,6 +42,7 @@ const DIFF_TYPE_ORDER: Record = Object.fromEntries(
export default function SnapshotsPage() {
const organization = useOrganization();
const theme = useTheme();
+ const hasPageFrameFeature = useHasPageFrameFeature();
const {snapshotId} = useParams<{
snapshotId: string;
}>();
@@ -403,13 +406,23 @@ export default function SnapshotsPage() {
isSoloView={isSoloView}
onToggleView={handleToggleView}
/>
-
-
-
+ {hasPageFrameFeature ? (
+
+
+
+ ) : (
+
+
+
+ )}
{isComparisonProcessing ? processingContent : snapshotContent}
diff --git a/static/app/views/projectsDashboard/index.tsx b/static/app/views/projectsDashboard/index.tsx
index 0365f5e0e6dbb9..18b62642b79676 100644
--- a/static/app/views/projectsDashboard/index.tsx
+++ b/static/app/views/projectsDashboard/index.tsx
@@ -42,6 +42,8 @@ import {useTeamsById} from 'sentry/utils/useTeamsById';
import {useUser} from 'sentry/utils/useUser';
import {useUserTeams} from 'sentry/utils/useUserTeams';
import {TeamFilter} from 'sentry/views/alerts/list/rules/teamFilter';
+import {TopBar} from 'sentry/views/navigation/topBar';
+import {useHasPageFrameFeature} from 'sentry/views/navigation/useHasPageFrameFeature';
import {makeProjectsPathname} from 'sentry/views/projects/pathname';
import {ProjectCard} from './projectCard';
@@ -138,6 +140,7 @@ function Dashboard() {
const navigate = useNavigate();
const location = useLocation();
const organization = useOrganization();
+ const hasPageFrameFeature = useHasPageFrameFeature();
useEffect(() => {
return function cleanup() {
@@ -239,8 +242,8 @@ function Dashboard() {
/>
-
-
+ {hasPageFrameFeature ? (
+
}
@@ -273,8 +276,45 @@ function Dashboard() {
>
{t('Create Project')}
-
-
+
+ ) : (
+
+
+ }
+ tooltipProps={{
+ title: canJoinTeam
+ ? undefined
+ : t('You do not have permission to join a team.'),
+ }}
+ disabled={!canJoinTeam}
+ to={`/settings/${organization.slug}/teams/`}
+ data-test-id="join-team"
+ >
+ {t('Join a Team')}
+
+ }
+ data-test-id="create-project"
+ >
+ {t('Create Project')}
+
+
+
+ )}
diff --git a/static/app/views/releases/detail/header/releaseHeader.tsx b/static/app/views/releases/detail/header/releaseHeader.tsx
index 4e7261d7cf60fc..c1ab3a6b647be9 100644
--- a/static/app/views/releases/detail/header/releaseHeader.tsx
+++ b/static/app/views/releases/detail/header/releaseHeader.tsx
@@ -20,6 +20,8 @@ import type {Organization} from 'sentry/types/organization';
import type {Release, ReleaseMeta, ReleaseProject} from 'sentry/types/release';
import {formatAbbreviatedNumber} from 'sentry/utils/formatters';
import {normalizeUrl} from 'sentry/utils/url/normalizeUrl';
+import {TopBar} from 'sentry/views/navigation/topBar';
+import {useHasPageFrameFeature} from 'sentry/views/navigation/useHasPageFrameFeature';
import {isMobileRelease} from 'sentry/views/releases/utils';
import {makeReleasesPathname} from 'sentry/views/releases/utils/pathnames';
@@ -42,6 +44,7 @@ export function ReleaseHeader({
releaseMeta,
refetchData,
}: Props) {
+ const hasPageFrameFeature = useHasPageFrameFeature();
const {version, url} = release;
const {commitCount, commitFilesChanged} = releaseMeta;
@@ -165,14 +168,25 @@ export function ReleaseHeader({
-
-
-
+ {hasPageFrameFeature ? (
+
+
+
+ ) : (
+
+
+
+ )}
diff --git a/static/app/views/replays/detail/header/replayDetailsHeaderActions.tsx b/static/app/views/replays/detail/header/replayDetailsHeaderActions.tsx
index ec36ab8d06418a..9b0478c567cb1a 100644
--- a/static/app/views/replays/detail/header/replayDetailsHeaderActions.tsx
+++ b/static/app/views/replays/detail/header/replayDetailsHeaderActions.tsx
@@ -1,3 +1,4 @@
+import {Fragment} from 'react';
import styled from '@emotion/styled';
import {FeedbackButton} from 'sentry/components/feedbackButton/feedbackButton';
@@ -24,44 +25,67 @@ export function ReplayDetailsHeaderActions({readerResult}: Props) {
renderThrottled={() => null}
renderLoading={() => }
renderMissing={() => null}
- renderProcessingError={({replayRecord, projectSlug}) => (
-
- {hasPageFrameFeature ? (
+ renderProcessingError={({replayRecord, projectSlug}) =>
+ hasPageFrameFeature ? (
+
+
+
+
+
{null}
- ) : (
+
+ ) : (
+
- )}
-
-
-
- )}
+
+
+
+ )
+ }
>
- {({replay}) => (
-
- {hasPageFrameFeature ? (
+ {({replay}) =>
+ hasPageFrameFeature ? (
+
+
+
+
+
{null}
- ) : (
+
+ ) : (
+
- )}
-
-
-
- )}
+
+
+
+ )
+ }
);
}
diff --git a/static/app/views/replays/list.tsx b/static/app/views/replays/list.tsx
index e151a7e3b52ba5..9288adc427bc98 100644
--- a/static/app/views/replays/list.tsx
+++ b/static/app/views/replays/list.tsx
@@ -30,6 +30,8 @@ import {
useQueryParamsTitle,
} from 'sentry/views/explore/queryParams/context';
import {TraceItemDataset} from 'sentry/views/explore/types';
+import {TopBar} from 'sentry/views/navigation/topBar';
+import {useHasPageFrameFeature} from 'sentry/views/navigation/useHasPageFrameFeature';
import {ReplaysFilters} from 'sentry/views/replays/list/filters';
import {ReplayIndexContainer} from 'sentry/views/replays/list/replayIndexContainer';
import {ReplayIndexTimestampPrefPicker} from 'sentry/views/replays/list/replayIndexTimestampPrefPicker';
@@ -48,6 +50,7 @@ function ReplaysHeader() {
const title = useQueryParamsTitle();
const organization = useOrganization();
const {data: savedQuery} = useGetSavedQuery(pageId);
+ const hasPageFrameFeature = useHasPageFrameFeature();
const hasSavedQueryTitle =
defined(pageId) && defined(savedQuery) && savedQuery.name.length > 0;
@@ -81,9 +84,15 @@ function ReplaysHeader() {
)}
-
-
-
+ {hasPageFrameFeature ? (
+
+
+
+ ) : (
+
+
+
+ )}
);
}