mirror of
https://github.com/grafana/grafana.git
synced 2025-01-16 03:32:37 -06:00
8c8f584b41
* feat(plugins): introduce dashboard panel menu placement for adding menu items
* test: add test for getPanelMenu()
* added an unique identifier for each extension.
* added context to getPluginExtensions.
* wip
* Wip
* wiwip
* Wip
* feat: WWWIIIIPPPP 🧨
* Wip
* Renamed some of the types to align a bit better.
* added limit to how many extensions a plugin can register per placement.
* decreased number of items to 2
* will trim the lenght of titles to max 25 chars.
* wrapping configure function with error handling.
* added error handling for all scenarios.
* moved extension menu items to the bottom of the more sub menu.
* added tests for configuring the title.
* minor refactorings.
* changed so you need to specify the full path in package.json.
* wip
* removed unused type.
* big refactor to make things simpler and to centralize all configure error/validation handling.
* added missing import.
* fixed failing tests.
* fixed tests.
* revert(extensions): remove static extensions config in favour of registering via AppPlugin APIs
* removed the compose that didn't work for some reason.
* added tests just to verify that validation and error handling is tied together in configuration function.
* adding some more values to the context.
* draft validation.
* added missing tests for getPanelMenu.
* added more tests.
* refactor(extensions): move logic for validating extension link config to function
* Fixed ts errors.
* Update packages/grafana-data/src/types/app.ts
Co-authored-by: Levente Balogh <balogh.levente.hu@gmail.com>
* Update packages/grafana-runtime/src/services/pluginExtensions/extensions.test.ts
Co-authored-by: Levente Balogh <balogh.levente.hu@gmail.com>
* refactor(extensions): rename limiter -> pluginPlacementCount
* refactor(getpanelmenu): remove redundant continue statement
---------
Co-authored-by: Levente Balogh <balogh.levente.hu@gmail.com>
Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com>
182 lines
5.1 KiB
TypeScript
182 lines
5.1 KiB
TypeScript
import React, { useMemo, useState } from 'react';
|
|
import { useObservable } from 'react-use';
|
|
import AutoSizer from 'react-virtualized-auto-sizer';
|
|
|
|
import {
|
|
ApplyFieldOverrideOptions,
|
|
dateMath,
|
|
FieldColorModeId,
|
|
isPluginExtensionLink,
|
|
NavModelItem,
|
|
PanelData,
|
|
} from '@grafana/data';
|
|
import { getPluginExtensions } from '@grafana/runtime';
|
|
import { DataTransformerConfig } from '@grafana/schema';
|
|
import { Button, HorizontalGroup, LinkButton, Table } from '@grafana/ui';
|
|
import { Page } from 'app/core/components/Page/Page';
|
|
import { config } from 'app/core/config';
|
|
import { useAppNotification } from 'app/core/copy/appNotification';
|
|
import { QueryGroupOptions } from 'app/types';
|
|
|
|
import { PanelRenderer } from '../panel/components/PanelRenderer';
|
|
import { QueryGroup } from '../query/components/QueryGroup';
|
|
import { PanelQueryRunner } from '../query/state/PanelQueryRunner';
|
|
|
|
interface State {
|
|
queryRunner: PanelQueryRunner;
|
|
queryOptions: QueryGroupOptions;
|
|
data?: PanelData;
|
|
}
|
|
|
|
export const TestStuffPage = () => {
|
|
const [state, setState] = useState<State>(getDefaultState());
|
|
const { queryOptions, queryRunner } = state;
|
|
|
|
const onRunQueries = () => {
|
|
const timeRange = { from: 'now-1h', to: 'now' };
|
|
|
|
queryRunner.run({
|
|
queries: queryOptions.queries,
|
|
datasource: queryOptions.dataSource,
|
|
timezone: 'browser',
|
|
timeRange: { from: dateMath.parse(timeRange.from)!, to: dateMath.parse(timeRange.to)!, raw: timeRange },
|
|
maxDataPoints: queryOptions.maxDataPoints ?? 100,
|
|
minInterval: queryOptions.minInterval,
|
|
});
|
|
};
|
|
|
|
const onOptionsChange = (queryOptions: QueryGroupOptions) => {
|
|
setState({ ...state, queryOptions });
|
|
};
|
|
|
|
/**
|
|
* Subscribe to data
|
|
*/
|
|
const observable = useMemo(() => queryRunner.getData({ withFieldConfig: true, withTransforms: true }), [queryRunner]);
|
|
const data = useObservable(observable);
|
|
|
|
const node: NavModelItem = {
|
|
id: 'test-page',
|
|
text: 'Test page',
|
|
icon: 'dashboard',
|
|
subTitle: 'FOR TESTING!',
|
|
url: 'sandbox/test',
|
|
};
|
|
|
|
const notifyApp = useAppNotification();
|
|
|
|
return (
|
|
<Page navModel={{ node: node, main: node }}>
|
|
<Page.Contents>
|
|
<HorizontalGroup>
|
|
<LinkToBasicApp placement="grafana/sandbox/testing" />
|
|
</HorizontalGroup>
|
|
{data && (
|
|
<AutoSizer style={{ width: '100%', height: '600px' }}>
|
|
{({ width }) => {
|
|
return (
|
|
<div>
|
|
<PanelRenderer
|
|
title="Hello"
|
|
pluginId="timeseries"
|
|
width={width}
|
|
height={300}
|
|
data={data}
|
|
options={{}}
|
|
fieldConfig={{ defaults: {}, overrides: [] }}
|
|
timeZone="browser"
|
|
/>
|
|
<Table data={data.series[0]} width={width} height={300} />
|
|
</div>
|
|
);
|
|
}}
|
|
</AutoSizer>
|
|
)}
|
|
<div style={{ marginTop: '16px', height: '45%' }}>
|
|
<QueryGroup
|
|
options={queryOptions}
|
|
queryRunner={queryRunner}
|
|
onRunQueries={onRunQueries}
|
|
onOptionsChange={onOptionsChange}
|
|
/>
|
|
</div>
|
|
<div style={{ display: 'flex', gap: '1em' }}>
|
|
<Button onClick={() => notifyApp.success('Success toast', 'some more text goes here')} variant="primary">
|
|
Success
|
|
</Button>
|
|
<Button
|
|
onClick={() => notifyApp.warning('Warning toast', 'some more text goes here', 'bogus-trace-99999')}
|
|
variant="secondary"
|
|
>
|
|
Warning
|
|
</Button>
|
|
<Button
|
|
onClick={() => notifyApp.error('Error toast', 'some more text goes here', 'bogus-trace-fdsfdfsfds')}
|
|
variant="destructive"
|
|
>
|
|
Error
|
|
</Button>
|
|
</div>
|
|
</Page.Contents>
|
|
</Page>
|
|
);
|
|
};
|
|
|
|
export function getDefaultState(): State {
|
|
const options: ApplyFieldOverrideOptions = {
|
|
fieldConfig: {
|
|
defaults: {
|
|
color: {
|
|
mode: FieldColorModeId.PaletteClassic,
|
|
},
|
|
},
|
|
overrides: [],
|
|
},
|
|
replaceVariables: (v: string) => v,
|
|
theme: config.theme2,
|
|
};
|
|
|
|
const dataConfig = {
|
|
getTransformations: () => [] as DataTransformerConfig[],
|
|
getFieldOverrideOptions: () => options,
|
|
getDataSupport: () => ({ annotations: false, alertStates: false }),
|
|
};
|
|
|
|
return {
|
|
queryRunner: new PanelQueryRunner(dataConfig),
|
|
queryOptions: {
|
|
queries: [],
|
|
dataSource: {
|
|
name: 'gdev-testdata',
|
|
},
|
|
maxDataPoints: 100,
|
|
savedQueryUid: null,
|
|
},
|
|
};
|
|
}
|
|
|
|
function LinkToBasicApp({ placement }: { placement: string }) {
|
|
const { extensions } = getPluginExtensions({ placement });
|
|
|
|
if (extensions.length === 0) {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
<div>
|
|
{extensions.map((extension) => {
|
|
if (!isPluginExtensionLink(extension)) {
|
|
return null;
|
|
}
|
|
return (
|
|
<LinkButton href={extension.path} title={extension.description} key={extension.key}>
|
|
{extension.title}
|
|
</LinkButton>
|
|
);
|
|
})}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default TestStuffPage;
|