2025-04-01 10:38:02 +09:00

492 lines
13 KiB
TypeScript

import { Scope, ScopeDashboardBinding, ScopeNode } from '@grafana/data';
import { DataSourceRef } from '@grafana/schema/dist/esm/common/common.gen';
import { getDashboardScenePageStateManager } from 'app/features/dashboard-scene/pages/DashboardScenePageStateManager';
import * as api from '../../internal/api';
export const mocksScopes: Scope[] = [
{
metadata: { name: 'cloud' },
spec: {
title: 'Cloud',
type: 'indexHelper',
description: 'redundant label filter but makes queries faster',
category: 'indexHelpers',
filters: [{ key: 'cloud', value: '.*', operator: 'regex-match' }],
},
},
{
metadata: { name: 'dev' },
spec: {
title: 'Dev',
type: 'cloud',
description: 'Dev',
category: 'cloud',
filters: [{ key: 'cloud', value: 'dev', operator: 'equals' }],
},
},
{
metadata: { name: 'ops' },
spec: {
title: 'Ops',
type: 'cloud',
description: 'Ops',
category: 'cloud',
filters: [{ key: 'cloud', value: 'ops', operator: 'equals' }],
},
},
{
metadata: { name: 'prod' },
spec: {
title: 'Prod',
type: 'cloud',
description: 'Prod',
category: 'cloud',
filters: [{ key: 'cloud', value: 'prod', operator: 'equals' }],
},
},
{
metadata: { name: 'grafana' },
spec: {
title: 'Grafana',
type: 'app',
description: 'Grafana',
category: 'apps',
filters: [{ key: 'app', value: 'grafana', operator: 'equals' }],
},
},
{
metadata: { name: 'mimir' },
spec: {
title: 'Mimir',
type: 'app',
description: 'Mimir',
category: 'apps',
filters: [{ key: 'app', value: 'mimir', operator: 'equals' }],
},
},
{
metadata: { name: 'loki' },
spec: {
title: 'Loki',
type: 'app',
description: 'Loki',
category: 'apps',
filters: [{ key: 'app', value: 'loki', operator: 'equals' }],
},
},
{
metadata: { name: 'tempo' },
spec: {
title: 'Tempo',
type: 'app',
description: 'Tempo',
category: 'apps',
filters: [{ key: 'app', value: 'tempo', operator: 'equals' }],
},
},
] as const;
const dashboardBindingsGenerator = (
scopes: string[],
dashboards: Array<{ dashboardTitle: string; dashboardKey?: string; groups?: string[] }>
) =>
scopes.reduce<ScopeDashboardBinding[]>((scopeAcc, scopeTitle) => {
const scope = scopeTitle.toLowerCase().replaceAll(' ', '-').replaceAll('/', '-');
return [
...scopeAcc,
...dashboards.reduce<ScopeDashboardBinding[]>((acc, { dashboardTitle, groups, dashboardKey }, idx) => {
dashboardKey = dashboardKey ?? dashboardTitle.toLowerCase().replaceAll(' ', '-').replaceAll('/', '-');
const group = !groups
? ''
: groups.length === 1
? groups[0] === ''
? ''
: `${groups[0].toLowerCase().replaceAll(' ', '-').replaceAll('/', '-')}-`
: `multiple${idx}-`;
const dashboard = `${group}${dashboardKey}`;
return [
...acc,
{
metadata: { name: `${scope}-${dashboard}` },
spec: {
dashboard,
scope,
},
status: {
dashboardTitle,
groups,
},
},
];
}, []),
];
}, []);
export const mocksScopeDashboardBindings: ScopeDashboardBinding[] = [
...dashboardBindingsGenerator(
['Grafana'],
[
{ dashboardTitle: 'Data Sources', groups: ['General'] },
{ dashboardTitle: 'Usage', groups: ['General'] },
{ dashboardTitle: 'Frontend Errors', groups: ['Observability'] },
{ dashboardTitle: 'Frontend Logs', groups: ['Observability'] },
{ dashboardTitle: 'Backend Errors', groups: ['Observability'] },
{ dashboardTitle: 'Backend Logs', groups: ['Observability'] },
{ dashboardTitle: 'Usage Overview', groups: ['Usage'] },
{ dashboardTitle: 'Data Sources', groups: ['Usage'] },
{ dashboardTitle: 'Stats', groups: ['Usage'] },
{ dashboardTitle: 'Overview', groups: [''] },
{ dashboardTitle: 'Frontend' },
{ dashboardTitle: 'Stats' },
]
),
...dashboardBindingsGenerator(
['Loki', 'Tempo', 'Mimir'],
[
{ dashboardTitle: 'Ingester', groups: ['Components', 'Investigations'] },
{ dashboardTitle: 'Distributor', groups: ['Components', 'Investigations'] },
{ dashboardTitle: 'Compacter', groups: ['Components', 'Investigations'] },
{ dashboardTitle: 'Datasource Errors', groups: ['Observability', 'Investigations'] },
{ dashboardTitle: 'Datasource Logs', groups: ['Observability', 'Investigations'] },
{ dashboardTitle: 'Overview' },
{ dashboardTitle: 'Stats', dashboardKey: 'another-stats' },
]
),
...dashboardBindingsGenerator(
['Dev', 'Ops', 'Prod'],
[
{ dashboardTitle: 'Overview', groups: ['Cardinality Management'] },
{ dashboardTitle: 'Metrics', groups: ['Cardinality Management'] },
{ dashboardTitle: 'Labels', groups: ['Cardinality Management'] },
{ dashboardTitle: 'Overview', groups: ['Usage Insights'] },
{ dashboardTitle: 'Data Sources', groups: ['Usage Insights'] },
{ dashboardTitle: 'Query Errors', groups: ['Usage Insights'] },
{ dashboardTitle: 'Alertmanager', groups: ['Usage Insights'] },
{ dashboardTitle: 'Metrics Ingestion', groups: ['Usage Insights'] },
{ dashboardTitle: 'Billing/Usage' },
]
),
] as const;
export const mocksNodes: Array<ScopeNode & { parent: string }> = [
{
parent: '',
metadata: { name: 'applications' },
spec: {
nodeType: 'container',
title: 'Applications',
description: 'Application Scopes',
},
},
{
parent: '',
metadata: { name: 'cloud' },
spec: {
nodeType: 'container',
title: 'Cloud',
description: 'Cloud Scopes',
disableMultiSelect: true,
linkType: 'scope',
linkId: 'cloud',
},
},
{
parent: 'applications',
metadata: { name: 'applications-grafana' },
spec: {
nodeType: 'leaf',
title: 'Grafana',
description: 'Grafana',
linkType: 'scope',
linkId: 'grafana',
},
},
{
parent: 'applications',
metadata: { name: 'applications-mimir' },
spec: {
nodeType: 'leaf',
title: 'Mimir',
description: 'Mimir',
linkType: 'scope',
linkId: 'mimir',
},
},
{
parent: 'applications',
metadata: { name: 'applications-loki' },
spec: {
nodeType: 'leaf',
title: 'Loki',
description: 'Loki',
linkType: 'scope',
linkId: 'loki',
},
},
{
parent: 'applications',
metadata: { name: 'applications-tempo' },
spec: {
nodeType: 'leaf',
title: 'Tempo',
description: 'Tempo',
linkType: 'scope',
linkId: 'tempo',
},
},
{
parent: 'applications',
metadata: { name: 'applications-cloud' },
spec: {
nodeType: 'container',
title: 'Cloud',
description: 'Application/Cloud Scopes',
linkType: 'scope',
linkId: 'cloud',
},
},
{
parent: 'applications-cloud',
metadata: { name: 'applications-cloud-dev' },
spec: {
nodeType: 'leaf',
title: 'Dev',
description: 'Dev',
linkType: 'scope',
linkId: 'dev',
},
},
{
parent: 'applications-cloud',
metadata: { name: 'applications-cloud-ops' },
spec: {
nodeType: 'leaf',
title: 'Ops',
description: 'Ops',
linkType: 'scope',
linkId: 'ops',
},
},
{
parent: 'applications-cloud',
metadata: { name: 'applications-cloud-prod' },
spec: {
nodeType: 'leaf',
title: 'Prod',
description: 'Prod',
linkType: 'scope',
linkId: 'prod',
},
},
{
parent: 'cloud',
metadata: { name: 'cloud-dev' },
spec: {
nodeType: 'leaf',
title: 'Dev',
description: 'Dev',
linkType: 'scope',
linkId: 'dev',
},
},
{
parent: 'cloud',
metadata: { name: 'cloud-ops' },
spec: {
nodeType: 'leaf',
title: 'Ops',
description: 'Ops',
linkType: 'scope',
linkId: 'ops',
},
},
{
parent: 'cloud',
metadata: { name: 'cloud-prod' },
spec: {
nodeType: 'leaf',
title: 'Prod',
description: 'Prod',
linkType: 'scope',
linkId: 'prod',
},
},
{
parent: 'cloud',
metadata: { name: 'cloud-applications' },
spec: {
nodeType: 'container',
title: 'Applications',
description: 'Cloud/Application Scopes',
},
},
{
parent: 'cloud-applications',
metadata: { name: 'cloud-applications-grafana' },
spec: {
nodeType: 'leaf',
title: 'Grafana',
description: 'Grafana',
linkType: 'scope',
linkId: 'grafana',
},
},
{
parent: 'cloud-applications',
metadata: { name: 'cloud-applications-mimir' },
spec: {
nodeType: 'leaf',
title: 'Mimir',
description: 'Mimir',
linkType: 'scope',
linkId: 'mimir',
},
},
{
parent: 'cloud-applications',
metadata: { name: 'cloud-applications-loki' },
spec: {
nodeType: 'leaf',
title: 'Loki',
description: 'Loki',
linkType: 'scope',
linkId: 'loki',
},
},
{
parent: 'cloud-applications',
metadata: { name: 'cloud-applications-tempo' },
spec: {
nodeType: 'leaf',
title: 'Tempo',
description: 'Tempo',
linkType: 'scope',
linkId: 'tempo',
},
},
] as const;
export const fetchNodesSpy = jest.spyOn(api, 'fetchNodes');
export const fetchScopeSpy = jest.spyOn(api, 'fetchScope');
export const fetchSelectedScopesSpy = jest.spyOn(api, 'fetchSelectedScopes');
export const fetchDashboardsSpy = jest.spyOn(api, 'fetchDashboards');
export const dashboardReloadSpy = jest.spyOn(getDashboardScenePageStateManager(), 'reloadDashboard');
export const getMock = jest
.fn()
.mockImplementation(
(url: string, params: { parent: string; scope: string[]; query?: string } & Record<string, string | string[]>) => {
if (url.startsWith('/apis/scope.grafana.app/v0alpha1/namespaces/default/find/scope_node_children')) {
return {
items: mocksNodes.filter(
({ parent, spec: { title } }) =>
parent === params.parent && title.toLowerCase().includes((params.query ?? '').toLowerCase())
),
};
}
if (url.startsWith('/apis/scope.grafana.app/v0alpha1/namespaces/default/scopes/')) {
const name = url.replace('/apis/scope.grafana.app/v0alpha1/namespaces/default/scopes/', '');
return mocksScopes.find((scope) => scope.metadata.name.toLowerCase() === name.toLowerCase()) ?? {};
}
if (url.startsWith('/apis/scope.grafana.app/v0alpha1/namespaces/default/find/scope_dashboard_bindings')) {
return {
items: mocksScopeDashboardBindings.filter(({ spec: { scope: bindingScope } }) =>
params.scope.includes(bindingScope)
),
};
}
if (url.startsWith('/api/dashboards/uid/')) {
return {};
}
if (url.startsWith('/apis/dashboard.grafana.app/v0alpha1/namespaces/default/dashboards/')) {
return {
metadata: {
name: '1',
},
};
}
return {};
}
);
const generateScopeDashboardBinding = (dashboardTitle: string, groups?: string[], dashboardId?: string) => ({
metadata: { name: `${dashboardTitle}-name` },
spec: {
dashboard: `${dashboardId ?? dashboardTitle}-dashboard`,
scope: `${dashboardTitle}-scope`,
},
status: {
dashboardTitle,
groups,
},
});
export const dashboardWithoutFolder: ScopeDashboardBinding = generateScopeDashboardBinding('Without Folder');
export const dashboardWithOneFolder: ScopeDashboardBinding = generateScopeDashboardBinding('With one folder', [
'Folder 1',
]);
export const dashboardWithTwoFolders: ScopeDashboardBinding = generateScopeDashboardBinding('With two folders', [
'Folder 1',
'Folder 2',
]);
export const alternativeDashboardWithTwoFolders: ScopeDashboardBinding = generateScopeDashboardBinding(
'Alternative with two folders',
['Folder 1', 'Folder 2'],
'With two folders'
);
export const dashboardWithRootFolder: ScopeDashboardBinding = generateScopeDashboardBinding('With root folder', ['']);
export const alternativeDashboardWithRootFolder: ScopeDashboardBinding = generateScopeDashboardBinding(
'Alternative With root folder',
[''],
'With root folder'
);
export const dashboardWithRootFolderAndOtherFolder: ScopeDashboardBinding = generateScopeDashboardBinding(
'With root folder and other folder',
['', 'Folder 3']
);
export const getDatasource = async (ref: DataSourceRef) => {
if (ref.uid === '-- Grafana --') {
return {
id: 1,
uid: '-- Grafana --',
name: 'grafana',
type: 'grafana',
meta: {
id: 'grafana',
},
};
}
return {
meta: {
id: 'grafana-testdata-datasource',
},
name: 'grafana-testdata-datasource',
type: 'grafana-testdata-datasource',
uid: 'gdev-testdata',
getRef: () => {
return { type: 'grafana-testdata-datasource', uid: 'gdev-testdata' };
},
};
};
export const getInstanceSettings = () => ({
id: 1,
uid: 'gdev-testdata',
name: 'testDs1',
type: 'grafana-testdata-datasource',
meta: {
id: 'grafana-testdata-datasource',
},
});