Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -402,8 +402,16 @@ export function GlobalCommandPaletteActions() {
</CMDKAction>

<CMDKAction display={{label: t('Dashboards'), icon: <IconDashboard />}} limit={4}>
{hasPrebuiltDashboards && (
<CMDKAction
display={{label: t('All Dashboards')}}
to={`${prefix}/dashboards/?filter=${DashboardFilter.ALL}`}
/>
)}
<CMDKAction
display={{label: t('All Dashboards')}}
display={{
label: hasPrebuiltDashboards ? t('Custom Dashboards') : t('All Dashboards'),
}}
to={`${prefix}/dashboards/`}
/>
{hasPrebuiltDashboards && (
Expand Down
9 changes: 7 additions & 2 deletions static/app/views/dashboards/manage/index.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,12 @@ import {getPaginationPageLink} from 'sentry/views/organizationStats/utils';

jest.mock('sentry/utils/localStorage');

const FEATURES = ['dashboards-basic', 'dashboards-edit', 'discover-query'];
const FEATURES = [
'dashboards-basic',
'dashboards-edit',
'discover-query',
'dashboards-prebuilt-insights-dashboards',
];

jest.mock('sentry/utils/useNavigate', () => ({
useNavigate: jest.fn(),
Expand Down Expand Up @@ -71,7 +76,7 @@ describe('Dashboards > Detail', () => {
organization: mockAuthorizedOrg,
});

expect(await screen.findByText('All Dashboards')).toBeInTheDocument();
expect(await screen.findByText('Custom Dashboards')).toBeInTheDocument();

expect(await screen.findByText('Test Dashboard')).toBeInTheDocument();

Expand Down
34 changes: 23 additions & 11 deletions static/app/views/dashboards/manage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ import {useNavigate} from 'sentry/utils/useNavigate';
import {useOrganization} from 'sentry/utils/useOrganization';
import {DashboardCreateLimitWrapper} from 'sentry/views/dashboards/createLimitWrapper';
import DashboardTable from 'sentry/views/dashboards/manage/dashboardTable';
import type {DashboardsLayout} from 'sentry/views/dashboards/manage/types';
import {type DashboardsLayout, DashboardsTab} from 'sentry/views/dashboards/manage/types';
import {getDashboardsTab} from 'sentry/views/dashboards/manage/utils/getDashboardsTab';
import {DashboardFilter, PREBUILT_DASHBOARD_LABEL} from 'sentry/views/dashboards/types';
import {PREBUILT_DASHBOARDS} from 'sentry/views/dashboards/utils/prebuiltConfigs';
import {TopBar} from 'sentry/views/navigation/topBar';
Expand All @@ -66,6 +67,18 @@ export const LAYOUT_KEY = 'dashboards-overview-layout';
const GRID = 'grid';
const TABLE = 'table';

const DASHBOARDS_TAB_TITLES: Record<DashboardsTab, string> = {
[DashboardsTab.CUSTOM]: t('Custom Dashboards'),
[DashboardsTab.ALL]: t('All Dashboards'),
[DashboardsTab.PREBUILT]: PREBUILT_DASHBOARD_LABEL,
};

const DASHBOARDS_TAB_API_QUERY: Record<DashboardsTab, {filter?: DashboardFilter}> = {
[DashboardsTab.CUSTOM]: {filter: DashboardFilter.EXCLUDE_PREBUILT},
[DashboardsTab.ALL]: {},
[DashboardsTab.PREBUILT]: {filter: DashboardFilter.ONLY_PREBUILT},
};

function getDashboardsOverviewLayout(): DashboardsLayout {
const dashboardsLayout = localStorageWrapper.getItem(LAYOUT_KEY);

Expand Down Expand Up @@ -118,8 +131,12 @@ function ManageDashboards() {
'dashboards-prebuilt-insights-dashboards'
);
const urlFilter = decodeScalar(location.query.filter) as DashboardFilter | undefined;
const isOnlyPrebuilt =
hasPrebuiltDashboards && urlFilter === DashboardFilter.ONLY_PREBUILT;
const dashboardsTab = getDashboardsTab(hasPrebuiltDashboards, urlFilter);
const isOnlyPrebuilt = dashboardsTab === DashboardsTab.PREBUILT;
const pageTitle =
dashboardsTab === DashboardsTab.CUSTOM && !hasPrebuiltDashboards
? t('All Dashboards')
: DASHBOARDS_TAB_TITLES[dashboardsTab];

const areAiFeaturesAllowed =
!organization.hideAiFeatures && organization.features.includes('gen-ai-features');
Expand Down Expand Up @@ -151,9 +168,7 @@ function ManageDashboards() {
pin: 'favorites',
per_page:
dashboardsLayout === GRID ? rowCount * columnCount : DASHBOARD_TABLE_NUM_ROWS,
...(isOnlyPrebuilt
? {filter: DashboardFilter.ONLY_PREBUILT}
: {filter: DashboardFilter.EXCLUDE_PREBUILT}),
...DASHBOARDS_TAB_API_QUERY[dashboardsTab],
},
}),
select: selectJsonWithHeaders,
Expand Down Expand Up @@ -530,10 +545,7 @@ function ManageDashboards() {
features="dashboards-edit"
renderDisabled={renderNoAccess}
>
<SentryDocumentTitle
title={isOnlyPrebuilt ? PREBUILT_DASHBOARD_LABEL : t('All Dashboards')}
orgSlug={organization.slug}
>
<SentryDocumentTitle title={pageTitle} orgSlug={organization.slug}>
<ErrorBoundary>
{isError ? (
<Stack flex={1} padding="2xl 3xl">
Expand All @@ -545,7 +557,7 @@ function ManageDashboards() {
<Layout.Header unified>
<Layout.HeaderContent unified>
<Layout.Title>
{isOnlyPrebuilt ? PREBUILT_DASHBOARD_LABEL : t('All Dashboards')}
{pageTitle}
<PageHeadingQuestionTooltip
docsUrl="https://docs.sentry.io/product/dashboards/"
title={
Expand Down
6 changes: 6 additions & 0 deletions static/app/views/dashboards/manage/types.tsx
Original file line number Diff line number Diff line change
@@ -1 +1,7 @@
export type DashboardsLayout = 'grid' | 'table';

export enum DashboardsTab {
CUSTOM = 'custom',
ALL = 'all',
PREBUILT = 'prebuilt',
}
18 changes: 18 additions & 0 deletions static/app/views/dashboards/manage/utils/getDashboardsTab.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import {DashboardsTab} from 'sentry/views/dashboards/manage/types';
import {DashboardFilter} from 'sentry/views/dashboards/types';

export function getDashboardsTab(
hasPrebuiltDashboards: boolean,
urlFilter: DashboardFilter | undefined
): DashboardsTab {
if (!hasPrebuiltDashboards) {
return DashboardsTab.CUSTOM;
}
if (urlFilter === DashboardFilter.ONLY_PREBUILT) {
return DashboardsTab.PREBUILT;
}
if (urlFilter === DashboardFilter.ALL) {
return DashboardsTab.ALL;
}
return DashboardsTab.CUSTOM;
}
1 change: 1 addition & 0 deletions static/app/views/dashboards/types.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export enum DashboardFilter {
SHARED = 'shared',
EXCLUDE_PREBUILT = 'excludePrebuilt',
ONLY_PREBUILT = 'onlyPrebuilt',
ALL = 'all',
SHOW_HIDDEN = 'showHidden',
}

Expand Down
5 changes: 3 additions & 2 deletions static/app/views/navigation/index.desktop.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const ALL_AVAILABLE_FEATURES = [
'discover-query',
'dashboards-basic',
'dashboards-edit',
'dashboards-prebuilt-insights-dashboards',
'session-replay-ui',
'ourlogs-enabled',
'performance-view',
Expand Down Expand Up @@ -376,7 +377,7 @@ describe('desktop navigation', () => {
[`${ORG}/explore/releases/`, 'Explore', 'Releases'],
[`${ORG}/explore/saved-queries/`, 'Explore', 'All Queries'],
// Dashboards
[`${ORG}/dashboards/`, 'Dashboards', 'All Dashboards'],
[`${ORG}/dashboards/`, 'Dashboards', 'Custom Dashboards'],
// Insights
[`${ORG}/insights/frontend/`, 'Insights', 'Frontend'],
[`${ORG}/insights/backend/`, 'Insights', 'Backend'],
Expand Down Expand Up @@ -477,7 +478,7 @@ describe('desktop navigation', () => {
['/explore/logs/', 'Explore', 'Logs'],
['/explore/replays/', 'Explore', 'Replays'],
// Dashboards
['/dashboards/', 'Dashboards', 'All Dashboards'],
['/dashboards/', 'Dashboards', 'Custom Dashboards'],
// Insights
['/insights/frontend/', 'Insights', 'Frontend'],
['/insights/backend/', 'Insights', 'Backend'],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ describe('DashboardsSecondaryNavigation', () => {
let organization: Organization;

beforeEach(() => {
organization = OrganizationFixture();
organization = OrganizationFixture({
features: ['dashboards-prebuilt-insights-dashboards'],
});

MockApiClient.addMockResponse({
url: '/organizations/org-slug/group-search-views/starred/',
Expand Down Expand Up @@ -46,6 +48,8 @@ describe('DashboardsSecondaryNavigation', () => {

expect(screen.getAllByRole('link').map(el => el.textContent)).toEqual([
'All Dashboards',
'Custom Dashboards',
'Sentry Built',
'Dashboard 9999',
'Dashboard 1',
]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import {useProjects} from 'sentry/utils/useProjects';
import {useUser} from 'sentry/utils/useUser';
import {useGetStarredDashboards} from 'sentry/views/dashboards/hooks/useGetStarredDashboards';
import {DEFAULT_PREBUILT_SORT} from 'sentry/views/dashboards/manage/settings';
import {DashboardsTab} from 'sentry/views/dashboards/manage/types';
import {getDashboardsTab} from 'sentry/views/dashboards/manage/utils/getDashboardsTab';
import {DashboardFilter, PREBUILT_DASHBOARD_LABEL} from 'sentry/views/dashboards/types';
import type {DashboardListItem} from 'sentry/views/dashboards/types';
import {isPrimaryNavigationLinkActive} from 'sentry/views/navigation/primary/components';
Expand All @@ -29,7 +31,7 @@ export function DashboardsSecondaryNavigation() {
'dashboards-prebuilt-insights-dashboards'
);
const urlFilter = decodeScalar(location.query.filter) as DashboardFilter | undefined;
const isOnlyPrebuilt = urlFilter === DashboardFilter.ONLY_PREBUILT;
const dashboardsTab = getDashboardsTab(hasPrebuiltDashboards, urlFilter);
const isOnDashboardsList = isPrimaryNavigationLinkActive(
`${baseUrl}/`,
location.pathname,
Expand All @@ -44,25 +46,38 @@ export function DashboardsSecondaryNavigation() {
<SecondaryNavigation.Body>
<SecondaryNavigation.Section id="dashboards-all">
<SecondaryNavigation.List>
{hasPrebuiltDashboards ? (
<SecondaryNavigation.ListItem>
<SecondaryNavigation.Link
to={`${baseUrl}/?filter=${DashboardFilter.ALL}`}
isActive={isOnDashboardsList && dashboardsTab === DashboardsTab.ALL}
analyticsItemName="dashboards_all_combined"
>
{t('All Dashboards')}
</SecondaryNavigation.Link>
</SecondaryNavigation.ListItem>
) : null}
<SecondaryNavigation.ListItem>
<SecondaryNavigation.Link
to={`${baseUrl}/`}
end
isActive={
hasPrebuiltDashboards
? isOnDashboardsList && !isOnlyPrebuilt
? isOnDashboardsList && dashboardsTab === DashboardsTab.CUSTOM
: undefined
}
analyticsItemName="dashboards_all"
>
{t('All Dashboards')}
{hasPrebuiltDashboards ? t('Custom Dashboards') : t('All Dashboards')}
</SecondaryNavigation.Link>
</SecondaryNavigation.ListItem>
{hasPrebuiltDashboards ? (
<SecondaryNavigation.ListItem>
<SecondaryNavigation.Link
to={`${baseUrl}/?filter=${DashboardFilter.ONLY_PREBUILT}&sort=${DEFAULT_PREBUILT_SORT}`}
isActive={isOnDashboardsList && isOnlyPrebuilt}
isActive={
isOnDashboardsList && dashboardsTab === DashboardsTab.PREBUILT
}
analyticsItemName="dashboards_sentry_built"
>
{PREBUILT_DASHBOARD_LABEL}
Expand Down
Loading