BrowseDashboards: Add tracking (#113696)

* feat: add tracking for New button

* feat: add tracking for New button dashboard click

* refactor: move tracking

* refactor: add payload

* refactor: clean up

* refactor: include folder clicks

* refactor: add view to payload

* feat: add tracking in serach view

* refactor: fix TS error

* refactor: adjust payload

* refactor: adjust payload

* refactor: fix TS error

* refactor: clean up

* refactor: set trackingSource

* refactor: remove type declaration

Co-authored-by: Alex Khomenko <Clarity-89@users.noreply.github.com>

* refactor: apply changes after code review

* Refactor: clean up

Co-authored-by: Alex Khomenko <Clarity-89@users.noreply.github.com>

* refactor: fix tests

---------

Co-authored-by: Alex Khomenko <Clarity-89@users.noreply.github.com>
This commit is contained in:
Laura Benz
2025-11-17 13:19:37 +01:00
committed by GitHub
co-authored by Alex Khomenko
parent 77dac4210f
commit 434d370394
5 changed files with 47 additions and 13 deletions
@@ -50,6 +50,11 @@ export default function CreateNewButton({
const notifyApp = useAppNotification();
const isProvisionedInstance = useIsProvisionedInstance();
const handleVisibleChange = () => {
!isOpen && reportInteraction('grafana_create_new_button_menu_opened');
setIsOpen(!isOpen);
};
let renderPreBuiltDashboardAction = false;
if (config.featureToggles.dashboardTemplates) {
const testDataSources = getDataSourceSrv().getList({ type: 'grafana-testdata-datasource' });
@@ -129,7 +134,7 @@ export default function CreateNewButton({
return (
<>
<Dropdown overlay={newMenu} onVisibleChange={setIsOpen}>
<Dropdown overlay={newMenu} onVisibleChange={handleVisibleChange}>
<Button
disabled={isReadOnlyRepo}
tooltip={isReadOnlyRepo ? getReadOnlyTooltipText({ isLocal: repoType === 'local' }) : undefined}
@@ -93,7 +93,11 @@ export function NameCell({ row: { original: data }, onFolderClick, treeID }: Nam
{item.url ? (
<Link
onClick={() => {
reportInteraction('manage_dashboards_result_clicked');
reportInteraction('grafana_browse_dashboards_page_click_list_item', {
itemKind: item.kind,
parent: item.parentUID ? 'folder' : 'root',
source: 'browseDashboardsPage_BrowseView',
});
}}
href={item.url}
className={styles.link}
@@ -137,6 +137,7 @@ export function SearchView({
keyboardEvents,
onDatasourceChange: searchState.datasource ? stateManager.onDatasourceChange : undefined,
onClickItem: searchState.deleted ? undefined : stateManager.onSearchItemClicked,
trackingSource: 'browseDashboardsPage_SearchView',
};
return <SearchResultsTable {...props} />;
@@ -61,6 +61,7 @@ export function PluginUsage({ plugin }: Props) {
clearSelection={() => {}}
keyboardEvents={of()}
onTagSelected={() => {}}
trackingSource="PluginDetailsPage_PluginUsage"
/>
);
}}
@@ -8,6 +8,7 @@ import { Observable } from 'rxjs';
import { Field, GrafanaTheme2 } from '@grafana/data';
import { Trans, t } from '@grafana/i18n';
import { reportInteraction } from '@grafana/runtime';
import { TableCellHeight } from '@grafana/schema';
import { useStyles2, useTheme2 } from '@grafana/ui';
import { useTableStyles, TableCell } from '@grafana/ui/internal';
@@ -30,6 +31,7 @@ export type SearchResultsProps = {
onDatasourceChange?: (datasource?: string) => void;
onClickItem?: (event: React.MouseEvent<HTMLElement>) => void;
keyboardEvents: Observable<React.KeyboardEvent>;
trackingSource?: string;
};
export type TableColumn = Column & {
@@ -50,6 +52,7 @@ export const SearchResultsTable = React.memo(
onDatasourceChange,
onClickItem,
keyboardEvents,
trackingSource,
}: SearchResultsProps) => {
const styles = useStyles2(getStyles);
const columnStyles = useStyles2(getColumnStyles);
@@ -141,6 +144,35 @@ export const SearchResultsTable = React.memo(
return (
<div key={key} {...rowProps} className={className}>
{row.cells.map((cell: Cell, index: number) => {
const href = onClickItem ? url : undefined;
let userProps = {
href,
onClick: onClickItem,
};
if (cell.column.id === 'column-name' && href) {
const item = response.view.get(rowIndex);
const itemKind = item.kind;
const parent = item.location || 'general';
const parentType = parent === 'general' ? 'general' : 'folder';
userProps.onClick = (evt: React.MouseEvent<HTMLElement>) => {
try {
reportInteraction('grafana_browse_dashboards_page_click_list_item', {
itemKind: itemKind,
parent: parentType,
source: trackingSource,
});
} catch (e) {
// ignore analytics errors
}
if (onClickItem) {
onClickItem(evt);
}
};
}
return (
<TableCell
key={index}
@@ -148,7 +180,7 @@ export const SearchResultsTable = React.memo(
cell={cell}
columnIndex={index}
columnCount={row.cells.length}
userProps={{ href: onClickItem ? url : undefined, onClick: onClickItem }}
userProps={userProps}
frame={response.view.dataFrame}
/>
);
@@ -156,16 +188,7 @@ export const SearchResultsTable = React.memo(
</div>
);
},
[
rows,
prepareRow,
response.view.fields.url?.values,
highlightIndex,
styles,
tableStyles,
onClickItem,
response.view.dataFrame,
]
[rows, prepareRow, highlightIndex, styles, tableStyles, onClickItem, response.view, trackingSource]
);
if (!rows.length) {