+
+
+
+ Get started with Grafana templates using sample data. Connect your data to power them with real metrics.
+
+
+
+
+
+ {loading
+ ? Array.from({ length: 4 }).map((_, index) => )
+ : dashboards?.map((dashboard) => {
+ const thumbnail = dashboard.screenshots?.[0]?.links.find((l: Link) => l.rel === 'image')?.href ?? '';
+ const thumbnailUrl = thumbnail ? `/api/gnet${thumbnail}` : '';
+
+ return (
+ onPreviewDashboardClick(dashboard)}
+ dashboard={dashboard}
+ kind="template_dashboard"
+ />
+ );
+ })}
+
+
+
+ );
+};
+
+function getStyles(theme: GrafanaTheme2) {
+ return {
+ modal: css({
+ width: '1200px',
+ }),
+ stickyHeader: css({
+ position: 'sticky',
+ top: 0,
+ zIndex: 2,
+ backgroundColor: theme.colors.background.primary,
+ paddingTop: theme.spacing(1),
+ paddingBottom: theme.spacing(2),
+ }),
+ modalContent: css({
+ paddingTop: 0,
+ height: '100%',
+ }),
+ };
+}
diff --git a/public/app/features/dashboard/dashgrid/DashboardLibrary/api/dashboardLibraryApi.ts b/public/app/features/dashboard/dashgrid/DashboardLibrary/api/dashboardLibraryApi.ts
index b97568a8ab9..6f3a4045368 100644
--- a/public/app/features/dashboard/dashgrid/DashboardLibrary/api/dashboardLibraryApi.ts
+++ b/public/app/features/dashboard/dashgrid/DashboardLibrary/api/dashboardLibraryApi.ts
@@ -71,11 +71,11 @@ export async function fetchCommunityDashboards(
// Grafana.com API returns format: { page: number, pages: number, items: GnetDashboard[] }
// We normalize it to use "dashboards" instead of "items" for consistency
- if (result && Array.isArray(result.items)) {
+ if (result) {
return {
page: result.page || params.page,
pages: result.pages || 1,
- dashboards: result.items,
+ items: result.items,
};
}
@@ -84,7 +84,7 @@ export async function fetchCommunityDashboards(
return {
page: params.page,
pages: 1,
- dashboards: [],
+ items: [],
};
}
diff --git a/public/app/features/dashboard/dashgrid/DashboardLibrary/interactions.ts b/public/app/features/dashboard/dashgrid/DashboardLibrary/interactions.ts
index 714e53145e9..804ef885d61 100644
--- a/public/app/features/dashboard/dashgrid/DashboardLibrary/interactions.ts
+++ b/public/app/features/dashboard/dashgrid/DashboardLibrary/interactions.ts
@@ -7,16 +7,25 @@ export const EVENT_LOCATIONS = {
EMPTY_DASHBOARD: 'empty_dashboard',
MODAL_PROVISIONED_TAB: 'suggested_dashboards_modal_provisioned_tab',
MODAL_COMMUNITY_TAB: 'suggested_dashboards_modal_community_tab',
+ BROWSE_DASHBOARDS_PAGE: 'browse_dashboards_page',
} as const;
export const CONTENT_KINDS = {
DATASOURCE_DASHBOARD: 'datasource_dashboard',
COMMUNITY_DASHBOARD: 'community_dashboard',
+ TEMPLATE_DASHBOARD: 'template_dashboard',
// in future this could also include "TEMPLATE_DASHBOARD" if/when items become templates
} as const;
+export const TemplateDashboardSourceEntryPoint = {
+ QUICK_ADD_BUTTON: 'quick_add_button',
+ COMMAND_PALETTE: 'command_palette',
+ BROWSE_DASHBOARDS_PAGE: 'browse_dashboards_page_create_new_button',
+} as const;
+
export const SOURCE_ENTRY_POINTS = {
DATASOURCE_PAGE: 'datasource_page',
+ ...TemplateDashboardSourceEntryPoint,
// possible future flows: CREATE_DASHBOARD, EMPTY_STATE
} as const;
@@ -28,6 +37,7 @@ export const DISCOVERY_METHODS = {
export const CREATION_ORIGINS = {
DASHBOARD_LIBRARY_DATASOURCE_DASHBOARD: 'dashboard_library_datasource_dashboard',
DASHBOARD_LIBRARY_COMMUNITY_DASHBOARD: 'dashboard_library_community_dashboard',
+ DASHBOARD_LIBRARY_TEMPLATE_DASHBOARD: 'dashboard_library_template_dashboard',
} as const;
// Derive types from constant maps for single source of truth
@@ -91,6 +101,9 @@ export const DashboardLibraryInteractions = {
}) => {
reportDashboardLibraryInteraction('mapping_form_completed', properties);
},
+ entryPointClicked: (properties: { entryPoint: SourceEntryPoint; contentKind: ContentKind }) => {
+ reportDashboardLibraryInteraction('entry_point_clicked', properties);
+ },
};
const reportDashboardLibraryInteraction = (name: string, properties?: Record