mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Chore: Upgrade to react 18 (#64428)
* update react 18 related deps * fix some types * make sure we're on react-router-dom >= 5.3.3 * Use new root API * Remove StrictMode for now - react 18 double rendering causes issues * fix + ignore some @grafana/ui types * fix some more types * use renderHook from @testing-library/react in almost all cases * fix storybook types * rewrite useDashboardSave to not use useEffect * make props optional * only render if props are provided * add correct type for useCallback * make resourcepicker tests more robust * fix ModalManager rendering * fix some more unit tests * store the click coordinates in a ref as setState is NOT synchronous * fix remaining e2e tests * rewrite dashboardpage tests to avoid act warnings * undo lint ignores * fix ExpanderCell types * set SymbolCell type correctly * fix QueryAndExpressionsStep * looks like the types were actually wrong instead :D * undo this for now... * remove spinner waits * more robust tests * rewrite errorboundary test to not explicitly count the number of renders * make urlParam expect async * increase timeout in waitFor * revert ExplorePage test changes * Update public/app/features/dashboard/containers/DashboardPage.test.tsx Co-authored-by: Alex Khomenko <Clarity-89@users.noreply.github.com> * Update public/app/features/dashboard/containers/PublicDashboardPage.test.tsx Co-authored-by: Alex Khomenko <Clarity-89@users.noreply.github.com> * Update public/app/features/dashboard/containers/PublicDashboardPage.test.tsx Co-authored-by: Alex Khomenko <Clarity-89@users.noreply.github.com> * Update public/app/features/dashboard/containers/PublicDashboardPage.test.tsx Co-authored-by: Alex Khomenko <Clarity-89@users.noreply.github.com> * skip fakeTimer test, ignore table types for now + other review comments * update package peerDeps * small tweak to resourcepicker test * update lockfile... * increase timeout in sharepublicdashboard tests * ensure ExplorePaneContainer passes correct queries to initializeExplore * fix LokiContextUI test * fix unit tests * make importDashboard flow more consistent * wait for dashboard name before continuing * more test fixes * readd dashboard name to variable e2e tests * wait for switches to be enabled before clicking * fix modal rendering * don't use @testing-library/dom directly * quick fix for rendering of panels in firefox * make PromQueryField test more robust * don't wait for chartData - in react 18 this can happen before the wait code even gets executed --------- Co-authored-by: kay delaney <kay@grafana.com> Co-authored-by: Alex Khomenko <Clarity-89@users.noreply.github.com>
This commit is contained in:
parent
a5499bbf70
commit
1261345b81
10
.github/renovate.json5
vendored
10
.github/renovate.json5
vendored
@ -22,16 +22,6 @@
|
||||
"@sentry/browser",
|
||||
"@sentry/types",
|
||||
"@sentry/utils",
|
||||
|
||||
// dep updates blocked by React 18
|
||||
"@testing-library/dom",
|
||||
"@testing-library/react",
|
||||
"@types/react",
|
||||
"@types/react-dom",
|
||||
"@types/react-test-renderer",
|
||||
"react",
|
||||
"react-dom",
|
||||
"react-test-renderer"
|
||||
],
|
||||
"includePaths": ["package.json", "packages/**"],
|
||||
"ignorePaths": ["packages/grafana-toolkit/package.json", "emails/**", "plugins-bundled/**", "**/mocks/**"],
|
||||
|
@ -0,0 +1,14 @@
|
||||
diff --git a/dist/ts3.9/blocks/DocsContainer.d.ts b/dist/ts3.9/blocks/DocsContainer.d.ts
|
||||
index be330e44bebb02eaf2c92d365d4e7dc1da452465..6c8b1d42bea2e184456e2757eb2ee20076ba43b3 100644
|
||||
--- a/dist/ts3.9/blocks/DocsContainer.d.ts
|
||||
+++ b/dist/ts3.9/blocks/DocsContainer.d.ts
|
||||
@@ -1,7 +1,8 @@
|
||||
-import { FunctionComponent } from 'react';
|
||||
+import { FunctionComponent, ReactNode } from 'react';
|
||||
import { AnyFramework } from '@storybook/csf';
|
||||
import { DocsContextProps } from './DocsContext';
|
||||
export interface DocsContainerProps<TFramework extends AnyFramework = AnyFramework> {
|
||||
context: DocsContextProps<TFramework>;
|
||||
+ children?: ReactNode;
|
||||
}
|
||||
export declare const DocsContainer: FunctionComponent<DocsContainerProps>;
|
12
.yarn/patches/react-split-pane-npm-0.1.92-93dbf51dff.patch
Normal file
12
.yarn/patches/react-split-pane-npm-0.1.92-93dbf51dff.patch
Normal file
@ -0,0 +1,12 @@
|
||||
diff --git a/index.d.ts b/index.d.ts
|
||||
index d116f54d6da12d24b48e24ff3636c9066059aa58..93290945d8b1818cab893d6466179b33869a47b9 100644
|
||||
--- a/index.d.ts
|
||||
+++ b/index.d.ts
|
||||
@@ -25,6 +25,7 @@ export type SplitPaneProps = {
|
||||
pane2Style?: React.CSSProperties;
|
||||
resizerClassName?: string;
|
||||
step?: number;
|
||||
+ children?: React.ReactNode;
|
||||
};
|
||||
|
||||
export type SplitPaneState = {
|
@ -1,5 +1,6 @@
|
||||
import { e2e } from '@grafana/e2e';
|
||||
const PAGE_UNDER_TEST = 'k3PEoCpnk/repeating-a-row-with-a-non-repeating-panel-and-horizontal-repeating-panel';
|
||||
const DASHBOARD_NAME = 'Repeating a row with a non-repeating panel and horizontal repeating panel';
|
||||
|
||||
describe('Repeating a row with repeated panels and a non-repeating panel', () => {
|
||||
beforeEach(() => {
|
||||
@ -8,6 +9,7 @@ describe('Repeating a row with repeated panels and a non-repeating panel', () =>
|
||||
|
||||
it('should be able to collapse and expand a repeated row without losing panels', () => {
|
||||
e2e.flows.openDashboard({ uid: PAGE_UNDER_TEST });
|
||||
e2e().contains(DASHBOARD_NAME).should('be.visible');
|
||||
|
||||
const panelsToCheck = [
|
||||
'Row 2 non-repeating panel',
|
||||
|
@ -2,11 +2,13 @@ import { e2e } from '@grafana/e2e';
|
||||
import { GrafanaBootConfig } from '@grafana/runtime';
|
||||
|
||||
const PAGE_UNDER_TEST = 'kVi2Gex7z/test-variable-output';
|
||||
const DASHBOARD_NAME = 'Test variable output';
|
||||
|
||||
describe('Variables - Constant', () => {
|
||||
it('can add a new constant variable', () => {
|
||||
e2e.flows.login('admin', 'admin');
|
||||
e2e.flows.openDashboard({ uid: `${PAGE_UNDER_TEST}?orgId=1&editview=templating` });
|
||||
e2e().contains(DASHBOARD_NAME).should('be.visible');
|
||||
|
||||
// Create a new "Constant" variable
|
||||
e2e.components.CallToActionCard.buttonV2('Add variable').click();
|
||||
@ -15,8 +17,8 @@ describe('Variables - Constant', () => {
|
||||
e2e().get('input').type('Constant{enter}');
|
||||
});
|
||||
e2e.pages.Dashboard.Settings.Variables.Edit.General.generalNameInputV2().clear().type('VariableUnderTest').blur();
|
||||
e2e.pages.Dashboard.Settings.Variables.Edit.General.generalLabelInputV2().type('Variable under test').blur();
|
||||
e2e.pages.Dashboard.Settings.Variables.Edit.ConstantVariable.constantOptionsQueryInputV2().type('pesto').blur();
|
||||
e2e.pages.Dashboard.Settings.Variables.Edit.General.generalLabelInputV2().type('Variable under test').blur();
|
||||
|
||||
e2e.pages.Dashboard.Settings.Variables.Edit.General.previewOfValuesOption().eq(0).should('have.text', 'pesto');
|
||||
|
||||
|
@ -2,6 +2,7 @@ import { e2e } from '@grafana/e2e';
|
||||
import { GrafanaBootConfig } from '@grafana/runtime';
|
||||
|
||||
const PAGE_UNDER_TEST = 'kVi2Gex7z/test-variable-output';
|
||||
const DASHBOARD_NAME = 'Test variable output';
|
||||
|
||||
function fillInCustomVariable(name: string, label: string, value: string) {
|
||||
e2e.pages.Dashboard.Settings.Variables.Edit.General.generalTypeSelectV2().within(() => {
|
||||
@ -23,6 +24,7 @@ describe('Variables - Custom', () => {
|
||||
it('can add a custom template variable', () => {
|
||||
e2e.flows.login('admin', 'admin');
|
||||
e2e.flows.openDashboard({ uid: `${PAGE_UNDER_TEST}?orgId=1&editview=templating` });
|
||||
e2e().contains(DASHBOARD_NAME).should('be.visible');
|
||||
|
||||
// Create a new "Custom" variable
|
||||
e2e.components.CallToActionCard.buttonV2('Add variable').click();
|
||||
@ -50,6 +52,7 @@ describe('Variables - Custom', () => {
|
||||
it('can add a custom template variable with labels', () => {
|
||||
e2e.flows.login('admin', 'admin');
|
||||
e2e.flows.openDashboard({ uid: `${PAGE_UNDER_TEST}?orgId=1&editview=templating` });
|
||||
e2e().contains(DASHBOARD_NAME).should('be.visible');
|
||||
|
||||
// Create a new "Custom" variable
|
||||
e2e.components.CallToActionCard.buttonV2('Add variable').click();
|
||||
|
@ -2,11 +2,13 @@ import { e2e } from '@grafana/e2e';
|
||||
import { GrafanaBootConfig } from '@grafana/runtime';
|
||||
|
||||
const PAGE_UNDER_TEST = 'kVi2Gex7z/test-variable-output';
|
||||
const DASHBOARD_NAME = 'Test variable output';
|
||||
|
||||
describe('Variables - Datasource', () => {
|
||||
it('can add a new datasource variable', () => {
|
||||
e2e.flows.login('admin', 'admin');
|
||||
e2e.flows.openDashboard({ uid: `${PAGE_UNDER_TEST}?orgId=1&editview=templating` });
|
||||
e2e().contains(DASHBOARD_NAME).should('be.visible');
|
||||
|
||||
// Create a new "Datasource" variable
|
||||
e2e.components.CallToActionCard.buttonV2('Add variable').click();
|
||||
|
@ -2,6 +2,7 @@ import { e2e } from '@grafana/e2e';
|
||||
import { GrafanaBootConfig } from '@grafana/runtime';
|
||||
|
||||
const PAGE_UNDER_TEST = 'kVi2Gex7z/test-variable-output';
|
||||
const DASHBOARD_NAME = 'Test variable output';
|
||||
|
||||
function assertPreviewValues(expectedValues: string[]) {
|
||||
for (const expected of expectedValues) {
|
||||
@ -14,6 +15,7 @@ describe('Variables - Interval', () => {
|
||||
it('can add a new interval variable', () => {
|
||||
e2e.flows.login('admin', 'admin');
|
||||
e2e.flows.openDashboard({ uid: `${PAGE_UNDER_TEST}?orgId=1&editview=templating` });
|
||||
e2e().contains(DASHBOARD_NAME).should('be.visible');
|
||||
|
||||
// Create a new "Interval" variable
|
||||
e2e.components.CallToActionCard.buttonV2('Add variable').click();
|
||||
|
@ -2,11 +2,13 @@ import { e2e } from '@grafana/e2e';
|
||||
import { GrafanaBootConfig } from '@grafana/runtime';
|
||||
|
||||
const PAGE_UNDER_TEST = '-Y-tnEDWk/templating-nested-template-variables';
|
||||
const DASHBOARD_NAME = 'Templating - Nested Template Variables';
|
||||
|
||||
describe('Variables - Query - Add variable', () => {
|
||||
it('query variable should be default and default fields should be correct', () => {
|
||||
e2e.flows.login('admin', 'admin');
|
||||
e2e.flows.openDashboard({ uid: `${PAGE_UNDER_TEST}?orgId=1&editview=templating` });
|
||||
e2e().contains(DASHBOARD_NAME).should('be.visible');
|
||||
|
||||
e2e.pages.Dashboard.Settings.Variables.List.newButton().should('be.visible').click();
|
||||
|
||||
@ -77,6 +79,7 @@ describe('Variables - Query - Add variable', () => {
|
||||
it('adding a single value query variable', () => {
|
||||
e2e.flows.login('admin', 'admin');
|
||||
e2e.flows.openDashboard({ uid: `${PAGE_UNDER_TEST}?orgId=1&editview=templating` });
|
||||
e2e().contains(DASHBOARD_NAME).should('be.visible');
|
||||
|
||||
e2e.pages.Dashboard.Settings.Variables.List.newButton().should('be.visible').click();
|
||||
|
||||
@ -132,6 +135,7 @@ describe('Variables - Query - Add variable', () => {
|
||||
it('adding a multi value query variable', () => {
|
||||
e2e.flows.login('admin', 'admin');
|
||||
e2e.flows.openDashboard({ uid: `${PAGE_UNDER_TEST}?orgId=1&editview=templating` });
|
||||
e2e().contains(DASHBOARD_NAME).should('be.visible');
|
||||
|
||||
e2e.pages.Dashboard.Settings.Variables.List.newButton().should('be.visible').click();
|
||||
|
||||
|
@ -2,11 +2,13 @@ import { e2e } from '@grafana/e2e';
|
||||
import { GrafanaBootConfig } from '@grafana/runtime';
|
||||
|
||||
const PAGE_UNDER_TEST = 'kVi2Gex7z/test-variable-output';
|
||||
const DASHBOARD_NAME = 'Test variable output';
|
||||
|
||||
describe('Variables - Text box', () => {
|
||||
it('can add a new text box variable', () => {
|
||||
e2e.flows.login('admin', 'admin');
|
||||
e2e.flows.openDashboard({ uid: `${PAGE_UNDER_TEST}?orgId=1&editview=templating` });
|
||||
e2e().contains(DASHBOARD_NAME).should('be.visible');
|
||||
|
||||
// Create a new "text box" variable
|
||||
e2e.components.CallToActionCard.buttonV2('Add variable').click();
|
||||
|
@ -29,7 +29,9 @@ describe('Trace view', () => {
|
||||
e2e.pages.Explore.General.scrollView().children('.scrollbar-view').scrollTo('center');
|
||||
|
||||
// After scrolling we should load more spans
|
||||
e2e.components.TraceViewer.spanBar().its('length').should('be.gt', oldLength);
|
||||
e2e.components.TraceViewer.spanBar().should(($span) => {
|
||||
expect($span.length).to.be.gt(oldLength);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
24
package.json
24
package.json
@ -114,10 +114,9 @@
|
||||
"@rtsao/plugin-proposal-class-properties": "7.0.1-patch.1",
|
||||
"@swc/core": "1.3.38",
|
||||
"@swc/helpers": "0.4.14",
|
||||
"@testing-library/dom": "8.20.0",
|
||||
"@testing-library/dom": "9.0.1",
|
||||
"@testing-library/jest-dom": "5.16.5",
|
||||
"@testing-library/react": "12.1.4",
|
||||
"@testing-library/react-hooks": "8.0.1",
|
||||
"@testing-library/react": "14.0.0",
|
||||
"@testing-library/user-event": "14.4.3",
|
||||
"@types/angular": "1.8.4",
|
||||
"@types/angular-route": "1.7.2",
|
||||
@ -146,15 +145,15 @@
|
||||
"@types/papaparse": "5.3.7",
|
||||
"@types/pluralize": "^0.0.29",
|
||||
"@types/prismjs": "1.26.0",
|
||||
"@types/react": "17.0.42",
|
||||
"@types/react": "18.0.28",
|
||||
"@types/react-beautiful-dnd": "13.1.3",
|
||||
"@types/react-dom": "17.0.14",
|
||||
"@types/react-dom": "18.0.11",
|
||||
"@types/react-grid-layout": "1.3.2",
|
||||
"@types/react-highlight-words": "0.16.4",
|
||||
"@types/react-redux": "7.1.25",
|
||||
"@types/react-router-dom": "5.3.3",
|
||||
"@types/react-table": "7.7.14",
|
||||
"@types/react-test-renderer": "17.0.1",
|
||||
"@types/react-test-renderer": "18.0.0",
|
||||
"@types/react-transition-group": "4.4.5",
|
||||
"@types/react-virtualized-auto-sizer": "1.0.1",
|
||||
"@types/react-window": "1.8.5",
|
||||
@ -226,7 +225,7 @@
|
||||
"react-refresh": "0.14.0",
|
||||
"react-select-event": "5.5.1",
|
||||
"react-simple-compat": "1.2.3",
|
||||
"react-test-renderer": "17.0.2",
|
||||
"react-test-renderer": "18.2.0",
|
||||
"redux-mock-store": "1.5.4",
|
||||
"rimraf": "4.4.0",
|
||||
"rudder-sdk-js": "2.25.0",
|
||||
@ -294,6 +293,7 @@
|
||||
"@sentry/browser": "6.19.7",
|
||||
"@sentry/types": "6.19.7",
|
||||
"@sentry/utils": "6.19.7",
|
||||
"@testing-library/react-hooks": "^8.0.1",
|
||||
"@types/react-resizable": "3.0.3",
|
||||
"@types/webpack-env": "1.18.0",
|
||||
"@visx/event": "3.0.1",
|
||||
@ -366,11 +366,11 @@
|
||||
"rc-time-picker": "3.7.3",
|
||||
"rc-tree": "5.7.2",
|
||||
"re-resizable": "6.9.9",
|
||||
"react": "17.0.2",
|
||||
"react": "18.2.0",
|
||||
"react-awesome-query-builder": "5.4.0",
|
||||
"react-beautiful-dnd": "13.1.1",
|
||||
"react-diff-viewer": "^3.1.1",
|
||||
"react-dom": "17.0.2",
|
||||
"react-dom": "18.2.0",
|
||||
"react-draggable": "4.4.5",
|
||||
"react-dropzone": "^14.2.3",
|
||||
"react-enable": "^3.1.0",
|
||||
@ -385,7 +385,7 @@
|
||||
"react-redux": "7.2.6",
|
||||
"react-resizable": "3.0.4",
|
||||
"react-reverse-portal": "2.1.1",
|
||||
"react-router-dom": "^5.2.0",
|
||||
"react-router-dom": "5.3.3",
|
||||
"react-select": "5.7.0",
|
||||
"react-split-pane": "0.1.92",
|
||||
"react-table": "7.8.0",
|
||||
@ -437,7 +437,9 @@
|
||||
"@storybook/manager-webpack5/webpack": "5.76.0",
|
||||
"ngtemplate-loader/loader-utils": "^2.0.0",
|
||||
"trim": "0.0.3",
|
||||
"slate-dev-environment@^0.2.2": "patch:slate-dev-environment@npm:0.2.5#.yarn/patches/slate-dev-environment-npm-0.2.5-9aeb7da7b5.patch"
|
||||
"slate-dev-environment@^0.2.2": "patch:slate-dev-environment@npm:0.2.5#.yarn/patches/slate-dev-environment-npm-0.2.5-9aeb7da7b5.patch",
|
||||
"react-split-pane@0.1.92": "patch:react-split-pane@npm:0.1.92#.yarn/patches/react-split-pane-npm-0.1.92-93dbf51dff.patch",
|
||||
"@storybook/addon-docs@6.5.16": "patch:@storybook/addon-docs@npm:6.5.16#.yarn/patches/@storybook-addon-docs-npm-6.5.16-56ecbd77e7.patch"
|
||||
},
|
||||
"workspaces": {
|
||||
"packages": [
|
||||
|
@ -63,10 +63,9 @@
|
||||
"@rollup/plugin-commonjs": "23.0.2",
|
||||
"@rollup/plugin-json": "5.0.1",
|
||||
"@rollup/plugin-node-resolve": "15.0.1",
|
||||
"@testing-library/dom": "8.20.0",
|
||||
"@testing-library/dom": "9.0.1",
|
||||
"@testing-library/jest-dom": "5.16.5",
|
||||
"@testing-library/react": "12.1.4",
|
||||
"@testing-library/react-hooks": "8.0.1",
|
||||
"@testing-library/react": "14.0.0",
|
||||
"@testing-library/user-event": "14.4.3",
|
||||
"@types/dompurify": "^2",
|
||||
"@types/history": "4.7.11",
|
||||
@ -76,15 +75,15 @@
|
||||
"@types/marked": "4.0.8",
|
||||
"@types/node": "18.14.6",
|
||||
"@types/papaparse": "5.3.7",
|
||||
"@types/react": "17.0.42",
|
||||
"@types/react-dom": "17.0.14",
|
||||
"@types/react": "18.0.28",
|
||||
"@types/react-dom": "18.0.11",
|
||||
"@types/sinon": "10.0.13",
|
||||
"@types/testing-library__jest-dom": "5.14.5",
|
||||
"@types/tinycolor2": "1.4.3",
|
||||
"esbuild": "0.16.17",
|
||||
"react": "17.0.2",
|
||||
"react-dom": "17.0.2",
|
||||
"react-test-renderer": "17.0.2",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react-test-renderer": "18.2.0",
|
||||
"rimraf": "4.4.0",
|
||||
"rollup": "2.79.1",
|
||||
"rollup-plugin-dts": "^5.0.0",
|
||||
@ -94,7 +93,7 @@
|
||||
"typescript": "4.8.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.0 || ^17.0.0",
|
||||
"react-dom": "^16.8.0 || ^17.0.0"
|
||||
"react": "^17.0.0 || ^18.0.0",
|
||||
"react-dom": "^17.0.0 || ^18.0.0"
|
||||
}
|
||||
}
|
||||
|
@ -141,7 +141,6 @@ export const configurePanel = (config: PartialAddPanelConfig | PartialEditPanelC
|
||||
|
||||
if (queriesForm) {
|
||||
queriesForm(fullConfig);
|
||||
e2e().wait('@chartData');
|
||||
|
||||
// Wait for a possible complex visualization to render (or something related, as this isn't necessary on the dashboard page)
|
||||
// Can't assert that its HTML changed because a new query could produce the same results
|
||||
@ -158,8 +157,6 @@ export const configurePanel = (config: PartialAddPanelConfig | PartialEditPanelC
|
||||
// Avoid annotations flakiness
|
||||
e2e.components.RefreshPicker.runButtonV2().first().click({ force: true });
|
||||
|
||||
e2e().wait('@chartData');
|
||||
|
||||
// Wait for RxJS
|
||||
e2e().wait(500);
|
||||
|
||||
|
@ -20,10 +20,9 @@ export const importDashboard = (dashboardToImport: Dashboard, queryTimeout?: num
|
||||
e2e().visit(fromBaseUrl('/dashboard/import'));
|
||||
|
||||
// Note: normally we'd use 'click' and then 'type' here, but the json object is so big that using 'val' is much faster
|
||||
e2e.components.DashboardImportPage.textarea()
|
||||
.should('be.visible')
|
||||
.click()
|
||||
.invoke('val', JSON.stringify(dashboardToImport));
|
||||
e2e.components.DashboardImportPage.textarea().should('be.visible');
|
||||
e2e.components.DashboardImportPage.textarea().click();
|
||||
e2e.components.DashboardImportPage.textarea().invoke('val', JSON.stringify(dashboardToImport));
|
||||
e2e.components.DashboardImportPage.submit().should('be.visible').click();
|
||||
e2e.components.ImportDashboardForm.name().should('be.visible').click().clear().type(dashboardToImport.title);
|
||||
e2e.components.ImportDashboardForm.submit().should('be.visible').click();
|
||||
|
@ -52,21 +52,20 @@
|
||||
"@grafana/tsconfig": "^1.2.0-rc1",
|
||||
"@rollup/plugin-commonjs": "23.0.2",
|
||||
"@rollup/plugin-node-resolve": "15.0.1",
|
||||
"@testing-library/dom": "8.20.0",
|
||||
"@testing-library/react": "12.1.4",
|
||||
"@testing-library/react-hooks": "8.0.1",
|
||||
"@testing-library/dom": "9.0.1",
|
||||
"@testing-library/react": "14.0.0",
|
||||
"@testing-library/user-event": "14.4.3",
|
||||
"@types/angular": "1.8.4",
|
||||
"@types/history": "4.7.11",
|
||||
"@types/jest": "29.2.3",
|
||||
"@types/lodash": "4.14.191",
|
||||
"@types/react": "17.0.42",
|
||||
"@types/react-dom": "17.0.14",
|
||||
"@types/react": "18.0.28",
|
||||
"@types/react-dom": "18.0.11",
|
||||
"@types/systemjs": "^0.20.6",
|
||||
"esbuild": "0.16.17",
|
||||
"lodash": "4.17.21",
|
||||
"react": "17.0.2",
|
||||
"react-dom": "17.0.2",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"rimraf": "4.4.0",
|
||||
"rollup": "2.79.1",
|
||||
"rollup-plugin-dts": "^5.0.0",
|
||||
@ -77,7 +76,7 @@
|
||||
"typescript": "4.8.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "17.0.2",
|
||||
"react-dom": "17.0.2"
|
||||
"react": "^17.0.0 || ^18.0.0",
|
||||
"react-dom": "^17.0.0 || ^18.0.0"
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { renderHook } from '@testing-library/react-hooks';
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
|
||||
import {
|
||||
|
@ -97,7 +97,7 @@
|
||||
"react-inlinesvg": "3.0.2",
|
||||
"react-popper": "2.3.0",
|
||||
"react-popper-tooltip": "4.4.2",
|
||||
"react-router-dom": "^5.2.0",
|
||||
"react-router-dom": "5.3.3",
|
||||
"react-select": "5.7.0",
|
||||
"react-select-event": "^5.1.0",
|
||||
"react-table": "7.8.0",
|
||||
@ -134,10 +134,9 @@
|
||||
"@storybook/preset-scss": "1.0.3",
|
||||
"@storybook/react": "6.5.16",
|
||||
"@storybook/theming": "6.5.16",
|
||||
"@testing-library/dom": "8.20.0",
|
||||
"@testing-library/dom": "9.0.1",
|
||||
"@testing-library/jest-dom": "5.16.5",
|
||||
"@testing-library/react": "12.1.4",
|
||||
"@testing-library/react-hooks": "8.0.1",
|
||||
"@testing-library/react": "14.0.0",
|
||||
"@testing-library/user-event": "14.4.3",
|
||||
"@types/common-tags": "^1.8.0",
|
||||
"@types/d3": "7.4.0",
|
||||
@ -149,15 +148,15 @@
|
||||
"@types/mock-raf": "1.0.3",
|
||||
"@types/node": "18.14.6",
|
||||
"@types/prismjs": "1.26.0",
|
||||
"@types/react": "17.0.42",
|
||||
"@types/react": "18.0.28",
|
||||
"@types/react-beautiful-dnd": "13.1.3",
|
||||
"@types/react-calendar": "3.9.0",
|
||||
"@types/react-color": "3.0.6",
|
||||
"@types/react-dom": "17.0.14",
|
||||
"@types/react-dom": "18.0.11",
|
||||
"@types/react-highlight-words": "0.16.4",
|
||||
"@types/react-router-dom": "5.3.3",
|
||||
"@types/react-table": "7.7.14",
|
||||
"@types/react-test-renderer": "17.0.1",
|
||||
"@types/react-test-renderer": "18.0.0",
|
||||
"@types/react-transition-group": "4.4.5",
|
||||
"@types/react-window": "1.8.5",
|
||||
"@types/slate": "0.47.11",
|
||||
@ -173,9 +172,9 @@
|
||||
"expose-loader": "4.0.0",
|
||||
"mock-raf": "1.0.1",
|
||||
"process": "^0.11.10",
|
||||
"react": "17.0.2",
|
||||
"react-dom": "17.0.2",
|
||||
"react-test-renderer": "17.0.2",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react-test-renderer": "18.2.0",
|
||||
"rimraf": "4.4.0",
|
||||
"rollup": "2.79.1",
|
||||
"rollup-plugin-dts": "^5.0.0",
|
||||
@ -190,7 +189,7 @@
|
||||
"webpack": "5.76.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.0 || ^17.0.0",
|
||||
"react-dom": "^16.8.0 || ^17.0.0"
|
||||
"react": "^17.0.0 || ^18.0.0",
|
||||
"react-dom": "^17.0.0 || ^18.0.0"
|
||||
}
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ export const Dropdown = React.memo(({ children, overlay, placement, offset, onVi
|
||||
timeout={{ appear: animationDuration, exit: 0, enter: 0 }}
|
||||
classNames={animationStyles}
|
||||
>
|
||||
<div ref={transitionRef}>{ReactUtils.renderOrCallToRender(overlay)}</div>
|
||||
<div ref={transitionRef}>{ReactUtils.renderOrCallToRender(overlay, {})}</div>
|
||||
</CSSTransition>
|
||||
</div>
|
||||
</FocusScope>
|
||||
|
@ -57,7 +57,7 @@ describe('ErrorBoundary', () => {
|
||||
expect((faro.api.pushError as jest.Mock).mock.calls[0][0]).toBe(problem);
|
||||
});
|
||||
|
||||
it('should recover when when recover props change', async () => {
|
||||
it('should rerender when recover props change', async () => {
|
||||
const problem = new Error('things went terribly wrong');
|
||||
let renderCount = 0;
|
||||
|
||||
@ -75,6 +75,8 @@ describe('ErrorBoundary', () => {
|
||||
);
|
||||
|
||||
await screen.findByText(problem.message);
|
||||
expect(renderCount).toBeGreaterThan(0);
|
||||
const oldRenderCount = renderCount;
|
||||
|
||||
rerender(
|
||||
<ErrorBoundary dependencies={[1, 3]}>
|
||||
@ -89,6 +91,6 @@ describe('ErrorBoundary', () => {
|
||||
</ErrorBoundary>
|
||||
);
|
||||
|
||||
expect(renderCount).toBe(2);
|
||||
expect(renderCount).toBeGreaterThan(oldRenderCount);
|
||||
});
|
||||
});
|
||||
|
@ -10,7 +10,7 @@ const expanderContainerStyles = css`
|
||||
height: 100%;
|
||||
`;
|
||||
|
||||
export function ExpanderCell<K extends object>({ row, __rowID }: CellProps<K, void> & { __rowID: string }) {
|
||||
export function ExpanderCell<K extends object>({ row, __rowID }: CellProps<K, void>) {
|
||||
return (
|
||||
<div className={expanderContainerStyles}>
|
||||
<IconButton
|
||||
|
@ -158,13 +158,14 @@ export const LogRowContextGroup = ({
|
||||
<List
|
||||
items={rows}
|
||||
renderItem={(item) => {
|
||||
const message = typeof item === 'string' ? item : item.message ?? '';
|
||||
return (
|
||||
<div
|
||||
className={css`
|
||||
padding: 5px 0;
|
||||
`}
|
||||
>
|
||||
{typeof item === 'string' && textUtil.hasAnsiCodes(item) ? <LogMessageAnsi value={item} /> : item}
|
||||
{textUtil.hasAnsiCodes(message) ? <LogMessageAnsi value={message} /> : message}
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { fireEvent } from '@testing-library/dom';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { fireEvent, render, screen } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
|
@ -1,6 +1,4 @@
|
||||
import { fireEvent } from '@testing-library/dom';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { act, renderHook } from '@testing-library/react-hooks';
|
||||
import { act, fireEvent, render, renderHook, screen } from '@testing-library/react';
|
||||
import React, { createRef, KeyboardEvent, RefObject } from 'react';
|
||||
|
||||
import { useMenuFocus } from './hooks';
|
||||
|
@ -40,6 +40,7 @@ export function Segment<T>({
|
||||
|
||||
if (!expanded) {
|
||||
const label = isObject(value) ? value.label : value;
|
||||
const labelAsString = label != null ? String(label) : undefined;
|
||||
|
||||
return (
|
||||
<Label
|
||||
@ -56,7 +57,7 @@ export function Segment<T>({
|
||||
className
|
||||
)}
|
||||
>
|
||||
{label || placeholder}
|
||||
{labelAsString || placeholder}
|
||||
</InlineLabel>
|
||||
)
|
||||
}
|
||||
|
@ -53,6 +53,7 @@ export function SegmentAsync<T>({
|
||||
|
||||
if (!expanded) {
|
||||
const label = isObject(value) ? value.label : value;
|
||||
const labelAsString = label != null ? String(label) : undefined;
|
||||
|
||||
return (
|
||||
<Label
|
||||
@ -70,7 +71,7 @@ export function SegmentAsync<T>({
|
||||
className
|
||||
)}
|
||||
>
|
||||
{label || placeholder}
|
||||
{labelAsString || placeholder}
|
||||
</InlineLabel>
|
||||
)
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ const HandleTooltip = (props: {
|
||||
children: React.ReactElement;
|
||||
visible: boolean;
|
||||
placement: 'top' | 'right';
|
||||
tipFormatter?: (value: number) => React.ReactNode;
|
||||
tipFormatter?: () => React.ReactNode;
|
||||
}) => {
|
||||
const { value, children, visible, placement, tipFormatter, ...restProps } = props;
|
||||
|
||||
@ -71,6 +71,7 @@ const tooltipStyles = (theme: GrafanaTheme2) => {
|
||||
fontSize: theme.typography.bodySmall.fontSize,
|
||||
opacity: 0.9,
|
||||
padding: 3,
|
||||
zIndex: theme.zIndex.tooltip,
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
@ -51,7 +51,7 @@ export const RangeSlider = ({
|
||||
<HandleTooltip
|
||||
value={handleProps.value}
|
||||
visible={tooltipAlwaysVisible || handleProps.dragging}
|
||||
tipFormatter={formatTooltipResult}
|
||||
tipFormatter={formatTooltipResult ? () => formatTooltipResult(handleProps.value) : undefined}
|
||||
placement={isHorizontal ? 'top' : 'right'}
|
||||
>
|
||||
{node}
|
||||
|
@ -85,6 +85,8 @@ export function getColumns(
|
||||
// Make an expander cell
|
||||
Header: () => null, // No header
|
||||
id: 'expander', // It needs an ID
|
||||
// @ts-expect-error
|
||||
// TODO fix type error here
|
||||
Cell: RowExpander,
|
||||
width: EXPANDER_WIDTH,
|
||||
minWidth: EXPANDER_WIDTH,
|
||||
@ -124,6 +126,8 @@ export function getColumns(
|
||||
|
||||
const Cell = getCellComponent(fieldTableOptions.cellOptions?.type, field);
|
||||
columns.push({
|
||||
// @ts-expect-error
|
||||
// TODO fix type error here
|
||||
Cell,
|
||||
id: fieldIndex.toString(),
|
||||
field: field,
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { css } from '@emotion/css';
|
||||
import { render } from '@testing-library/react';
|
||||
import { renderHook } from '@testing-library/react-hooks';
|
||||
import { render, renderHook } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
|
||||
import { mockThemeContext, useStyles2 } from './ThemeContext';
|
||||
|
@ -25,14 +25,14 @@ export function getChildId(children: ReactElement): string | undefined {
|
||||
* @param props props to be passed to the function if item provided as such
|
||||
*/
|
||||
export function renderOrCallToRender<TProps = {}>(
|
||||
itemToRender: ((props?: TProps) => React.ReactNode) | React.ReactNode,
|
||||
itemToRender: ((props: TProps) => React.ReactNode) | React.ReactNode,
|
||||
props?: TProps
|
||||
): React.ReactNode {
|
||||
if (React.isValidElement(itemToRender) || typeof itemToRender === 'string' || typeof itemToRender === 'number') {
|
||||
return itemToRender;
|
||||
}
|
||||
|
||||
if (typeof itemToRender === 'function') {
|
||||
if (typeof itemToRender === 'function' && props) {
|
||||
return itemToRender(props);
|
||||
}
|
||||
|
||||
|
@ -18,17 +18,17 @@
|
||||
"@grafana/toolkit": "10.0.0-pre",
|
||||
"@types/jest": "26.0.15",
|
||||
"@types/lodash": "4.14.149",
|
||||
"@types/react": "17.0.30",
|
||||
"@types/react": "18.0.28",
|
||||
"lodash": "4.17.21"
|
||||
},
|
||||
"dependencies": {
|
||||
"@grafana/data": "10.0.0-pre",
|
||||
"@grafana/ui": "10.0.0-pre",
|
||||
"jquery": "3.5.1",
|
||||
"react": "17.0.1",
|
||||
"react-dom": "17.0.1",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react-hook-form": "7.5.3",
|
||||
"react-router-dom": "^5.2.0",
|
||||
"react-router-dom": "5.3.3",
|
||||
"tslib": "2.4.0"
|
||||
}
|
||||
}
|
||||
|
@ -94,42 +94,40 @@ export class AppWrapper extends React.Component<AppWrapperProps, AppWrapperState
|
||||
};
|
||||
|
||||
return (
|
||||
<React.StrictMode>
|
||||
<Provider store={store}>
|
||||
<ErrorBoundaryAlert style="page">
|
||||
<GrafanaContext.Provider value={app.context}>
|
||||
<ThemeProvider value={config.theme2}>
|
||||
<KBarProvider
|
||||
actions={[]}
|
||||
options={{ enableHistory: true, callbacks: { onSelectAction: commandPaletteActionSelected } }}
|
||||
>
|
||||
<ModalsProvider>
|
||||
<GlobalStyles />
|
||||
<div className="grafana-app">
|
||||
<Router history={locationService.getHistory()}>
|
||||
<AppChrome>
|
||||
{pageBanners.map((Banner, index) => (
|
||||
<Banner key={index.toString()} />
|
||||
))}
|
||||
<AngularRoot />
|
||||
<AppNotificationList />
|
||||
{ready && this.renderRoutes()}
|
||||
{bodyRenderHooks.map((Hook, index) => (
|
||||
<Hook key={index.toString()} />
|
||||
))}
|
||||
</AppChrome>
|
||||
</Router>
|
||||
</div>
|
||||
<LiveConnectionWarning />
|
||||
<ModalRoot />
|
||||
<PortalContainer />
|
||||
</ModalsProvider>
|
||||
</KBarProvider>
|
||||
</ThemeProvider>
|
||||
</GrafanaContext.Provider>
|
||||
</ErrorBoundaryAlert>
|
||||
</Provider>
|
||||
</React.StrictMode>
|
||||
<Provider store={store}>
|
||||
<ErrorBoundaryAlert style="page">
|
||||
<GrafanaContext.Provider value={app.context}>
|
||||
<ThemeProvider value={config.theme2}>
|
||||
<KBarProvider
|
||||
actions={[]}
|
||||
options={{ enableHistory: true, callbacks: { onSelectAction: commandPaletteActionSelected } }}
|
||||
>
|
||||
<ModalsProvider>
|
||||
<GlobalStyles />
|
||||
<div className="grafana-app">
|
||||
<Router history={locationService.getHistory()}>
|
||||
<AppChrome>
|
||||
{pageBanners.map((Banner, index) => (
|
||||
<Banner key={index.toString()} />
|
||||
))}
|
||||
<AngularRoot />
|
||||
<AppNotificationList />
|
||||
{ready && this.renderRoutes()}
|
||||
{bodyRenderHooks.map((Hook, index) => (
|
||||
<Hook key={index.toString()} />
|
||||
))}
|
||||
</AppChrome>
|
||||
</Router>
|
||||
</div>
|
||||
<LiveConnectionWarning />
|
||||
<ModalRoot />
|
||||
<PortalContainer />
|
||||
</ModalsProvider>
|
||||
</KBarProvider>
|
||||
</ThemeProvider>
|
||||
</GrafanaContext.Provider>
|
||||
</ErrorBoundaryAlert>
|
||||
</Provider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -12,14 +12,17 @@
|
||||
import angular, { auto } from 'angular';
|
||||
import { kebabCase } from 'lodash';
|
||||
import React, { ComponentType } from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { createRoot, Root } from 'react-dom/client';
|
||||
|
||||
// get a react component from name (components can be an angular injectable e.g. value, factory or
|
||||
// available on window
|
||||
function getReactComponent(name: string | Function, $injector: auto.IInjectorService): ComponentType {
|
||||
function getReactComponent(
|
||||
name: string | Function,
|
||||
$injector: auto.IInjectorService
|
||||
): ComponentType<React.PropsWithChildren<{}>> {
|
||||
// if name is a function assume it is component and return it
|
||||
if (angular.isFunction(name)) {
|
||||
return name as unknown as ComponentType;
|
||||
return name as unknown as ComponentType<React.PropsWithChildren<{}>>;
|
||||
}
|
||||
|
||||
// a React component name must be specified
|
||||
@ -46,7 +49,7 @@ function getReactComponent(name: string | Function, $injector: auto.IInjectorSer
|
||||
throw Error('Cannot find react component ' + name);
|
||||
}
|
||||
|
||||
return reactComponent as unknown as ComponentType;
|
||||
return reactComponent as unknown as ComponentType<React.PropsWithChildren<{}>>;
|
||||
}
|
||||
|
||||
// wraps a function with scope.$apply, if already applied just return
|
||||
@ -140,9 +143,9 @@ function watchProps(watchDepth: string, scope: any, watchExpressions: any[], lis
|
||||
}
|
||||
|
||||
// render React component, with scope[attrs.props] being passed in as the component props
|
||||
function renderComponent(component: any, props: object, scope: any, elem: Element[]) {
|
||||
function renderComponent(component: any, props: object, scope: any, root: Root) {
|
||||
scope.$evalAsync(() => {
|
||||
ReactDOM.render(React.createElement(component, props), elem[0]);
|
||||
root.render(React.createElement(component, props));
|
||||
});
|
||||
}
|
||||
|
||||
@ -207,11 +210,12 @@ const reactComponent = ($injector: any): any => {
|
||||
link: function (scope: any, elem: Element[], attrs: any) {
|
||||
const reactComponent = getReactComponent(attrs.name, $injector);
|
||||
|
||||
const root = createRoot(elem[0]);
|
||||
const renderMyComponent = () => {
|
||||
const scopeProps = scope.$eval(attrs.props);
|
||||
const props = applyFunctions(scopeProps, scope);
|
||||
|
||||
renderComponent(reactComponent, props, scope, elem);
|
||||
renderComponent(reactComponent, props, scope, root);
|
||||
};
|
||||
|
||||
// If there are props, re-render when they change
|
||||
@ -220,10 +224,10 @@ const reactComponent = ($injector: any): any => {
|
||||
// cleanup when scope is destroyed
|
||||
scope.$on('$destroy', () => {
|
||||
if (!attrs.onScopeDestroy) {
|
||||
ReactDOM.unmountComponentAtNode(elem[0]);
|
||||
root.unmount();
|
||||
} else {
|
||||
scope.$eval(attrs.onScopeDestroy, {
|
||||
unmountComponent: ReactDOM.unmountComponentAtNode.bind(this, elem[0]),
|
||||
unmountComponent: root.unmount.bind(this),
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -264,6 +268,7 @@ const reactDirective = ($injector: auto.IInjectorService) => {
|
||||
replace: true,
|
||||
link: function (scope: any, elem: Element[], attrs: any) {
|
||||
const reactComponent = getReactComponent(reactComponentName, $injector);
|
||||
const root = createRoot(elem[0]);
|
||||
|
||||
// if props is not defined, fall back to use the React component's propTypes if present
|
||||
props = props || Object.keys(reactComponent.propTypes || {});
|
||||
@ -281,7 +286,7 @@ const reactDirective = ($injector: auto.IInjectorService) => {
|
||||
|
||||
scopeProps = applyFunctions(scopeProps, scope, config);
|
||||
scopeProps = angular.extend({}, scopeProps, injectableProps);
|
||||
renderComponent(reactComponent, scopeProps, scope, elem);
|
||||
renderComponent(reactComponent, scopeProps, scope, root);
|
||||
};
|
||||
|
||||
// watch each property name and trigger an update whenever something changes,
|
||||
@ -298,10 +303,10 @@ const reactDirective = ($injector: auto.IInjectorService) => {
|
||||
// cleanup when scope is destroyed
|
||||
scope.$on('$destroy', () => {
|
||||
if (!attrs.onScopeDestroy) {
|
||||
ReactDOM.unmountComponentAtNode(elem[0]);
|
||||
root.unmount();
|
||||
} else {
|
||||
scope.$eval(attrs.onScopeDestroy, {
|
||||
unmountComponent: ReactDOM.unmountComponentAtNode.bind(this, elem[0]),
|
||||
unmountComponent: root.unmount.bind(this),
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -11,7 +11,7 @@ import 'app/features/all';
|
||||
|
||||
import _ from 'lodash'; // eslint-disable-line lodash/import-scope
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
|
||||
import {
|
||||
locationUtil,
|
||||
@ -209,11 +209,11 @@ export class GrafanaApp {
|
||||
config,
|
||||
};
|
||||
|
||||
ReactDOM.render(
|
||||
const root = createRoot(document.getElementById('reactRoot')!);
|
||||
root.render(
|
||||
React.createElement(AppWrapper, {
|
||||
app: this,
|
||||
}),
|
||||
document.getElementById('reactRoot')
|
||||
})
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('Failed to start Grafana', error);
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
|
||||
import { textUtil } from '@grafana/data';
|
||||
import { config, CopyPanelEvent } from '@grafana/runtime';
|
||||
@ -19,6 +19,7 @@ import { provideTheme } from '../utils/ConfigProvider';
|
||||
export class ModalManager {
|
||||
reactModalRoot = document.body;
|
||||
reactModalNode = document.createElement('div');
|
||||
root = createRoot(this.reactModalNode);
|
||||
|
||||
init() {
|
||||
appEvents.subscribe(ShowConfirmModalEvent, (e) => this.showConfirmModal(e.payload));
|
||||
@ -39,11 +40,11 @@ export class ModalManager {
|
||||
|
||||
const elem = React.createElement(provideTheme(AngularModalProxy, config.theme2), modalProps);
|
||||
this.reactModalRoot.appendChild(this.reactModalNode);
|
||||
ReactDOM.render(elem, this.reactModalNode);
|
||||
this.root.render(elem);
|
||||
}
|
||||
|
||||
onReactModalDismiss = () => {
|
||||
ReactDOM.unmountComponentAtNode(this.reactModalNode);
|
||||
this.root.render(null);
|
||||
this.reactModalRoot.removeChild(this.reactModalNode);
|
||||
};
|
||||
|
||||
@ -96,6 +97,6 @@ export class ModalManager {
|
||||
|
||||
const elem = React.createElement(provideTheme(AngularModalProxy, config.theme2), modalProps);
|
||||
this.reactModalRoot.appendChild(this.reactModalNode);
|
||||
ReactDOM.render(elem, this.reactModalNode);
|
||||
this.root.render(elem);
|
||||
}
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ const NotificationsListPage: FC = () => {
|
||||
return (
|
||||
<Page navModel={navModel}>
|
||||
<Page.Contents>
|
||||
{state.error && <p>{state.error}</p>}
|
||||
{state.error && <p>{state.error.message}</p>}
|
||||
{!!notifications.length && (
|
||||
<>
|
||||
<div className="page-action-bar">
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { render } from '@testing-library/react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
|
||||
import { PanelModel } from '../dashboard/state';
|
||||
@ -27,13 +27,15 @@ const props: React.ComponentProps<typeof TestRuleResult> = {
|
||||
};
|
||||
|
||||
describe('TestRuleResult', () => {
|
||||
it('should render without error', () => {
|
||||
expect(() => render(<TestRuleResult {...props} />)).not.toThrow();
|
||||
it('should render without error', async () => {
|
||||
render(<TestRuleResult {...props} />);
|
||||
await screen.findByRole('button', { name: 'Copy to Clipboard' });
|
||||
});
|
||||
|
||||
it('should call testRule when mounting', () => {
|
||||
it('should call testRule when mounting', async () => {
|
||||
jest.spyOn(backendSrv, 'post');
|
||||
render(<TestRuleResult {...props} />);
|
||||
await screen.findByRole('button', { name: 'Copy to Clipboard' });
|
||||
|
||||
expect(backendSrv.post).toHaveBeenCalledWith(
|
||||
'/api/alerts/test',
|
||||
|
@ -189,7 +189,7 @@ describe('Receivers', () => {
|
||||
mocks.api.fetchConfig.mockImplementation((name) =>
|
||||
Promise.resolve(name === GRAFANA_RULES_SOURCE_NAME ? someGrafanaAlertManagerConfig : someCloudAlertManagerConfig)
|
||||
);
|
||||
await renderReceivers();
|
||||
renderReceivers();
|
||||
|
||||
// check that by default grafana templates & receivers are fetched rendered in appropriate tables
|
||||
await ui.receiversTable.find();
|
||||
@ -234,7 +234,7 @@ describe('Receivers', () => {
|
||||
|
||||
mocks.api.fetchConfig.mockResolvedValue(someGrafanaAlertManagerConfig);
|
||||
|
||||
await renderReceivers();
|
||||
renderReceivers();
|
||||
|
||||
// go to new contact point page
|
||||
await userEvent.click(await ui.newContactPointButton.find());
|
||||
@ -292,7 +292,7 @@ describe('Receivers', () => {
|
||||
|
||||
mocks.api.fetchConfig.mockResolvedValue(someGrafanaAlertManagerConfig);
|
||||
mocks.api.updateConfig.mockResolvedValue();
|
||||
await renderReceivers();
|
||||
renderReceivers();
|
||||
|
||||
// go to new contact point page
|
||||
await userEvent.click(await ui.newContactPointButton.find());
|
||||
@ -351,18 +351,19 @@ describe('Receivers', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('Hides create contact point button for users without permission', () => {
|
||||
it('Hides create contact point button for users without permission', async () => {
|
||||
mockAlertmanagerChoiceResponse(server, alertmanagerChoiceMockedResponse);
|
||||
|
||||
mocks.api.fetchConfig.mockResolvedValue(someGrafanaAlertManagerConfig);
|
||||
mocks.api.updateConfig.mockResolvedValue();
|
||||
mocks.contextSrv.hasAccess.mockImplementation((action) =>
|
||||
mocks.contextSrv.hasPermission.mockImplementation((action) =>
|
||||
[AccessControlAction.AlertingNotificationsRead, AccessControlAction.AlertingNotificationsExternalRead].some(
|
||||
(a) => a === action
|
||||
)
|
||||
);
|
||||
mocks.hooks.useGetContactPointsState.mockReturnValue(emptyContactPointsState);
|
||||
renderReceivers();
|
||||
await ui.receiversTable.find();
|
||||
|
||||
expect(ui.newContactPointButton.query()).not.toBeInTheDocument();
|
||||
});
|
||||
@ -372,7 +373,7 @@ describe('Receivers', () => {
|
||||
|
||||
mocks.api.fetchConfig.mockResolvedValue(someCloudAlertManagerConfig);
|
||||
mocks.api.updateConfig.mockResolvedValue();
|
||||
await renderReceivers('CloudManager');
|
||||
renderReceivers('CloudManager');
|
||||
|
||||
// click edit button for the receiver
|
||||
await ui.receiversTable.find();
|
||||
@ -404,7 +405,7 @@ describe('Receivers', () => {
|
||||
// delete a field
|
||||
await userEvent.click(byText(/Fields \(2\)/i).get(slackContainer));
|
||||
await userEvent.click(byTestId('items.1.settings.fields.0.delete-button').get());
|
||||
await byText(/Fields \(1\)/i).get(slackContainer);
|
||||
byText(/Fields \(1\)/i).get(slackContainer);
|
||||
|
||||
// add another channel
|
||||
await userEvent.click(ui.newContactPointIntegrationButton.get());
|
||||
@ -470,7 +471,7 @@ describe('Receivers', () => {
|
||||
...someCloudAlertManagerStatus,
|
||||
config: someCloudAlertManagerConfig.alertmanager_config,
|
||||
});
|
||||
await renderReceivers(dataSources.promAlertManager.name);
|
||||
renderReceivers(dataSources.promAlertManager.name);
|
||||
|
||||
await ui.receiversTable.find();
|
||||
// there's no templates table for vanilla prom, API does not return templates
|
||||
@ -510,7 +511,7 @@ describe('Receivers', () => {
|
||||
alertmanager_config: {},
|
||||
});
|
||||
mocks.api.fetchStatus.mockResolvedValue(someCloudAlertManagerStatus);
|
||||
await renderReceivers('CloudManager');
|
||||
renderReceivers('CloudManager');
|
||||
|
||||
// check that receiver from the default config is represented
|
||||
await ui.receiversTable.find();
|
||||
@ -530,7 +531,7 @@ describe('Receivers', () => {
|
||||
mocks.api.discoverAlertmanagerFeatures.mockResolvedValue({ lazyConfigInit: true });
|
||||
mocks.api.fetchConfig.mockRejectedValue({ message: 'alertmanager storage object not found' });
|
||||
|
||||
await renderReceivers('CloudManager');
|
||||
renderReceivers('CloudManager');
|
||||
|
||||
const templatesTable = await ui.templatesTable.find();
|
||||
const receiversTable = await ui.receiversTable.find();
|
||||
@ -588,7 +589,7 @@ describe('Receivers', () => {
|
||||
};
|
||||
|
||||
mocks.hooks.useGetContactPointsState.mockReturnValue(receiversMock);
|
||||
await renderReceivers();
|
||||
renderReceivers();
|
||||
|
||||
//
|
||||
await ui.receiversTable.find();
|
||||
@ -660,7 +661,7 @@ describe('Receivers', () => {
|
||||
};
|
||||
|
||||
mocks.hooks.useGetContactPointsState.mockReturnValue(receiversMock);
|
||||
await renderReceivers();
|
||||
renderReceivers();
|
||||
|
||||
//
|
||||
await ui.receiversTable.find();
|
||||
@ -696,7 +697,7 @@ describe('Receivers', () => {
|
||||
mocks.api.updateConfig.mockResolvedValue();
|
||||
|
||||
mocks.hooks.useGetContactPointsState.mockReturnValue(emptyContactPointsState);
|
||||
await renderReceivers();
|
||||
renderReceivers();
|
||||
|
||||
await ui.receiversTable.find();
|
||||
//should not render notification error
|
||||
|
@ -218,9 +218,11 @@ const useAlertGroupsModal = (): [
|
||||
setMatchers([]);
|
||||
}, []);
|
||||
|
||||
const handleShow = useCallback((alertGroups, matchers) => {
|
||||
const handleShow = useCallback((alertGroups: AlertmanagerGroup[], matchers?: ObjectMatcher[]) => {
|
||||
setAlertGroups(alertGroups);
|
||||
setMatchers(matchers);
|
||||
if (matchers) {
|
||||
setMatchers(matchers);
|
||||
}
|
||||
setShowModal(true);
|
||||
}, []);
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { renderHook } from '@testing-library/react-hooks';
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import { createMemoryHistory } from 'history';
|
||||
import React from 'react';
|
||||
import { MemoryRouter, Router } from 'react-router-dom';
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { renderHook } from '@testing-library/react-hooks';
|
||||
import { renderHook, waitFor } from '@testing-library/react';
|
||||
import { setupServer } from 'msw/node';
|
||||
import React from 'react';
|
||||
import { Provider } from 'react-redux';
|
||||
@ -48,15 +48,15 @@ describe('useExternalDataSourceAlertmanagers', () => {
|
||||
const wrapper = ({ children }: React.PropsWithChildren<{}>) => <Provider store={store}>{children}</Provider>;
|
||||
|
||||
// Act
|
||||
const { result, waitForNextUpdate } = renderHook(() => useExternalDataSourceAlertmanagers(), { wrapper });
|
||||
await waitForNextUpdate();
|
||||
const { result } = renderHook(() => useExternalDataSourceAlertmanagers(), { wrapper });
|
||||
await waitFor(() => {
|
||||
// Assert
|
||||
const { current } = result;
|
||||
|
||||
// Assert
|
||||
const { current } = result;
|
||||
|
||||
expect(current).toHaveLength(1);
|
||||
expect(current[0].dataSource.uid).toBe('1');
|
||||
expect(current[0].url).toBe('http://grafana.com');
|
||||
expect(current).toHaveLength(1);
|
||||
expect(current[0].dataSource.uid).toBe('1');
|
||||
expect(current[0].url).toBe('http://grafana.com');
|
||||
});
|
||||
});
|
||||
|
||||
it('Should have active state if available in the activeAlertManagers', async () => {
|
||||
@ -81,15 +81,15 @@ describe('useExternalDataSourceAlertmanagers', () => {
|
||||
const wrapper = ({ children }: React.PropsWithChildren<{}>) => <Provider store={store}>{children}</Provider>;
|
||||
|
||||
// Act
|
||||
const { result, waitForValueToChange } = renderHook(() => useExternalDataSourceAlertmanagers(), { wrapper });
|
||||
await waitForValueToChange(() => result.current[0].status);
|
||||
const { result } = renderHook(() => useExternalDataSourceAlertmanagers(), { wrapper });
|
||||
await waitFor(() => {
|
||||
// Assert
|
||||
const { current } = result;
|
||||
|
||||
// Assert
|
||||
const { current } = result;
|
||||
|
||||
expect(current).toHaveLength(1);
|
||||
expect(current[0].status).toBe('active');
|
||||
expect(current[0].statusInconclusive).toBe(false);
|
||||
expect(current).toHaveLength(1);
|
||||
expect(current[0].status).toBe('active');
|
||||
expect(current[0].statusInconclusive).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
it('Should have dropped state if available in the droppedAlertManagers', async () => {
|
||||
@ -114,15 +114,16 @@ describe('useExternalDataSourceAlertmanagers', () => {
|
||||
const wrapper = ({ children }: React.PropsWithChildren<{}>) => <Provider store={store}>{children}</Provider>;
|
||||
|
||||
// Act
|
||||
const { result, waitForValueToChange } = renderHook(() => useExternalDataSourceAlertmanagers(), { wrapper });
|
||||
await waitForValueToChange(() => result.current[0].status);
|
||||
const { result } = renderHook(() => useExternalDataSourceAlertmanagers(), { wrapper });
|
||||
|
||||
// Assert
|
||||
const { current } = result;
|
||||
await waitFor(() => {
|
||||
// Assert
|
||||
const { current } = result;
|
||||
|
||||
expect(current).toHaveLength(1);
|
||||
expect(current[0].status).toBe('dropped');
|
||||
expect(current[0].statusInconclusive).toBe(false);
|
||||
expect(current).toHaveLength(1);
|
||||
expect(current[0].status).toBe('dropped');
|
||||
expect(current[0].statusInconclusive).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
it('Should have pending state if not available neither in dropped nor in active alertManagers', async () => {
|
||||
@ -147,15 +148,16 @@ describe('useExternalDataSourceAlertmanagers', () => {
|
||||
const wrapper = ({ children }: React.PropsWithChildren<{}>) => <Provider store={store}>{children}</Provider>;
|
||||
|
||||
// Act
|
||||
const { result, waitForNextUpdate } = renderHook(() => useExternalDataSourceAlertmanagers(), { wrapper });
|
||||
await waitForNextUpdate();
|
||||
const { result } = renderHook(() => useExternalDataSourceAlertmanagers(), { wrapper });
|
||||
|
||||
// Assert
|
||||
const { current } = result;
|
||||
await waitFor(() => {
|
||||
// Assert
|
||||
const { current } = result;
|
||||
|
||||
expect(current).toHaveLength(1);
|
||||
expect(current[0].status).toBe('pending');
|
||||
expect(current[0].statusInconclusive).toBe(false);
|
||||
expect(current).toHaveLength(1);
|
||||
expect(current[0].status).toBe('pending');
|
||||
expect(current[0].statusInconclusive).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
it('Should match Alertmanager url when datasource url does not have protocol specified', async () => {
|
||||
@ -180,15 +182,16 @@ describe('useExternalDataSourceAlertmanagers', () => {
|
||||
const wrapper = ({ children }: React.PropsWithChildren<{}>) => <Provider store={store}>{children}</Provider>;
|
||||
|
||||
// Act
|
||||
const { result, waitForValueToChange } = renderHook(() => useExternalDataSourceAlertmanagers(), { wrapper });
|
||||
await waitForValueToChange(() => result.current[0].status);
|
||||
const { result } = renderHook(() => useExternalDataSourceAlertmanagers(), { wrapper });
|
||||
|
||||
// Assert
|
||||
const { current } = result;
|
||||
await waitFor(() => {
|
||||
// Assert
|
||||
const { current } = result;
|
||||
|
||||
expect(current).toHaveLength(1);
|
||||
expect(current[0].status).toBe('active');
|
||||
expect(current[0].url).toBe('localhost:9093');
|
||||
expect(current).toHaveLength(1);
|
||||
expect(current[0].status).toBe('active');
|
||||
expect(current[0].url).toBe('localhost:9093');
|
||||
});
|
||||
});
|
||||
|
||||
it('Should have inconclusive state when there are many Alertmanagers of the same URL', async () => {
|
||||
@ -213,16 +216,16 @@ describe('useExternalDataSourceAlertmanagers', () => {
|
||||
const wrapper = ({ children }: React.PropsWithChildren<{}>) => <Provider store={store}>{children}</Provider>;
|
||||
|
||||
// Act
|
||||
const { result, waitForValueToChange } = renderHook(() => useExternalDataSourceAlertmanagers(), {
|
||||
const { result } = renderHook(() => useExternalDataSourceAlertmanagers(), {
|
||||
wrapper,
|
||||
});
|
||||
|
||||
await waitForValueToChange(() => result.current[0].status);
|
||||
|
||||
// Assert
|
||||
expect(result.current).toHaveLength(1);
|
||||
expect(result.current[0].status).toBe('active');
|
||||
expect(result.current[0].statusInconclusive).toBe(true);
|
||||
await waitFor(() => {
|
||||
// Assert
|
||||
expect(result.current).toHaveLength(1);
|
||||
expect(result.current[0].status).toBe('active');
|
||||
expect(result.current[0].statusInconclusive).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { renderHook } from '@testing-library/react-hooks';
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { Provider } from 'react-redux';
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { within } from '@testing-library/dom';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { render, screen, within } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import React from 'react';
|
||||
import { TestProvider } from 'test/helpers/TestProvider';
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { within } from '@testing-library/dom';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { render, screen, within } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import React from 'react';
|
||||
import { Provider } from 'react-redux';
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { within } from '@testing-library/dom';
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import { render, screen, waitFor, within } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import React from 'react';
|
||||
import { Provider } from 'react-redux';
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { screen, waitFor, waitForElementToBeRemoved } from '@testing-library/react';
|
||||
import { screen, waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { rest } from 'msw';
|
||||
import { setupServer } from 'msw/node';
|
||||
@ -311,6 +311,7 @@ describe('SharePublic - Already persisted', () => {
|
||||
|
||||
describe('SharePublic - Report interactions', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
server.use(getExistentPublicDashboardResponse());
|
||||
server.use(
|
||||
rest.put('/api/dashboards/uid/:dashboardUid/public-dashboards/:uid', (req, res, ctx) =>
|
||||
@ -327,29 +328,41 @@ describe('SharePublic - Report interactions', () => {
|
||||
|
||||
it('reports interaction when time range is clicked', async () => {
|
||||
await renderSharePublicDashboard();
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId(selectors.EnableTimeRangeSwitch)).toBeEnabled();
|
||||
});
|
||||
await userEvent.click(screen.getByTestId(selectors.EnableTimeRangeSwitch));
|
||||
await waitForElementToBeRemoved(screen.getByTestId('Spinner'));
|
||||
|
||||
expect(reportInteraction).toHaveBeenCalledWith('grafana_dashboards_public_time_selection_clicked', {
|
||||
action: pubdashResponse.timeSelectionEnabled ? 'disable' : 'enable',
|
||||
await waitFor(() => {
|
||||
expect(reportInteraction).toHaveBeenCalledWith('grafana_dashboards_public_time_selection_clicked', {
|
||||
action: pubdashResponse.timeSelectionEnabled ? 'disable' : 'enable',
|
||||
});
|
||||
});
|
||||
});
|
||||
it('reports interaction when show annotations is clicked', async () => {
|
||||
await renderSharePublicDashboard();
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId(selectors.EnableAnnotationsSwitch)).toBeEnabled();
|
||||
});
|
||||
await userEvent.click(screen.getByTestId(selectors.EnableAnnotationsSwitch));
|
||||
await waitForElementToBeRemoved(screen.getByTestId('Spinner'));
|
||||
|
||||
expect(reportInteraction).toHaveBeenCalledWith('grafana_dashboards_public_annotations_clicked', {
|
||||
action: pubdashResponse.annotationsEnabled ? 'disable' : 'enable',
|
||||
await waitFor(() => {
|
||||
expect(reportInteraction).toHaveBeenCalledWith('grafana_dashboards_public_annotations_clicked', {
|
||||
action: pubdashResponse.annotationsEnabled ? 'disable' : 'enable',
|
||||
});
|
||||
});
|
||||
});
|
||||
it('reports interaction when pause is clicked', async () => {
|
||||
await renderSharePublicDashboard();
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId(selectors.PauseSwitch)).toBeEnabled();
|
||||
});
|
||||
await userEvent.click(screen.getByTestId(selectors.PauseSwitch));
|
||||
await waitForElementToBeRemoved(screen.getByTestId('Spinner'));
|
||||
|
||||
expect(reportInteraction).toHaveBeenCalledWith('grafana_dashboards_public_enable_clicked', {
|
||||
action: pubdashResponse.isEnabled ? 'disable' : 'enable',
|
||||
await waitFor(() => {
|
||||
expect(reportInteraction).toHaveBeenCalledWith('grafana_dashboards_public_enable_clicked', {
|
||||
action: pubdashResponse.isEnabled ? 'disable' : 'enable',
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { Provider } from 'react-redux';
|
||||
import { match, Router } from 'react-router-dom';
|
||||
@ -66,16 +66,6 @@ jest.mock('react-virtualized-auto-sizer', () => {
|
||||
return ({ children }: AutoSizerProps) => children({ height: 1, width: 1 });
|
||||
});
|
||||
|
||||
interface ScenarioContext {
|
||||
dashboard?: DashboardModel | null;
|
||||
container?: HTMLElement;
|
||||
mount: (propOverrides?: Partial<Props>) => void;
|
||||
unmount: () => void;
|
||||
props: Props;
|
||||
rerender: (propOverrides?: Partial<Props>) => void;
|
||||
setup: (fn: () => void) => void;
|
||||
}
|
||||
|
||||
function getTestDashboard(overrides?: Partial<Dashboard>, metaOverrides?: Partial<DashboardMeta>): DashboardModel {
|
||||
const data = Object.assign(
|
||||
{
|
||||
@ -95,123 +85,98 @@ function getTestDashboard(overrides?: Partial<Dashboard>, metaOverrides?: Partia
|
||||
return createDashboardModelFixture(data, metaOverrides);
|
||||
}
|
||||
|
||||
function dashboardPageScenario(description: string, scenarioFn: (ctx: ScenarioContext) => void) {
|
||||
describe(description, () => {
|
||||
let setupFn: () => void;
|
||||
const mockInitDashboard = jest.fn();
|
||||
const mockCleanUpDashboardAndVariables = jest.fn();
|
||||
|
||||
const ctx: ScenarioContext = {
|
||||
setup: (fn) => {
|
||||
setupFn = fn;
|
||||
},
|
||||
mount: (propOverrides?: Partial<Props>) => {
|
||||
config.bootData.navTree = [
|
||||
{ text: 'Dashboards', id: 'dashboards' },
|
||||
{ text: 'Home', id: HOME_NAV_ID },
|
||||
];
|
||||
function setup(propOverrides?: Partial<Props>) {
|
||||
config.bootData.navTree = [
|
||||
{ text: 'Dashboards', id: 'dashboards' },
|
||||
{ text: 'Home', id: HOME_NAV_ID },
|
||||
];
|
||||
|
||||
const store = configureStore();
|
||||
const props: Props = {
|
||||
...getRouteComponentProps({
|
||||
match: { params: { slug: 'my-dash', uid: '11' } } as unknown as match,
|
||||
route: { routeName: DashboardRoutes.Normal } as RouteDescriptor,
|
||||
}),
|
||||
navIndex: {
|
||||
dashboards: { text: 'Dashboards', id: 'dashboards', parentItem: { text: 'Home', id: HOME_NAV_ID } },
|
||||
[HOME_NAV_ID]: { text: 'Home', id: HOME_NAV_ID },
|
||||
},
|
||||
initPhase: DashboardInitPhase.NotStarted,
|
||||
initError: null,
|
||||
initDashboard: jest.fn(),
|
||||
notifyApp: mockToolkitActionCreator(notifyApp),
|
||||
cleanUpDashboardAndVariables: jest.fn(),
|
||||
cancelVariables: jest.fn(),
|
||||
templateVarsChangedInUrl: jest.fn(),
|
||||
dashboard: null,
|
||||
theme: createTheme(),
|
||||
};
|
||||
const store = configureStore();
|
||||
const props: Props = {
|
||||
...getRouteComponentProps({
|
||||
match: { params: { slug: 'my-dash', uid: '11' } } as unknown as match,
|
||||
route: { routeName: DashboardRoutes.Normal } as RouteDescriptor,
|
||||
}),
|
||||
navIndex: {
|
||||
dashboards: { text: 'Dashboards', id: 'dashboards', parentItem: { text: 'Home', id: HOME_NAV_ID } },
|
||||
[HOME_NAV_ID]: { text: 'Home', id: HOME_NAV_ID },
|
||||
},
|
||||
initPhase: DashboardInitPhase.NotStarted,
|
||||
initError: null,
|
||||
initDashboard: mockInitDashboard,
|
||||
notifyApp: mockToolkitActionCreator(notifyApp),
|
||||
cleanUpDashboardAndVariables: mockCleanUpDashboardAndVariables,
|
||||
cancelVariables: jest.fn(),
|
||||
templateVarsChangedInUrl: jest.fn(),
|
||||
dashboard: null,
|
||||
theme: createTheme(),
|
||||
};
|
||||
|
||||
Object.assign(props, propOverrides);
|
||||
Object.assign(props, propOverrides);
|
||||
|
||||
ctx.props = props;
|
||||
ctx.dashboard = props.dashboard;
|
||||
const context = getGrafanaContextMock();
|
||||
|
||||
const context = getGrafanaContextMock();
|
||||
const { unmount, rerender } = render(
|
||||
<GrafanaContext.Provider value={context}>
|
||||
<Provider store={store}>
|
||||
<Router history={locationService.getHistory()}>
|
||||
<UnthemedDashboardPage {...props} />
|
||||
</Router>
|
||||
</Provider>
|
||||
</GrafanaContext.Provider>
|
||||
);
|
||||
|
||||
const { container, rerender, unmount } = render(
|
||||
<GrafanaContext.Provider value={context}>
|
||||
<Provider store={store}>
|
||||
<Router history={locationService.getHistory()}>
|
||||
<UnthemedDashboardPage {...props} />
|
||||
</Router>
|
||||
</Provider>
|
||||
</GrafanaContext.Provider>
|
||||
);
|
||||
const wrappedRerender = (newProps: Partial<Props>) => {
|
||||
Object.assign(props, newProps);
|
||||
return rerender(
|
||||
<GrafanaContext.Provider value={context}>
|
||||
<Provider store={store}>
|
||||
<Router history={locationService.getHistory()}>
|
||||
<UnthemedDashboardPage {...props} />
|
||||
</Router>
|
||||
</Provider>
|
||||
</GrafanaContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
ctx.container = container;
|
||||
|
||||
ctx.rerender = (newProps?: Partial<Props>) => {
|
||||
Object.assign(props, newProps);
|
||||
|
||||
rerender(
|
||||
<GrafanaContext.Provider value={context}>
|
||||
<Provider store={store}>
|
||||
<Router history={locationService.getHistory()}>
|
||||
<UnthemedDashboardPage {...props} />
|
||||
</Router>
|
||||
</Provider>
|
||||
</GrafanaContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
ctx.unmount = unmount;
|
||||
},
|
||||
props: {} as Props,
|
||||
rerender: () => {},
|
||||
unmount: () => {},
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
setupFn();
|
||||
});
|
||||
|
||||
scenarioFn(ctx);
|
||||
});
|
||||
return { rerender: wrappedRerender, unmount };
|
||||
}
|
||||
|
||||
describe('DashboardPage', () => {
|
||||
dashboardPageScenario('Given initial state', (ctx) => {
|
||||
ctx.setup(() => {
|
||||
ctx.mount();
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('Should call initDashboard on mount', () => {
|
||||
setup();
|
||||
expect(mockInitDashboard).toBeCalledWith({
|
||||
fixUrl: true,
|
||||
routeName: 'normal-dashboard',
|
||||
urlSlug: 'my-dash',
|
||||
urlUid: '11',
|
||||
keybindingSrv: expect.anything(),
|
||||
});
|
||||
});
|
||||
|
||||
describe('Given a simple dashboard', () => {
|
||||
it('Should render panels', async () => {
|
||||
setup({ dashboard: getTestDashboard() });
|
||||
expect(await screen.findByText('My panel title')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Should call initDashboard on mount', () => {
|
||||
expect(ctx.props.initDashboard).toBeCalledWith({
|
||||
fixUrl: true,
|
||||
routeName: 'normal-dashboard',
|
||||
urlSlug: 'my-dash',
|
||||
urlUid: '11',
|
||||
keybindingSrv: expect.anything(),
|
||||
it('Should update title', async () => {
|
||||
setup({ dashboard: getTestDashboard() });
|
||||
await waitFor(() => {
|
||||
expect(document.title).toBe('My dashboard - Dashboards - Grafana');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
dashboardPageScenario('Given a simple dashboard', (ctx) => {
|
||||
ctx.setup(() => {
|
||||
ctx.mount();
|
||||
ctx.rerender({ dashboard: getTestDashboard() });
|
||||
});
|
||||
|
||||
it('Should render panels', () => {
|
||||
expect(screen.getByText('My panel title')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Should update title', () => {
|
||||
expect(document.title).toBe('My dashboard - Dashboards - Grafana');
|
||||
});
|
||||
});
|
||||
|
||||
dashboardPageScenario('When going into view mode', (ctx) => {
|
||||
ctx.setup(() => {
|
||||
describe('When going into view mode', () => {
|
||||
beforeEach(() => {
|
||||
setDataSourceSrv({
|
||||
get: jest.fn().mockResolvedValue({ getRef: jest.fn(), query: jest.fn().mockResolvedValue([]) }),
|
||||
getInstanceSettings: jest.fn().mockReturnValue({ meta: {} }),
|
||||
@ -221,101 +186,110 @@ describe('DashboardPage', () => {
|
||||
setDashboardSrv({
|
||||
getCurrent: () => getTestDashboard(),
|
||||
} as DashboardSrv);
|
||||
ctx.mount({
|
||||
dashboard: getTestDashboard(),
|
||||
});
|
||||
|
||||
it('Should render panel in view mode', async () => {
|
||||
const dashboard = getTestDashboard();
|
||||
setup({
|
||||
dashboard,
|
||||
queryParams: { viewPanel: '1' },
|
||||
});
|
||||
await waitFor(() => {
|
||||
expect(dashboard.panelInView).toBeDefined();
|
||||
expect(dashboard.panels[0].isViewing).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('Should render panel in view mode', () => {
|
||||
expect(ctx.dashboard?.panelInView).toBeDefined();
|
||||
expect(ctx.dashboard?.panels[0].isViewing).toBe(true);
|
||||
});
|
||||
it('Should reset state when leaving', async () => {
|
||||
const dashboard = getTestDashboard();
|
||||
const { rerender } = setup({
|
||||
dashboard,
|
||||
queryParams: { viewPanel: '1' },
|
||||
});
|
||||
rerender({ queryParams: {}, dashboard });
|
||||
|
||||
it('Should reset state when leaving', () => {
|
||||
ctx.rerender({ queryParams: {} });
|
||||
|
||||
expect(ctx.dashboard?.panelInView).toBeUndefined();
|
||||
expect(ctx.dashboard?.panels[0].isViewing).toBe(false);
|
||||
await waitFor(() => {
|
||||
expect(dashboard.panelInView).toBeUndefined();
|
||||
expect(dashboard.panels[0].isViewing).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
dashboardPageScenario('When going into edit mode', (ctx) => {
|
||||
ctx.setup(() => {
|
||||
ctx.mount({
|
||||
dashboard: getTestDashboard(),
|
||||
describe('When going into edit mode', () => {
|
||||
it('Should render panel in edit mode', async () => {
|
||||
const dashboard = getTestDashboard();
|
||||
setup({
|
||||
dashboard,
|
||||
queryParams: { editPanel: '1' },
|
||||
});
|
||||
await waitFor(() => {
|
||||
expect(dashboard.panelInEdit).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
it('Should render panel in edit mode', () => {
|
||||
expect(ctx.dashboard?.panelInEdit).toBeDefined();
|
||||
it('Should render panel editor', async () => {
|
||||
const dashboard = getTestDashboard();
|
||||
setup({
|
||||
dashboard,
|
||||
queryParams: { editPanel: '1' },
|
||||
});
|
||||
expect(await screen.findByTitle('Apply changes and go back to dashboard')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Should render panel editor', () => {
|
||||
expect(screen.getByTitle('Apply changes and go back to dashboard')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Should reset state when leaving', () => {
|
||||
ctx.rerender({ queryParams: {} });
|
||||
expect(screen.queryByTitle('Apply changes and go back to dashboard')).not.toBeInTheDocument();
|
||||
it('Should reset state when leaving', async () => {
|
||||
const dashboard = getTestDashboard();
|
||||
const { rerender } = setup({
|
||||
dashboard,
|
||||
queryParams: { editPanel: '1' },
|
||||
});
|
||||
rerender({ queryParams: {} });
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByTitle('Apply changes and go back to dashboard')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
dashboardPageScenario('When dashboard unmounts', (ctx) => {
|
||||
ctx.setup(() => {
|
||||
ctx.mount();
|
||||
ctx.rerender({ dashboard: getTestDashboard() });
|
||||
ctx.unmount();
|
||||
});
|
||||
|
||||
it('Should call close action', () => {
|
||||
expect(ctx.props.cleanUpDashboardAndVariables).toHaveBeenCalledTimes(1);
|
||||
describe('When dashboard unmounts', () => {
|
||||
it('Should call close action', async () => {
|
||||
const { rerender, unmount } = setup();
|
||||
rerender({ dashboard: getTestDashboard() });
|
||||
unmount();
|
||||
await waitFor(() => {
|
||||
expect(mockCleanUpDashboardAndVariables).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
dashboardPageScenario('When dashboard changes', (ctx) => {
|
||||
ctx.setup(() => {
|
||||
ctx.mount();
|
||||
ctx.rerender({ dashboard: getTestDashboard() });
|
||||
ctx.rerender({
|
||||
match: {
|
||||
params: { uid: 'new-uid' },
|
||||
} as unknown as match,
|
||||
describe('When dashboard changes', () => {
|
||||
it('Should call clean up action and init', async () => {
|
||||
const { rerender } = setup();
|
||||
rerender({ dashboard: getTestDashboard() });
|
||||
rerender({
|
||||
match: { params: { uid: 'new-uid' } } as unknown as match,
|
||||
dashboard: getTestDashboard({ title: 'Another dashboard' }),
|
||||
});
|
||||
});
|
||||
|
||||
it('Should call clean up action and init', () => {
|
||||
expect(ctx.props.cleanUpDashboardAndVariables).toHaveBeenCalledTimes(1);
|
||||
expect(ctx.props.initDashboard).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
|
||||
dashboardPageScenario('No kiosk mode tv', (ctx) => {
|
||||
ctx.setup(() => {
|
||||
ctx.mount({ dashboard: getTestDashboard() });
|
||||
ctx.rerender({ dashboard: ctx.dashboard });
|
||||
});
|
||||
|
||||
it('should render dashboard page toolbar and submenu', () => {
|
||||
expect(screen.queryAllByTestId(selectors.pages.Dashboard.DashNav.navV2)).toHaveLength(1);
|
||||
expect(screen.queryAllByLabelText(selectors.pages.Dashboard.SubMenu.submenu)).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
dashboardPageScenario('When in full kiosk mode', (ctx) => {
|
||||
ctx.setup(() => {
|
||||
ctx.mount({
|
||||
queryParams: { kiosk: true },
|
||||
dashboard: getTestDashboard(),
|
||||
await waitFor(() => {
|
||||
expect(mockCleanUpDashboardAndVariables).toHaveBeenCalledTimes(1);
|
||||
expect(mockInitDashboard).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
ctx.rerender({ dashboard: ctx.dashboard });
|
||||
});
|
||||
});
|
||||
|
||||
it('should not render page toolbar and submenu', () => {
|
||||
expect(screen.queryAllByTestId(selectors.pages.Dashboard.DashNav.navV2)).toHaveLength(0);
|
||||
expect(screen.queryAllByLabelText(selectors.pages.Dashboard.SubMenu.submenu)).toHaveLength(0);
|
||||
describe('No kiosk mode tv', () => {
|
||||
it('should render dashboard page toolbar and submenu', async () => {
|
||||
setup({ dashboard: getTestDashboard() });
|
||||
expect(await screen.findAllByTestId(selectors.pages.Dashboard.DashNav.navV2)).toHaveLength(1);
|
||||
expect(screen.getAllByLabelText(selectors.pages.Dashboard.SubMenu.submenu)).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('When in full kiosk mode', () => {
|
||||
it('should not render page toolbar and submenu', async () => {
|
||||
setup({ dashboard: getTestDashboard(), queryParams: { kiosk: true } });
|
||||
await waitFor(() => {
|
||||
expect(screen.queryAllByTestId(selectors.pages.Dashboard.DashNav.navV2)).toHaveLength(0);
|
||||
expect(screen.queryAllByLabelText(selectors.pages.Dashboard.SubMenu.submenu)).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { render, RenderResult, screen } from '@testing-library/react';
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { Provider } from 'react-redux';
|
||||
import { Router } from 'react-router-dom';
|
||||
@ -48,29 +48,27 @@ jest.mock('app/types', () => ({
|
||||
useDispatch: () => jest.fn(),
|
||||
}));
|
||||
|
||||
interface ScenarioContext {
|
||||
mount: () => void;
|
||||
rerender: ({
|
||||
propOverrides,
|
||||
newState,
|
||||
}: {
|
||||
propOverrides?: Partial<Props>;
|
||||
newState?: Partial<appTypes.StoreState>;
|
||||
}) => void;
|
||||
setup: (fn: () => void) => void;
|
||||
}
|
||||
|
||||
const renderWithProvider = ({
|
||||
props,
|
||||
initialState,
|
||||
}: {
|
||||
props: Props;
|
||||
initialState?: Partial<appTypes.StoreState>;
|
||||
}): RenderResult => {
|
||||
const setup = (propOverrides?: Partial<Props>, initialState?: Partial<appTypes.StoreState>) => {
|
||||
const context = getGrafanaContextMock();
|
||||
const store = configureStore(initialState);
|
||||
|
||||
return render(
|
||||
const props: Props = {
|
||||
...getRouteComponentProps({
|
||||
match: { params: { accessToken: 'an-access-token' }, isExact: true, url: '', path: '' },
|
||||
route: {
|
||||
routeName: DashboardRoutes.Public,
|
||||
path: '/public-dashboards/:accessToken',
|
||||
component: SafeDynamicImport(
|
||||
() =>
|
||||
import(/* webpackChunkName: "PublicDashboardPage"*/ 'app/features/dashboard/containers/PublicDashboardPage')
|
||||
),
|
||||
},
|
||||
}),
|
||||
};
|
||||
|
||||
Object.assign(props, propOverrides);
|
||||
|
||||
const { unmount, rerender } = render(
|
||||
<GrafanaContext.Provider value={context}>
|
||||
<Provider store={store}>
|
||||
<Router history={locationService.getHistory()}>
|
||||
@ -79,6 +77,21 @@ const renderWithProvider = ({
|
||||
</Provider>
|
||||
</GrafanaContext.Provider>
|
||||
);
|
||||
|
||||
const wrappedRerender = (newProps: Partial<Props>) => {
|
||||
Object.assign(props, newProps);
|
||||
return rerender(
|
||||
<GrafanaContext.Provider value={context}>
|
||||
<Provider store={store}>
|
||||
<Router history={locationService.getHistory()}>
|
||||
<PublicDashboardPage {...props} />
|
||||
</Router>
|
||||
</Provider>
|
||||
</GrafanaContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
return { rerender: wrappedRerender, unmount };
|
||||
};
|
||||
|
||||
const selectors = e2eSelectors.components;
|
||||
@ -110,185 +123,114 @@ const getTestDashboard = (overrides?: Partial<Dashboard>, metaOverrides?: Partia
|
||||
return new DashboardModel(data, metaOverrides);
|
||||
};
|
||||
|
||||
function dashboardPageScenario(description: string, scenarioFn: (ctx: ScenarioContext) => void) {
|
||||
describe(description, () => {
|
||||
let setupFn: () => void;
|
||||
describe('PublicDashboardPage', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
const ctx: ScenarioContext = {
|
||||
setup: (fn) => {
|
||||
setupFn = fn;
|
||||
it('Should call initDashboard on mount', () => {
|
||||
setup();
|
||||
expect(initDashboard).toBeCalledWith({
|
||||
fixUrl: false,
|
||||
accessToken: 'an-access-token',
|
||||
routeName: 'public-dashboard',
|
||||
keybindingSrv: expect.anything(),
|
||||
});
|
||||
});
|
||||
|
||||
describe('Given a simple public dashboard', () => {
|
||||
const newState = {
|
||||
dashboard: {
|
||||
getModel: getTestDashboard,
|
||||
initError: null,
|
||||
initPhase: DashboardInitPhase.Completed,
|
||||
permissions: [],
|
||||
},
|
||||
mount: () => {
|
||||
const props: Props = {
|
||||
...getRouteComponentProps({
|
||||
match: { params: { accessToken: 'an-access-token' }, isExact: true, url: '', path: '' },
|
||||
route: {
|
||||
routeName: DashboardRoutes.Public,
|
||||
path: '/public-dashboards/:accessToken',
|
||||
component: SafeDynamicImport(
|
||||
() =>
|
||||
import(
|
||||
/* webpackChunkName: "PublicDashboardPage"*/ 'app/features/dashboard/containers/PublicDashboardPage'
|
||||
)
|
||||
),
|
||||
},
|
||||
}),
|
||||
};
|
||||
|
||||
const { rerender } = renderWithProvider({ props });
|
||||
|
||||
ctx.rerender = ({
|
||||
propsOverride,
|
||||
newState,
|
||||
}: {
|
||||
propsOverride?: Partial<Props>;
|
||||
newState?: Partial<appTypes.StoreState>;
|
||||
}) => {
|
||||
Object.assign(props, propsOverride);
|
||||
|
||||
const context = getGrafanaContextMock();
|
||||
const store = configureStore(newState);
|
||||
|
||||
rerender(
|
||||
<GrafanaContext.Provider value={context}>
|
||||
<Provider store={store}>
|
||||
<Router history={locationService.getHistory()}>
|
||||
<PublicDashboardPage {...props} />
|
||||
</Router>
|
||||
</Provider>
|
||||
</GrafanaContext.Provider>
|
||||
);
|
||||
};
|
||||
},
|
||||
rerender: () => {},
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
setupFn();
|
||||
it('Should render panels', async () => {
|
||||
setup(undefined, newState);
|
||||
expect(await screen.findByText('My panel title')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
scenarioFn(ctx);
|
||||
});
|
||||
}
|
||||
|
||||
describe('PublicDashboardPage', () => {
|
||||
dashboardPageScenario('Given initial state', (ctx) => {
|
||||
ctx.setup(() => {
|
||||
ctx.mount();
|
||||
it('Should update title', async () => {
|
||||
setup(undefined, newState);
|
||||
await waitFor(() => {
|
||||
expect(document.title).toBe('My dashboard - Grafana');
|
||||
});
|
||||
});
|
||||
|
||||
it('Should call initDashboard on mount', () => {
|
||||
expect(initDashboard).toBeCalledWith({
|
||||
fixUrl: false,
|
||||
accessToken: 'an-access-token',
|
||||
routeName: 'public-dashboard',
|
||||
keybindingSrv: expect.anything(),
|
||||
it('Should not render neither time range nor refresh picker buttons', async () => {
|
||||
setup(undefined, newState);
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByTestId(selectors.TimePicker.openButton)).not.toBeInTheDocument();
|
||||
expect(screen.queryByTestId(selectors.RefreshPicker.runButtonV2)).not.toBeInTheDocument();
|
||||
expect(screen.queryByTestId(selectors.RefreshPicker.intervalButtonV2)).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('Should not render paused or deleted screen', async () => {
|
||||
setup(undefined, newState);
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByTestId(publicDashboardSelector.NotAvailable.container)).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
dashboardPageScenario('Given a simple public dashboard', (ctx) => {
|
||||
ctx.setup(() => {
|
||||
ctx.mount();
|
||||
ctx.rerender({
|
||||
newState: {
|
||||
dashboard: {
|
||||
getModel: getTestDashboard,
|
||||
initError: null,
|
||||
initPhase: DashboardInitPhase.Completed,
|
||||
permissions: [],
|
||||
},
|
||||
describe('Given a public dashboard with time range enabled', () => {
|
||||
it('Should render time range and refresh picker buttons', async () => {
|
||||
setup(undefined, {
|
||||
dashboard: {
|
||||
getModel: () =>
|
||||
getTestDashboard({
|
||||
timepicker: { hidden: false, collapse: false, enable: true, refresh_intervals: [], time_options: [] },
|
||||
}),
|
||||
initError: null,
|
||||
initPhase: DashboardInitPhase.Completed,
|
||||
permissions: [],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('Should render panels', () => {
|
||||
expect(screen.getByText('My panel title')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Should update title', () => {
|
||||
expect(document.title).toBe('My dashboard - Grafana');
|
||||
});
|
||||
|
||||
it('Should not render neither time range nor refresh picker buttons', () => {
|
||||
expect(screen.queryByTestId(selectors.TimePicker.openButton)).not.toBeInTheDocument();
|
||||
expect(screen.queryByTestId(selectors.RefreshPicker.runButtonV2)).not.toBeInTheDocument();
|
||||
expect(screen.queryByTestId(selectors.RefreshPicker.intervalButtonV2)).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Should not render paused or deleted screen', () => {
|
||||
expect(screen.queryByTestId(publicDashboardSelector.NotAvailable.container)).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
dashboardPageScenario('Given a public dashboard with time range enabled', (ctx) => {
|
||||
ctx.setup(() => {
|
||||
ctx.mount();
|
||||
ctx.rerender({
|
||||
newState: {
|
||||
dashboard: {
|
||||
getModel: () =>
|
||||
getTestDashboard({
|
||||
timepicker: { hidden: false, collapse: false, enable: true, refresh_intervals: [], time_options: [] },
|
||||
}),
|
||||
initError: null,
|
||||
initPhase: DashboardInitPhase.Completed,
|
||||
permissions: [],
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('Should render time range and refresh picker buttons', () => {
|
||||
expect(screen.getByTestId(selectors.TimePicker.openButton)).toBeInTheDocument();
|
||||
expect(await screen.findByTestId(selectors.TimePicker.openButton)).toBeInTheDocument();
|
||||
expect(screen.getByTestId(selectors.RefreshPicker.runButtonV2)).toBeInTheDocument();
|
||||
expect(screen.getByTestId(selectors.RefreshPicker.intervalButtonV2)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
dashboardPageScenario('Given paused public dashboard', (ctx) => {
|
||||
ctx.setup(() => {
|
||||
ctx.mount();
|
||||
ctx.rerender({
|
||||
newState: {
|
||||
dashboard: {
|
||||
getModel: () => getTestDashboard(undefined, { publicDashboardEnabled: false, dashboardNotFound: false }),
|
||||
initError: null,
|
||||
initPhase: DashboardInitPhase.Completed,
|
||||
permissions: [],
|
||||
},
|
||||
describe('Given paused public dashboard', () => {
|
||||
it('Should render public dashboard paused screen', async () => {
|
||||
setup(undefined, {
|
||||
dashboard: {
|
||||
getModel: () => getTestDashboard(undefined, { publicDashboardEnabled: false, dashboardNotFound: false }),
|
||||
initError: null,
|
||||
initPhase: DashboardInitPhase.Completed,
|
||||
permissions: [],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('Should render public dashboard paused screen', () => {
|
||||
expect(screen.queryByTestId(publicDashboardSelector.page)).not.toBeInTheDocument();
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByTestId(publicDashboardSelector.page)).not.toBeInTheDocument();
|
||||
});
|
||||
expect(screen.getByTestId(publicDashboardSelector.NotAvailable.title)).toBeInTheDocument();
|
||||
expect(screen.getByTestId(publicDashboardSelector.NotAvailable.pausedDescription)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
dashboardPageScenario('Given deleted public dashboard', (ctx) => {
|
||||
ctx.setup(() => {
|
||||
ctx.mount();
|
||||
ctx.rerender({
|
||||
newState: {
|
||||
dashboard: {
|
||||
getModel: () => getTestDashboard(undefined, { dashboardNotFound: true }),
|
||||
initError: null,
|
||||
initPhase: DashboardInitPhase.Completed,
|
||||
permissions: [],
|
||||
},
|
||||
describe('Given deleted public dashboard', () => {
|
||||
it('Should render public dashboard deleted screen', async () => {
|
||||
setup(undefined, {
|
||||
dashboard: {
|
||||
getModel: () => getTestDashboard(undefined, { dashboardNotFound: true }),
|
||||
initError: null,
|
||||
initPhase: DashboardInitPhase.Completed,
|
||||
permissions: [],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('Should render public dashboard deleted screen', () => {
|
||||
expect(screen.queryByTestId(publicDashboardSelector.page)).not.toBeInTheDocument();
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByTestId(publicDashboardSelector.page)).not.toBeInTheDocument();
|
||||
expect(screen.queryByTestId(publicDashboardSelector.NotAvailable.pausedDescription)).not.toBeInTheDocument();
|
||||
});
|
||||
expect(screen.getByTestId(publicDashboardSelector.NotAvailable.title)).toBeInTheDocument();
|
||||
expect(screen.queryByTestId(publicDashboardSelector.NotAvailable.pausedDescription)).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -8,9 +8,10 @@ import { DashboardModel } from '../state';
|
||||
import { createDashboardModelFixture } from '../state/__fixtures__/dashboardFixtures';
|
||||
|
||||
import { DashboardGrid, Props } from './DashboardGrid';
|
||||
import { Props as LazyLoaderProps } from './LazyLoader';
|
||||
|
||||
jest.mock('app/features/dashboard/dashgrid/LazyLoader', () => {
|
||||
const LazyLoader = ({ children }: React.PropsWithChildren<{}>) => {
|
||||
const LazyLoader = ({ children }: LazyLoaderProps) => {
|
||||
return <>{children}</>;
|
||||
};
|
||||
return { LazyLoader };
|
||||
|
@ -71,7 +71,7 @@ export class DashboardPanelUnconnected extends PureComponent<Props> {
|
||||
}
|
||||
};
|
||||
|
||||
renderPanel = (isInView: boolean) => {
|
||||
renderPanel = ({ isInView }: { isInView: boolean }) => {
|
||||
const { dashboard, panel, isViewing, isEditing, width, height, plugin, timezone, hideMenu } = this.props;
|
||||
|
||||
if (!plugin) {
|
||||
@ -118,7 +118,7 @@ export class DashboardPanelUnconnected extends PureComponent<Props> {
|
||||
{this.renderPanel}
|
||||
</LazyLoader>
|
||||
) : (
|
||||
this.renderPanel(true)
|
||||
this.renderPanel({ isInView: true })
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -55,7 +55,9 @@ LazyLoader.addCallback = (id: string, c: (e: IntersectionObserverEntry) => void)
|
||||
LazyLoader.observer = new IntersectionObserver(
|
||||
(entries) => {
|
||||
for (const entry of entries) {
|
||||
LazyLoader.callbacks[entry.target.id](entry);
|
||||
if (LazyLoader.callbacks[entry.target.id]) {
|
||||
LazyLoader.callbacks[entry.target.id](entry);
|
||||
}
|
||||
}
|
||||
},
|
||||
{ rootMargin: '100px' }
|
||||
|
@ -26,7 +26,7 @@ export function DataSourceTestingStatus({ testingStatus }: Props) {
|
||||
<>
|
||||
{detailsMessage}
|
||||
{detailsVerboseMessage ? (
|
||||
<details style={{ whiteSpace: 'pre-wrap' }}>{detailsVerboseMessage}</details>
|
||||
<details style={{ whiteSpace: 'pre-wrap' }}>{String(detailsVerboseMessage)}</details>
|
||||
) : null}
|
||||
</>
|
||||
)}
|
||||
|
@ -110,9 +110,9 @@ class ExplorePaneContainerUnconnected extends React.PureComponent<Props> {
|
||||
rootDatasourceOverride = changeDatasourceUid;
|
||||
const datasource = await getDatasourceSrv().get(changeDatasourceUid);
|
||||
const datasourceInit = await getDatasourceSrv().get(initialDatasource);
|
||||
await this.props.importQueries(exploreId, queries, datasourceInit, datasource);
|
||||
const newQueries = await this.props.importQueries(exploreId, queries, datasourceInit, datasource);
|
||||
await this.props.stateSave({ replace: true });
|
||||
queries = this.props.initialQueries;
|
||||
queries = newQueries ?? this.props.initialQueries;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { renderHook, act } from '@testing-library/react-hooks';
|
||||
import { renderHook, act } from '@testing-library/react';
|
||||
|
||||
import { TraceSpan } from './components';
|
||||
import { useChildrenState } from './useChildrenState';
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { act, renderHook } from '@testing-library/react-hooks';
|
||||
import { act, renderHook } from '@testing-library/react';
|
||||
|
||||
import { DataFrame } from '@grafana/data';
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { renderHook, act } from '@testing-library/react-hooks';
|
||||
import { renderHook, act } from '@testing-library/react';
|
||||
|
||||
import { useHoverIndentGuide } from './useHoverIndentGuide';
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { act, renderHook } from '@testing-library/react-hooks';
|
||||
import { act, renderHook } from '@testing-library/react';
|
||||
|
||||
import { TraceSpan } from './components';
|
||||
import { useSearch } from './useSearch';
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { renderHook, act } from '@testing-library/react-hooks';
|
||||
import { renderHook, act } from '@testing-library/react';
|
||||
|
||||
import { useViewRange } from './useViewRange';
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { within } from '@testing-library/dom';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { render, screen, within } from '@testing-library/react';
|
||||
import { fromPairs } from 'lodash';
|
||||
import React from 'react';
|
||||
import { Provider } from 'react-redux';
|
||||
|
@ -339,7 +339,7 @@ export const importQueries = (
|
||||
sourceDataSource: DataSourceApi | undefined | null,
|
||||
targetDataSource: DataSourceApi,
|
||||
singleQueryChangeRef?: string // when changing one query DS to another in a mixed environment, we do not want to change all queries, just the one being changed
|
||||
): ThunkResult<Promise<void>> => {
|
||||
): ThunkResult<Promise<DataQuery[] | void>> => {
|
||||
return async (dispatch) => {
|
||||
if (!sourceDataSource) {
|
||||
// explore not initialized
|
||||
@ -396,6 +396,7 @@ export const importQueries = (
|
||||
}
|
||||
|
||||
dispatch(queriesImportedAction({ exploreId, queries: nextQueries }));
|
||||
return nextQueries;
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { within } from '@testing-library/dom';
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import { render, screen, waitFor, within } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import React from 'react';
|
||||
|
||||
|
@ -357,7 +357,11 @@ export const LogRowContextGroup = ({
|
||||
padding: 5px 0;
|
||||
`}
|
||||
>
|
||||
{typeof item === 'string' && textUtil.hasAnsiCodes(item) ? <LogMessageAnsi value={item} /> : item}
|
||||
{typeof item === 'string' && textUtil.hasAnsiCodes(item) ? (
|
||||
<LogMessageAnsi value={item} />
|
||||
) : (
|
||||
String(item)
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { within } from '@testing-library/dom';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { render, screen, within } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import React from 'react';
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { within } from '@testing-library/dom';
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import { render, screen, waitFor, within } from '@testing-library/react';
|
||||
import userEvent, { PointerEventsCheckLevel } from '@testing-library/user-event';
|
||||
import React from 'react';
|
||||
|
||||
|
@ -187,7 +187,7 @@ export const generateColumns = (
|
||||
},
|
||||
id: `column-location`,
|
||||
field: access.location ?? access.url,
|
||||
Header: () => t('search.results-table.location-header', 'Location'),
|
||||
Header: t('search.results-table.location-header', 'Location'),
|
||||
width,
|
||||
});
|
||||
}
|
||||
@ -274,7 +274,7 @@ function makeDataSourceColumn(
|
||||
return {
|
||||
id: `column-datasource`,
|
||||
field,
|
||||
Header: () => t('search.results-table.datasource-header', 'Data source'),
|
||||
Header: t('search.results-table.datasource-header', 'Data source'),
|
||||
Cell: (p) => {
|
||||
const dslist = field.values.get(p.row.index);
|
||||
if (!dslist?.length) {
|
||||
@ -322,7 +322,7 @@ function makeTypeColumn(
|
||||
return {
|
||||
id: `column-type`,
|
||||
field: kindField ?? typeField,
|
||||
Header: () => t('search.results-table.type-header', 'Type'),
|
||||
Header: t('search.results-table.type-header', 'Type'),
|
||||
Cell: (p) => {
|
||||
const i = p.row.index;
|
||||
const kind = kindField?.values.get(i) ?? 'dashboard';
|
||||
@ -393,7 +393,7 @@ function makeTagsColumn(
|
||||
},
|
||||
id: `column-tags`,
|
||||
field: field,
|
||||
Header: () => t('search.results-table.tags-header', 'Tags'),
|
||||
Header: t('search.results-table.tags-header', 'Tags'),
|
||||
width,
|
||||
};
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { renderHook } from '@testing-library/react-hooks';
|
||||
import { renderHook, waitFor } from '@testing-library/react';
|
||||
|
||||
import createMockDatasource from '../../__mocks__/datasource';
|
||||
import Datasource from '../../datasource';
|
||||
@ -13,10 +13,6 @@ import {
|
||||
MetricsMetadataHook,
|
||||
} from './dataHooks';
|
||||
|
||||
const WAIT_OPTIONS = {
|
||||
timeout: 1000,
|
||||
};
|
||||
|
||||
const opt = (text: string, value: string) => ({ text, value });
|
||||
|
||||
interface TestScenario {
|
||||
@ -180,10 +176,11 @@ describe('AzureMonitor: metrics dataHooks', () => {
|
||||
...bareQuery,
|
||||
azureMonitor: scenario.emptyQueryPartial,
|
||||
};
|
||||
const { result, waitForNextUpdate } = renderHook(() => scenario.hook(query, datasource, onChange, setError));
|
||||
await waitForNextUpdate(WAIT_OPTIONS);
|
||||
const { result } = renderHook(() => scenario.hook(query, datasource, onChange, setError));
|
||||
|
||||
expect(result.current).toEqual(scenario.expectedOptions);
|
||||
await waitFor(() => {
|
||||
expect(result.current).toEqual(scenario.expectedOptions);
|
||||
});
|
||||
});
|
||||
|
||||
it('adds custom properties as a valid option', async () => {
|
||||
@ -192,10 +189,11 @@ describe('AzureMonitor: metrics dataHooks', () => {
|
||||
azureMonitor: scenario.customProperties,
|
||||
...scenario.topLevelCustomProperties,
|
||||
};
|
||||
const { result, waitForNextUpdate } = renderHook(() => scenario.hook(query, datasource, onChange, setError));
|
||||
await waitForNextUpdate(WAIT_OPTIONS);
|
||||
const { result } = renderHook(() => scenario.hook(query, datasource, onChange, setError));
|
||||
|
||||
expect(result.current).toEqual(scenario.expectedCustomPropertyResults);
|
||||
await waitFor(() => {
|
||||
expect(result.current).toEqual(scenario.expectedCustomPropertyResults);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -239,18 +237,19 @@ describe('AzureMonitor: metrics dataHooks', () => {
|
||||
...bareQuery,
|
||||
azureMonitor: metricsMetadataConfig.emptyQueryPartial,
|
||||
};
|
||||
const { result, waitForNextUpdate } = renderHook(() => metricsMetadataConfig.hook(query, datasource, onChange));
|
||||
await waitForNextUpdate(WAIT_OPTIONS);
|
||||
const { result } = renderHook(() => metricsMetadataConfig.hook(query, datasource, onChange));
|
||||
|
||||
expect(result.current).toEqual(metricsMetadataConfig.expectedOptions);
|
||||
expect(onChange).toHaveBeenCalledWith({
|
||||
...query,
|
||||
azureMonitor: {
|
||||
...query.azureMonitor,
|
||||
aggregation: result.current.primaryAggType,
|
||||
timeGrain: 'auto',
|
||||
allowedTimeGrainsMs: [60_000, 300_000, 900_000, 1_800_000, 3_600_000, 21_600_000, 43_200_000, 86_400_000],
|
||||
},
|
||||
await waitFor(() => {
|
||||
expect(result.current).toEqual(metricsMetadataConfig.expectedOptions);
|
||||
expect(onChange).toHaveBeenCalledWith({
|
||||
...query,
|
||||
azureMonitor: {
|
||||
...query.azureMonitor,
|
||||
aggregation: result.current.primaryAggType,
|
||||
timeGrain: 'auto',
|
||||
allowedTimeGrainsMs: [60_000, 300_000, 900_000, 1_800_000, 3_600_000, 21_600_000, 43_200_000, 86_400_000],
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -281,21 +280,20 @@ describe('AzureMonitor: metrics dataHooks', () => {
|
||||
...bareQuery,
|
||||
azureMonitor: metricNamespacesConfig.emptyQueryPartial,
|
||||
};
|
||||
const { result, waitForNextUpdate } = renderHook(() =>
|
||||
metricNamespacesConfig.hook(query, datasource, onChange, jest.fn())
|
||||
);
|
||||
await waitForNextUpdate(WAIT_OPTIONS);
|
||||
const { result } = renderHook(() => metricNamespacesConfig.hook(query, datasource, onChange, jest.fn()));
|
||||
|
||||
expect(result.current).toEqual(metricNamespacesConfig.expectedOptions);
|
||||
expect(datasource.azureMonitorDatasource.getMetricNamespaces).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
resourceGroup: 'rg',
|
||||
resourceName: 'rn',
|
||||
metricNamespace: 'azure/vm',
|
||||
}),
|
||||
// Here, "global" should be false
|
||||
false
|
||||
);
|
||||
await waitFor(() => {
|
||||
expect(result.current).toEqual(metricNamespacesConfig.expectedOptions);
|
||||
expect(datasource.azureMonitorDatasource.getMetricNamespaces).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
resourceGroup: 'rg',
|
||||
resourceName: 'rn',
|
||||
metricNamespace: 'azure/vm',
|
||||
}),
|
||||
// Here, "global" should be false
|
||||
false
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -71,7 +71,7 @@ const QueryEditor = ({
|
||||
<>
|
||||
<Space v={2} />
|
||||
<Alert severity="error" title="An error occurred while requesting metadata from Azure Monitor">
|
||||
{errorMessage}
|
||||
{errorMessage instanceof Error ? errorMessage.message : errorMessage}
|
||||
</Alert>
|
||||
</>
|
||||
)}
|
||||
|
@ -89,20 +89,20 @@ describe('AzureMonitor ResourcePicker', () => {
|
||||
|
||||
it('should show a subscription as selected if there is one saved', async () => {
|
||||
render(<ResourcePicker {...defaultProps} resources={[singleSubscriptionSelectionURI]} />);
|
||||
await waitFor(async () => {
|
||||
const subscriptionCheckboxes = await screen.findAllByLabelText('Dev Subscription');
|
||||
expect(subscriptionCheckboxes.length).toBe(2);
|
||||
await waitFor(() => {
|
||||
expect(screen.getAllByLabelText('Dev Subscription')).toHaveLength(2);
|
||||
});
|
||||
const subscriptionCheckboxes = await screen.findAllByLabelText('Dev Subscription');
|
||||
expect(subscriptionCheckboxes.length).toBe(2);
|
||||
expect(subscriptionCheckboxes[0]).toBeChecked();
|
||||
expect(subscriptionCheckboxes[1]).toBeChecked();
|
||||
});
|
||||
|
||||
it('should show a resourceGroup as selected if there is one saved', async () => {
|
||||
render(<ResourcePicker {...defaultProps} resources={[singleResourceGroupSelectionURI]} />);
|
||||
await waitFor(() => {
|
||||
expect(screen.getAllByLabelText('A Great Resource Group')).toHaveLength(2);
|
||||
});
|
||||
const resourceGroupCheckboxes = await screen.findAllByLabelText('A Great Resource Group');
|
||||
expect(resourceGroupCheckboxes.length).toBe(2);
|
||||
expect(resourceGroupCheckboxes[0]).toBeChecked();
|
||||
expect(resourceGroupCheckboxes[1]).toBeChecked();
|
||||
});
|
||||
@ -112,8 +112,10 @@ describe('AzureMonitor ResourcePicker', () => {
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByText('Loading...')).not.toBeInTheDocument();
|
||||
});
|
||||
await waitFor(() => {
|
||||
expect(screen.getAllByLabelText('db-server')).toHaveLength(2);
|
||||
});
|
||||
const resourceCheckboxes = await screen.findAllByLabelText('db-server');
|
||||
expect(resourceCheckboxes.length).toBe(2);
|
||||
expect(resourceCheckboxes[0]).toBeChecked();
|
||||
expect(resourceCheckboxes[1]).toBeChecked();
|
||||
});
|
||||
@ -158,8 +160,10 @@ describe('AzureMonitor ResourcePicker', () => {
|
||||
it('should call onApply removing an element', async () => {
|
||||
const onApply = jest.fn();
|
||||
render(<ResourcePicker {...defaultProps} resources={['/subscriptions/def-123']} onApply={onApply} />);
|
||||
await waitFor(() => {
|
||||
expect(screen.getAllByLabelText('Primary Subscription')).toHaveLength(2);
|
||||
});
|
||||
const subscriptionCheckbox = await screen.findAllByLabelText('Primary Subscription');
|
||||
expect(subscriptionCheckbox).toHaveLength(2);
|
||||
expect(subscriptionCheckbox.at(0)).toBeChecked();
|
||||
await userEvent.click(subscriptionCheckbox.at(0)!);
|
||||
const applyButton = screen.getByRole('button', { name: 'Apply' });
|
||||
@ -173,8 +177,10 @@ describe('AzureMonitor ResourcePicker', () => {
|
||||
render(
|
||||
<ResourcePicker {...defaultProps} resources={['/subscriptions/def-456/resourceGroups/DEV-3']} onApply={onApply} />
|
||||
);
|
||||
await waitFor(() => {
|
||||
expect(screen.getAllByLabelText('A Great Resource Group')).toHaveLength(2);
|
||||
});
|
||||
const subscriptionCheckbox = await screen.findAllByLabelText('A Great Resource Group');
|
||||
expect(subscriptionCheckbox).toHaveLength(2);
|
||||
expect(subscriptionCheckbox.at(0)).toBeChecked();
|
||||
await userEvent.click(subscriptionCheckbox.at(0)!);
|
||||
const applyButton = screen.getByRole('button', { name: 'Apply' });
|
||||
@ -232,8 +238,10 @@ describe('AzureMonitor ResourcePicker', () => {
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByText('Loading...')).not.toBeInTheDocument();
|
||||
});
|
||||
await waitFor(() => {
|
||||
expect(screen.getAllByLabelText('web-server')).toHaveLength(2);
|
||||
});
|
||||
const checkbox = await screen.findAllByLabelText('web-server');
|
||||
expect(checkbox).toHaveLength(2);
|
||||
expect(checkbox.at(0)).toBeChecked();
|
||||
await userEvent.click(checkbox.at(0)!);
|
||||
const applyButton = screen.getByRole('button', { name: 'Apply' });
|
||||
|
@ -256,7 +256,7 @@ const VariableEditor = (props: Props) => {
|
||||
<>
|
||||
<Space v={2} />
|
||||
<Alert severity="error" title="An error occurred while requesting metadata from Azure Monitor">
|
||||
{errorMessage}
|
||||
{errorMessage instanceof Error ? errorMessage.message : errorMessage}
|
||||
</Alert>
|
||||
</>
|
||||
)}
|
||||
@ -365,7 +365,7 @@ const VariableEditor = (props: Props) => {
|
||||
<>
|
||||
<Space v={2} />
|
||||
<Alert severity="error" title="An error occurred while requesting metadata from Azure Monitor">
|
||||
{errorMessage}
|
||||
{errorMessage instanceof Error ? errorMessage.message : errorMessage}
|
||||
</Alert>
|
||||
</>
|
||||
)}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { renderHook } from '@testing-library/react-hooks';
|
||||
import { renderHook, waitFor } from '@testing-library/react';
|
||||
|
||||
import { useAsyncState } from './useAsyncState';
|
||||
|
||||
@ -36,10 +36,11 @@ describe('useAsyncState', () => {
|
||||
const apiCall = () => Promise.resolve(['a', 'b', 'c']);
|
||||
const setError = jest.fn();
|
||||
|
||||
const { result, waitForNextUpdate } = renderHook(() => useAsyncState(apiCall, setError, []));
|
||||
await waitForNextUpdate();
|
||||
const { result } = renderHook(() => useAsyncState(apiCall, setError, []));
|
||||
|
||||
expect(result.current).toEqual(['a', 'b', 'c']);
|
||||
await waitFor(() => {
|
||||
expect(result.current).toEqual(['a', 'b', 'c']);
|
||||
});
|
||||
});
|
||||
|
||||
it('should report errors through setError', async () => {
|
||||
@ -47,20 +48,22 @@ describe('useAsyncState', () => {
|
||||
const apiCall = () => Promise.reject(error);
|
||||
const setError = createWaitableMock();
|
||||
|
||||
const { result, waitForNextUpdate } = renderHook(() => useAsyncState(apiCall, setError, []));
|
||||
await Promise.race([waitForNextUpdate(), setError.waitToBeCalled()]);
|
||||
const { result } = renderHook(() => useAsyncState(apiCall, setError, []));
|
||||
|
||||
expect(result.current).toEqual([]);
|
||||
expect(setError).toHaveBeenCalledWith(MOCKED_RANDOM_VALUE, error);
|
||||
await waitFor(() => {
|
||||
expect(result.current).toEqual([]);
|
||||
expect(setError).toHaveBeenCalledWith(MOCKED_RANDOM_VALUE, error);
|
||||
});
|
||||
});
|
||||
|
||||
it('should clear the error once the request is successful', async () => {
|
||||
const apiCall = () => Promise.resolve(['a', 'b', 'c']);
|
||||
const setError = createWaitableMock();
|
||||
|
||||
const { waitForNextUpdate } = renderHook(() => useAsyncState(apiCall, setError, []));
|
||||
await Promise.race([waitForNextUpdate(), setError.waitToBeCalled()]);
|
||||
renderHook(() => useAsyncState(apiCall, setError, []));
|
||||
|
||||
expect(setError).toHaveBeenCalledWith(MOCKED_RANDOM_VALUE, undefined);
|
||||
await waitFor(() => {
|
||||
expect(setError).toHaveBeenCalledWith(MOCKED_RANDOM_VALUE, undefined);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { renderHook, act } from '@testing-library/react-hooks';
|
||||
import { renderHook, act } from '@testing-library/react';
|
||||
|
||||
import useLastError from './useLastError';
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { renderHook } from '@testing-library/react-hooks';
|
||||
import { renderHook, waitFor } from '@testing-library/react';
|
||||
|
||||
import { config } from '@grafana/runtime';
|
||||
|
||||
@ -13,10 +13,6 @@ import {
|
||||
import { setupMockedResourcesAPI } from './__mocks__/ResourcesAPI';
|
||||
import { useAccountOptions, useDimensionKeys, useIsMonitoringAccount, useMetrics } from './hooks';
|
||||
|
||||
const WAIT_OPTIONS = {
|
||||
timeout: 1000,
|
||||
};
|
||||
|
||||
const originalFeatureToggleValue = config.featureToggles.cloudWatchCrossAccountQuerying;
|
||||
|
||||
describe('hooks', () => {
|
||||
@ -32,10 +28,11 @@ describe('hooks', () => {
|
||||
const isMonitoringAccountMock = jest.fn().mockResolvedValue(true);
|
||||
api.isMonitoringAccount = isMonitoringAccountMock;
|
||||
|
||||
const { waitForNextUpdate } = renderHook(() => useIsMonitoringAccount(api, `$${regionVariable.name}`));
|
||||
await waitForNextUpdate(WAIT_OPTIONS);
|
||||
expect(isMonitoringAccountMock).toHaveBeenCalledTimes(1);
|
||||
expect(isMonitoringAccountMock).toHaveBeenCalledWith(regionVariable.current.value);
|
||||
renderHook(() => useIsMonitoringAccount(api, `$${regionVariable.name}`));
|
||||
await waitFor(() => {
|
||||
expect(isMonitoringAccountMock).toHaveBeenCalledTimes(1);
|
||||
expect(isMonitoringAccountMock).toHaveBeenCalledWith(regionVariable.current.value);
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('useMetricNames', () => {
|
||||
@ -46,19 +43,20 @@ describe('hooks', () => {
|
||||
const getMetricsMock = jest.fn().mockResolvedValue([]);
|
||||
datasource.resources.getMetrics = getMetricsMock;
|
||||
|
||||
const { waitForNextUpdate } = renderHook(() =>
|
||||
renderHook(() =>
|
||||
useMetrics(datasource, {
|
||||
namespace: `$${namespaceVariable.name}`,
|
||||
region: `$${regionVariable.name}`,
|
||||
accountId: `$${accountIdVariable.name}`,
|
||||
})
|
||||
);
|
||||
await waitForNextUpdate(WAIT_OPTIONS);
|
||||
expect(getMetricsMock).toHaveBeenCalledTimes(1);
|
||||
expect(getMetricsMock).toHaveBeenCalledWith({
|
||||
region: regionVariable.current.value,
|
||||
namespace: namespaceVariable.current.value,
|
||||
accountId: accountIdVariable.current.value,
|
||||
await waitFor(() => {
|
||||
expect(getMetricsMock).toHaveBeenCalledTimes(1);
|
||||
expect(getMetricsMock).toHaveBeenCalledWith({
|
||||
region: regionVariable.current.value,
|
||||
namespace: namespaceVariable.current.value,
|
||||
accountId: accountIdVariable.current.value,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -72,7 +70,7 @@ describe('hooks', () => {
|
||||
const getDimensionKeysMock = jest.fn().mockResolvedValue([]);
|
||||
datasource.resources.getDimensionKeys = getDimensionKeysMock;
|
||||
|
||||
const { waitForNextUpdate } = renderHook(() =>
|
||||
renderHook(() =>
|
||||
useDimensionKeys(datasource, {
|
||||
namespace: `$${namespaceVariable.name}`,
|
||||
metricName: `$${metricVariable.name}`,
|
||||
@ -83,16 +81,17 @@ describe('hooks', () => {
|
||||
},
|
||||
})
|
||||
);
|
||||
await waitForNextUpdate(WAIT_OPTIONS);
|
||||
expect(getDimensionKeysMock).toHaveBeenCalledTimes(1);
|
||||
expect(getDimensionKeysMock).toHaveBeenCalledWith({
|
||||
region: regionVariable.current.value,
|
||||
namespace: namespaceVariable.current.value,
|
||||
metricName: metricVariable.current.value,
|
||||
accountId: accountIdVariable.current.value,
|
||||
dimensionFilters: {
|
||||
environment: [dimensionVariable.current.value],
|
||||
},
|
||||
await waitFor(() => {
|
||||
expect(getDimensionKeysMock).toHaveBeenCalledTimes(1);
|
||||
expect(getDimensionKeysMock).toHaveBeenCalledWith({
|
||||
region: regionVariable.current.value,
|
||||
namespace: namespaceVariable.current.value,
|
||||
metricName: metricVariable.current.value,
|
||||
accountId: accountIdVariable.current.value,
|
||||
dimensionFilters: {
|
||||
environment: [dimensionVariable.current.value],
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -105,9 +104,10 @@ describe('hooks', () => {
|
||||
});
|
||||
const getAccountsMock = jest.fn().mockResolvedValue([{ id: '123', label: 'accountLabel' }]);
|
||||
api.getAccounts = getAccountsMock;
|
||||
const { waitForNextUpdate } = renderHook(() => useAccountOptions(api, `$${regionVariable.name}`));
|
||||
await waitForNextUpdate(WAIT_OPTIONS);
|
||||
expect(getAccountsMock).toHaveBeenCalledTimes(0);
|
||||
renderHook(() => useAccountOptions(api, `$${regionVariable.name}`));
|
||||
await waitFor(() => {
|
||||
expect(getAccountsMock).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
});
|
||||
|
||||
it('interpolates region variables before calling the api', async () => {
|
||||
@ -117,10 +117,11 @@ describe('hooks', () => {
|
||||
});
|
||||
const getAccountsMock = jest.fn().mockResolvedValue([{ id: '123', label: 'accountLabel' }]);
|
||||
api.getAccounts = getAccountsMock;
|
||||
const { waitForNextUpdate } = renderHook(() => useAccountOptions(api, `$${regionVariable.name}`));
|
||||
await waitForNextUpdate(WAIT_OPTIONS);
|
||||
expect(getAccountsMock).toHaveBeenCalledTimes(1);
|
||||
expect(getAccountsMock).toHaveBeenCalledWith({ region: regionVariable.current.value });
|
||||
renderHook(() => useAccountOptions(api, `$${regionVariable.name}`));
|
||||
await waitFor(() => {
|
||||
expect(getAccountsMock).toHaveBeenCalledTimes(1);
|
||||
expect(getAccountsMock).toHaveBeenCalledWith({ region: regionVariable.current.value });
|
||||
});
|
||||
});
|
||||
|
||||
it('returns properly formatted account options, and template variables', async () => {
|
||||
@ -130,12 +131,13 @@ describe('hooks', () => {
|
||||
});
|
||||
const getAccountsMock = jest.fn().mockResolvedValue([{ id: '123', label: 'accountLabel' }]);
|
||||
api.getAccounts = getAccountsMock;
|
||||
const { waitForNextUpdate, result } = renderHook(() => useAccountOptions(api, `$${regionVariable.name}`));
|
||||
await waitForNextUpdate(WAIT_OPTIONS);
|
||||
expect(result.current.value).toEqual([
|
||||
{ label: 'accountLabel', description: '123', value: '123' },
|
||||
{ label: 'Template Variables', options: [{ label: '$region', value: '$region' }] },
|
||||
]);
|
||||
const { result } = renderHook(() => useAccountOptions(api, `$${regionVariable.name}`));
|
||||
await waitFor(() => {
|
||||
expect(result.current.value).toEqual([
|
||||
{ label: 'accountLabel', description: '123', value: '123' },
|
||||
{ label: 'Template Variables', options: [{ label: '$region', value: '$region' }] },
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { renderHook } from '@testing-library/react-hooks';
|
||||
import { renderHook } from '@testing-library/react';
|
||||
|
||||
import { config } from '@grafana/runtime';
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { renderHook } from '@testing-library/react-hooks';
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import React, { PropsWithChildren } from 'react';
|
||||
import { from } from 'rxjs';
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { renderHook } from '@testing-library/react-hooks';
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import React, { PropsWithChildren } from 'react';
|
||||
|
||||
import { getDefaultTimeRange } from '@grafana/data';
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { act, render } from '@testing-library/react';
|
||||
import { render, waitFor } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
|
||||
import InfluxDatasource from '../../datasource';
|
||||
@ -41,10 +41,10 @@ async function assertEditor(query: InfluxQuery, textContent: string) {
|
||||
const datasource: InfluxDatasource = {
|
||||
metricFindQuery: () => Promise.resolve([]),
|
||||
} as unknown as InfluxDatasource;
|
||||
await act(async () => {
|
||||
const { container } = await render(
|
||||
<Editor query={query} datasource={datasource} onChange={onChange} onRunQuery={onRunQuery} />
|
||||
);
|
||||
const { container } = render(
|
||||
<Editor query={query} datasource={datasource} onChange={onChange} onRunQuery={onRunQuery} />
|
||||
);
|
||||
await waitFor(() => {
|
||||
expect(container.textContent).toBe(textContent);
|
||||
});
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { renderHook, act } from '@testing-library/react-hooks';
|
||||
import { renderHook, act } from '@testing-library/react';
|
||||
|
||||
import { useShadowedState } from './useShadowedState';
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { renderHook } from '@testing-library/react-hooks';
|
||||
import { renderHook } from '@testing-library/react';
|
||||
|
||||
import { useUniqueId } from './useUniqueId';
|
||||
|
||||
|
@ -118,14 +118,13 @@ describe('LokiContextUi', () => {
|
||||
render(<LokiContextUi {...props} />);
|
||||
await waitFor(() => {
|
||||
expect(props.languageProvider.start).toHaveBeenCalled();
|
||||
expect(screen.getAllByRole('combobox')).toHaveLength(2);
|
||||
});
|
||||
const select = await screen.findAllByRole('combobox');
|
||||
await selectOptionInTest(select[1], 'label3');
|
||||
await selectOptionInTest(screen.getAllByRole('combobox')[1], 'label3');
|
||||
act(() => {
|
||||
jest.runAllTimers();
|
||||
});
|
||||
expect(props.updateFilter).toHaveBeenCalled();
|
||||
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { screen } from '@testing-library/dom';
|
||||
import { render } from '@testing-library/react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import React from 'react';
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { screen } from '@testing-library/dom';
|
||||
import { render } from '@testing-library/react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import React from 'react';
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { getByTestId, render, screen } from '@testing-library/react';
|
||||
import { getByTestId, render, screen, waitFor } from '@testing-library/react';
|
||||
// @ts-ignore
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import React from 'react';
|
||||
@ -141,11 +141,13 @@ describe('PromQueryField', () => {
|
||||
|
||||
// If we check the label browser right away it should be in loading state
|
||||
let labelBrowser = screen.getByRole('button');
|
||||
expect(labelBrowser.textContent).toContain('Loading');
|
||||
expect(labelBrowser).toHaveTextContent('Loading');
|
||||
|
||||
// wait for component to rerender
|
||||
labelBrowser = await screen.findByRole('button');
|
||||
expect(labelBrowser.textContent).toContain('Metrics browser');
|
||||
await waitFor(() => {
|
||||
expect(labelBrowser).toHaveTextContent('Metrics browser');
|
||||
});
|
||||
});
|
||||
|
||||
it('should not run query onBlur', async () => {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { act, renderHook } from '@testing-library/react-hooks';
|
||||
import { act, renderHook } from '@testing-library/react';
|
||||
|
||||
import { lokiQueryEditorExplainKey, promQueryEditorExplainKey, useFlag } from './useFlag';
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { act, renderHook } from '@testing-library/react-hooks';
|
||||
import { act, render, renderHook, screen, waitFor } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
|
||||
import { CascaderOption } from '@grafana/ui';
|
||||
@ -38,12 +37,13 @@ describe('useServices', () => {
|
||||
},
|
||||
} as ZipkinDatasource;
|
||||
|
||||
const { result, waitForNextUpdate } = renderHook(() => useServices(ds));
|
||||
await waitForNextUpdate();
|
||||
expect(result.current.value).toEqual([
|
||||
{ label: 'service1', value: 'service1', isLeaf: false },
|
||||
{ label: 'service2', value: 'service2', isLeaf: false },
|
||||
]);
|
||||
const { result } = renderHook(() => useServices(ds));
|
||||
await waitFor(() => {
|
||||
expect(result.current.value).toEqual([
|
||||
{ label: 'service1', value: 'service1', isLeaf: false },
|
||||
{ label: 'service2', value: 'service2', isLeaf: false },
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -62,25 +62,25 @@ describe('useLoadOptions', () => {
|
||||
},
|
||||
} as ZipkinDatasource;
|
||||
|
||||
const { result, waitForNextUpdate } = renderHook(() => useLoadOptions(ds));
|
||||
const { result } = renderHook(() => useLoadOptions(ds));
|
||||
expect(result.current.allOptions).toEqual({});
|
||||
|
||||
act(() => {
|
||||
result.current.onLoadOptions([{ value: 'service1' } as CascaderOption]);
|
||||
});
|
||||
|
||||
await waitForNextUpdate();
|
||||
|
||||
expect(result.current.allOptions).toEqual({ service1: { span1: undefined, span2: undefined } });
|
||||
await waitFor(() => {
|
||||
expect(result.current.allOptions).toEqual({ service1: { span1: undefined, span2: undefined } });
|
||||
});
|
||||
|
||||
act(() => {
|
||||
result.current.onLoadOptions([{ value: 'service1' } as CascaderOption, { value: 'span1' } as CascaderOption]);
|
||||
});
|
||||
|
||||
await waitForNextUpdate();
|
||||
|
||||
expect(result.current.allOptions).toEqual({
|
||||
service1: { span1: { 'trace1 [10 ms]': 'traceId1' }, span2: undefined },
|
||||
await waitFor(() => {
|
||||
expect(result.current.allOptions).toEqual({
|
||||
service1: { span1: { 'trace1 [10 ms]': 'traceId1' }, span2: undefined },
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { fireEvent, screen } from '@testing-library/dom';
|
||||
import { render } from '@testing-library/react';
|
||||
import { fireEvent, render, screen } from '@testing-library/react';
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import { CoreApp, MutableDataFrame } from '@grafana/data';
|
||||
|
@ -11,7 +11,7 @@ import './jquery.flot.events';
|
||||
import $ from 'jquery';
|
||||
import { clone, find, flatten, isUndefined, map, max as _max, min as _min, sortBy as _sortBy, toNumber } from 'lodash';
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { createRoot, Root } from 'react-dom/client';
|
||||
|
||||
import {
|
||||
DataFrame,
|
||||
@ -76,6 +76,7 @@ class GraphElement {
|
||||
thresholdManager: ThresholdManager;
|
||||
timeRegionManager: TimeRegionManager;
|
||||
declare legendElem: HTMLElement;
|
||||
declare legendElemRoot: Root;
|
||||
|
||||
constructor(
|
||||
private scope: any,
|
||||
@ -118,6 +119,7 @@ class GraphElement {
|
||||
// get graph legend element
|
||||
if (this.elem && this.elem.parent) {
|
||||
this.legendElem = this.elem.parent().find('.graph-legend')[0];
|
||||
this.legendElemRoot = createRoot(this.legendElem);
|
||||
}
|
||||
}
|
||||
|
||||
@ -134,7 +136,7 @@ class GraphElement {
|
||||
|
||||
if (!this.panel.legend.show) {
|
||||
if (this.legendElem.hasChildNodes()) {
|
||||
ReactDOM.unmountComponentAtNode(this.legendElem);
|
||||
this.legendElemRoot.unmount();
|
||||
}
|
||||
this.renderPanel();
|
||||
return;
|
||||
@ -156,7 +158,10 @@ class GraphElement {
|
||||
};
|
||||
|
||||
const legendReactElem = React.createElement(LegendWithThemeProvider, legendProps);
|
||||
ReactDOM.render(legendReactElem, this.legendElem, () => this.renderPanel());
|
||||
|
||||
// render callback isn't supported in react 18+, see: https://github.com/reactwg/react-18/discussions/5
|
||||
this.legendElemRoot.render(legendReactElem);
|
||||
requestIdleCallback(() => this.renderPanel());
|
||||
}
|
||||
|
||||
onGraphHover(evt: LegacyGraphHoverEventPayload | DataHoverPayload) {
|
||||
@ -192,7 +197,7 @@ class GraphElement {
|
||||
this.elem.off();
|
||||
this.elem.remove();
|
||||
|
||||
ReactDOM.unmountComponentAtNode(this.legendElem);
|
||||
this.legendElemRoot.unmount();
|
||||
}
|
||||
|
||||
onGraphHoverClear(handler: LegacyEventHandler<any>) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { renderHook } from '@testing-library/react-hooks';
|
||||
import { renderHook } from '@testing-library/react';
|
||||
|
||||
import { useLayout } from './layout';
|
||||
import { EdgeDatum, NodeDatum } from './types';
|
||||
|
361
yarn.lock
361
yarn.lock
@ -2993,13 +2993,13 @@ __metadata:
|
||||
"@grafana/ui": 10.0.0-pre
|
||||
"@types/jest": 26.0.15
|
||||
"@types/lodash": 4.14.149
|
||||
"@types/react": 17.0.30
|
||||
"@types/react": 18.0.28
|
||||
jquery: 3.5.1
|
||||
lodash: 4.17.21
|
||||
react: 17.0.1
|
||||
react-dom: 17.0.1
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0
|
||||
react-hook-form: 7.5.3
|
||||
react-router-dom: ^5.2.0
|
||||
react-router-dom: 5.3.3
|
||||
tslib: 2.4.0
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
@ -3033,10 +3033,9 @@ __metadata:
|
||||
"@rollup/plugin-commonjs": 23.0.2
|
||||
"@rollup/plugin-json": 5.0.1
|
||||
"@rollup/plugin-node-resolve": 15.0.1
|
||||
"@testing-library/dom": 8.20.0
|
||||
"@testing-library/dom": 9.0.1
|
||||
"@testing-library/jest-dom": 5.16.5
|
||||
"@testing-library/react": 12.1.4
|
||||
"@testing-library/react-hooks": 8.0.1
|
||||
"@testing-library/react": 14.0.0
|
||||
"@testing-library/user-event": 14.4.3
|
||||
"@types/d3-interpolate": ^3.0.0
|
||||
"@types/dompurify": ^2
|
||||
@ -3047,8 +3046,8 @@ __metadata:
|
||||
"@types/marked": 4.0.8
|
||||
"@types/node": 18.14.6
|
||||
"@types/papaparse": 5.3.7
|
||||
"@types/react": 17.0.42
|
||||
"@types/react-dom": 17.0.14
|
||||
"@types/react": 18.0.28
|
||||
"@types/react-dom": 18.0.11
|
||||
"@types/sinon": 10.0.13
|
||||
"@types/testing-library__jest-dom": 5.14.5
|
||||
"@types/tinycolor2": 1.4.3
|
||||
@ -3065,9 +3064,9 @@ __metadata:
|
||||
moment-timezone: 0.5.41
|
||||
ol: 7.2.2
|
||||
papaparse: 5.3.2
|
||||
react: 17.0.2
|
||||
react-dom: 17.0.2
|
||||
react-test-renderer: 17.0.2
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0
|
||||
react-test-renderer: 18.2.0
|
||||
react-use: 17.4.0
|
||||
regenerator-runtime: 0.13.11
|
||||
rimraf: 4.4.0
|
||||
@ -3083,8 +3082,8 @@ __metadata:
|
||||
uplot: 1.6.24
|
||||
xss: ^1.0.14
|
||||
peerDependencies:
|
||||
react: ^16.8.0 || ^17.0.0
|
||||
react-dom: ^16.8.0 || ^17.0.0
|
||||
react: ^17.0.0 || ^18.0.0
|
||||
react-dom: ^17.0.0 || ^18.0.0
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
@ -3293,22 +3292,21 @@ __metadata:
|
||||
"@rollup/plugin-commonjs": 23.0.2
|
||||
"@rollup/plugin-node-resolve": 15.0.1
|
||||
"@sentry/browser": 6.19.7
|
||||
"@testing-library/dom": 8.20.0
|
||||
"@testing-library/react": 12.1.4
|
||||
"@testing-library/react-hooks": 8.0.1
|
||||
"@testing-library/dom": 9.0.1
|
||||
"@testing-library/react": 14.0.0
|
||||
"@testing-library/user-event": 14.4.3
|
||||
"@types/angular": 1.8.4
|
||||
"@types/history": 4.7.11
|
||||
"@types/jest": 29.2.3
|
||||
"@types/lodash": 4.14.191
|
||||
"@types/react": 17.0.42
|
||||
"@types/react-dom": 17.0.14
|
||||
"@types/react": 18.0.28
|
||||
"@types/react-dom": 18.0.11
|
||||
"@types/systemjs": ^0.20.6
|
||||
esbuild: 0.16.17
|
||||
history: 4.10.1
|
||||
lodash: 4.17.21
|
||||
react: 17.0.2
|
||||
react-dom: 17.0.2
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0
|
||||
rimraf: 4.4.0
|
||||
rollup: 2.79.1
|
||||
rollup-plugin-dts: ^5.0.0
|
||||
@ -3321,8 +3319,8 @@ __metadata:
|
||||
tslib: 2.5.0
|
||||
typescript: 4.8.4
|
||||
peerDependencies:
|
||||
react: 17.0.2
|
||||
react-dom: 17.0.2
|
||||
react: ^17.0.0 || ^18.0.0
|
||||
react-dom: ^17.0.0 || ^18.0.0
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
@ -3500,10 +3498,9 @@ __metadata:
|
||||
"@storybook/preset-scss": 1.0.3
|
||||
"@storybook/react": 6.5.16
|
||||
"@storybook/theming": 6.5.16
|
||||
"@testing-library/dom": 8.20.0
|
||||
"@testing-library/dom": 9.0.1
|
||||
"@testing-library/jest-dom": 5.16.5
|
||||
"@testing-library/react": 12.1.4
|
||||
"@testing-library/react-hooks": 8.0.1
|
||||
"@testing-library/react": 14.0.0
|
||||
"@testing-library/user-event": 14.4.3
|
||||
"@types/common-tags": ^1.8.0
|
||||
"@types/d3": 7.4.0
|
||||
@ -3515,15 +3512,15 @@ __metadata:
|
||||
"@types/mock-raf": 1.0.3
|
||||
"@types/node": 18.14.6
|
||||
"@types/prismjs": 1.26.0
|
||||
"@types/react": 17.0.42
|
||||
"@types/react": 18.0.28
|
||||
"@types/react-beautiful-dnd": 13.1.3
|
||||
"@types/react-calendar": 3.9.0
|
||||
"@types/react-color": 3.0.6
|
||||
"@types/react-dom": 17.0.14
|
||||
"@types/react-dom": 18.0.11
|
||||
"@types/react-highlight-words": 0.16.4
|
||||
"@types/react-router-dom": 5.3.3
|
||||
"@types/react-table": 7.7.14
|
||||
"@types/react-test-renderer": 17.0.1
|
||||
"@types/react-test-renderer": 18.0.0
|
||||
"@types/react-transition-group": 4.4.5
|
||||
"@types/react-window": 1.8.5
|
||||
"@types/slate": 0.47.11
|
||||
@ -3561,12 +3558,12 @@ __metadata:
|
||||
rc-slider: 10.1.1
|
||||
rc-time-picker: ^3.7.3
|
||||
rc-tooltip: 5.3.1
|
||||
react: 17.0.2
|
||||
react: 18.2.0
|
||||
react-beautiful-dnd: 13.1.1
|
||||
react-calendar: 4.0.0
|
||||
react-colorful: 5.6.1
|
||||
react-custom-scrollbars-2: 4.5.0
|
||||
react-dom: 17.0.2
|
||||
react-dom: 18.2.0
|
||||
react-dropzone: 14.2.3
|
||||
react-highlight-words: 0.20.0
|
||||
react-hook-form: 7.5.3
|
||||
@ -3574,11 +3571,11 @@ __metadata:
|
||||
react-inlinesvg: 3.0.2
|
||||
react-popper: 2.3.0
|
||||
react-popper-tooltip: 4.4.2
|
||||
react-router-dom: ^5.2.0
|
||||
react-router-dom: 5.3.3
|
||||
react-select: 5.7.0
|
||||
react-select-event: ^5.1.0
|
||||
react-table: 7.8.0
|
||||
react-test-renderer: 17.0.2
|
||||
react-test-renderer: 18.2.0
|
||||
react-transition-group: 4.4.5
|
||||
react-use: 17.4.0
|
||||
react-window: 1.8.8
|
||||
@ -3603,8 +3600,8 @@ __metadata:
|
||||
uuid: 9.0.0
|
||||
webpack: 5.76.0
|
||||
peerDependencies:
|
||||
react: ^16.8.0 || ^17.0.0
|
||||
react-dom: ^16.8.0 || ^17.0.0
|
||||
react: ^17.0.0 || ^18.0.0
|
||||
react-dom: ^17.0.0 || ^18.0.0
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
@ -7315,6 +7312,53 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@storybook/addon-docs@patch:@storybook/addon-docs@npm:6.5.16#.yarn/patches/@storybook-addon-docs-npm-6.5.16-56ecbd77e7.patch::locator=grafana%40workspace%3A.":
|
||||
version: 6.5.16
|
||||
resolution: "@storybook/addon-docs@patch:@storybook/addon-docs@npm%3A6.5.16#.yarn/patches/@storybook-addon-docs-npm-6.5.16-56ecbd77e7.patch::version=6.5.16&hash=1c984c&locator=grafana%40workspace%3A."
|
||||
dependencies:
|
||||
"@babel/plugin-transform-react-jsx": ^7.12.12
|
||||
"@babel/preset-env": ^7.12.11
|
||||
"@jest/transform": ^26.6.2
|
||||
"@mdx-js/react": ^1.6.22
|
||||
"@storybook/addons": 6.5.16
|
||||
"@storybook/api": 6.5.16
|
||||
"@storybook/components": 6.5.16
|
||||
"@storybook/core-common": 6.5.16
|
||||
"@storybook/core-events": 6.5.16
|
||||
"@storybook/csf": 0.0.2--canary.4566f4d.1
|
||||
"@storybook/docs-tools": 6.5.16
|
||||
"@storybook/mdx1-csf": ^0.0.1
|
||||
"@storybook/node-logger": 6.5.16
|
||||
"@storybook/postinstall": 6.5.16
|
||||
"@storybook/preview-web": 6.5.16
|
||||
"@storybook/source-loader": 6.5.16
|
||||
"@storybook/store": 6.5.16
|
||||
"@storybook/theming": 6.5.16
|
||||
babel-loader: ^8.0.0
|
||||
core-js: ^3.8.2
|
||||
fast-deep-equal: ^3.1.3
|
||||
global: ^4.4.0
|
||||
lodash: ^4.17.21
|
||||
regenerator-runtime: ^0.13.7
|
||||
remark-external-links: ^8.0.0
|
||||
remark-slug: ^6.0.0
|
||||
ts-dedent: ^2.0.0
|
||||
util-deprecate: ^1.0.2
|
||||
peerDependencies:
|
||||
"@storybook/mdx2-csf": ^0.0.3
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||
peerDependenciesMeta:
|
||||
"@storybook/mdx2-csf":
|
||||
optional: true
|
||||
react:
|
||||
optional: true
|
||||
react-dom:
|
||||
optional: true
|
||||
checksum: de675ef948051275255c1430e114a6bcdb7fabc48f747c3d8d79a062679790208d8c6814809d8747068c5ee8a5f5425ca1c5d87f495fe80bcff99cbd45e72832
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@storybook/addon-essentials@npm:6.5.16":
|
||||
version: 6.5.16
|
||||
resolution: "@storybook/addon-essentials@npm:6.5.16"
|
||||
@ -8672,9 +8716,9 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@testing-library/dom@npm:8.20.0, @testing-library/dom@npm:>=7, @testing-library/dom@npm:^8.0.0":
|
||||
version: 8.20.0
|
||||
resolution: "@testing-library/dom@npm:8.20.0"
|
||||
"@testing-library/dom@npm:9.0.1, @testing-library/dom@npm:>=7, @testing-library/dom@npm:^9.0.0":
|
||||
version: 9.0.1
|
||||
resolution: "@testing-library/dom@npm:9.0.1"
|
||||
dependencies:
|
||||
"@babel/code-frame": ^7.10.4
|
||||
"@babel/runtime": ^7.12.5
|
||||
@ -8682,9 +8726,9 @@ __metadata:
|
||||
aria-query: ^5.0.0
|
||||
chalk: ^4.1.0
|
||||
dom-accessibility-api: ^0.5.9
|
||||
lz-string: ^1.4.4
|
||||
lz-string: ^1.5.0
|
||||
pretty-format: ^27.0.2
|
||||
checksum: 1e599129a2fe91959ce80900a0a4897232b89e2a8e22c1f5950c36d39c97629ea86b4986b60b173b5525a05de33fde1e35836ea597b03de78cc51b122835c6f0
|
||||
checksum: fa3d4097d0efd3b186d90e32ffa71c3f9c4ea7a5a793b186b565044b2950eea469594e1f75803e5edb52a75731feecd19cf7034b009b0bd3bfba173eb9c9cd0c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -8705,7 +8749,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@testing-library/react-hooks@npm:8.0.1":
|
||||
"@testing-library/react-hooks@npm:^8.0.1":
|
||||
version: 8.0.1
|
||||
resolution: "@testing-library/react-hooks@npm:8.0.1"
|
||||
dependencies:
|
||||
@ -8727,17 +8771,17 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@testing-library/react@npm:12.1.4":
|
||||
version: 12.1.4
|
||||
resolution: "@testing-library/react@npm:12.1.4"
|
||||
"@testing-library/react@npm:14.0.0":
|
||||
version: 14.0.0
|
||||
resolution: "@testing-library/react@npm:14.0.0"
|
||||
dependencies:
|
||||
"@babel/runtime": ^7.12.5
|
||||
"@testing-library/dom": ^8.0.0
|
||||
"@types/react-dom": "*"
|
||||
"@testing-library/dom": ^9.0.0
|
||||
"@types/react-dom": ^18.0.0
|
||||
peerDependencies:
|
||||
react: "*"
|
||||
react-dom: "*"
|
||||
checksum: 944c5f8d4abb22c0650c25c7ae499651828c37c0e741ff67a4635d4cd99b307d486dabec05b372aba638bd359d29cd2af97393b5055ea294a201d80b4bc384b8
|
||||
react: ^18.0.0
|
||||
react-dom: ^18.0.0
|
||||
checksum: 4a54c8f56cc4a39b50803205f84f06280bb76521d6d5d4b3b36651d760c7c7752ef142d857d52aaf4fad4848ed7a8be49afc793a5dda105955d2f8bef24901ac
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -9468,13 +9512,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/history@npm:*":
|
||||
version: 4.7.9
|
||||
resolution: "@types/history@npm:4.7.9"
|
||||
checksum: 556b062adb92795839301965776b0418e9ca32798bd8a6031345a6a84d7512771107143a497b7e3ff826d0b0d4456e962c6450485dda6f55c7dd33371e840529
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/history@npm:4.7.11, @types/history@npm:^4.7.11":
|
||||
version: 4.7.11
|
||||
resolution: "@types/history@npm:4.7.11"
|
||||
@ -10024,12 +10061,12 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/react-dom@npm:17.0.14":
|
||||
version: 17.0.14
|
||||
resolution: "@types/react-dom@npm:17.0.14"
|
||||
"@types/react-dom@npm:18.0.11, @types/react-dom@npm:^18.0.0":
|
||||
version: 18.0.11
|
||||
resolution: "@types/react-dom@npm:18.0.11"
|
||||
dependencies:
|
||||
"@types/react": "*"
|
||||
checksum: b54cd0ef573236b3d87fe7493e6d1c36d8b4ca37a3b46364272a5c91ac178e3296b68ea1aeb299ce68f12ad663c5720ee890d0539b14881c6754bdcbdb0befa0
|
||||
checksum: 579691e4d5ec09688087568037c35edf8cfb1ab3e07f6c60029280733ee7b5c06d66df6fcc90786702c93ac8cb13bc7ff16c79ddfc75d082938fbaa36e1cdbf4
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -10096,12 +10133,12 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"@types/react-router@npm:*":
|
||||
version: 5.1.17
|
||||
resolution: "@types/react-router@npm:5.1.17"
|
||||
version: 5.1.20
|
||||
resolution: "@types/react-router@npm:5.1.20"
|
||||
dependencies:
|
||||
"@types/history": "*"
|
||||
"@types/history": ^4.7.11
|
||||
"@types/react": "*"
|
||||
checksum: b9d1c7b6ce073652c39712d2b02aeec7640036e369c04be2e57e4b0eb049b64ec9f34fb91cad680ab3f794e89576f77aacadb015b61eb21500a1779e5c955b86
|
||||
checksum: 128764143473a5e9457ddc715436b5d49814b1c214dde48939b9bef23f0e77f52ffcdfa97eb8d3cc27e2c229869c0cdd90f637d887b62f2c9f065a87d6425419
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -10114,12 +10151,12 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/react-test-renderer@npm:17.0.1":
|
||||
version: 17.0.1
|
||||
resolution: "@types/react-test-renderer@npm:17.0.1"
|
||||
"@types/react-test-renderer@npm:18.0.0":
|
||||
version: 18.0.0
|
||||
resolution: "@types/react-test-renderer@npm:18.0.0"
|
||||
dependencies:
|
||||
"@types/react": "*"
|
||||
checksum: ecaae8df36cd8cfeb89080d52534856acc3789bad9a6e369ff5119426377c827b4e5b5daa638507f2c1c2fd6c994bf45de288a698143178cd4049c2cd8b77b35
|
||||
checksum: 6afc938a1d7618d88ab8793e251f0bd5981bf3f08c1b600f74df3f8800b92589ea534dc6dcb7c8d683893fcc740bf8d7843a42bf2dae59785cfe88f004bd7b0b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -10169,36 +10206,14 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/react@npm:*":
|
||||
version: 17.0.33
|
||||
resolution: "@types/react@npm:17.0.33"
|
||||
"@types/react@npm:*, @types/react@npm:18.0.28":
|
||||
version: 18.0.28
|
||||
resolution: "@types/react@npm:18.0.28"
|
||||
dependencies:
|
||||
"@types/prop-types": "*"
|
||||
"@types/scheduler": "*"
|
||||
csstype: ^3.0.2
|
||||
checksum: 5f53f3dae034229ff1eccb5de1c16d046696e883f8eae81b86e95c532798e655015e4edff8a6c9ec8f1c0ef12bb60dec43622d06256ba33ba6069e67a74b8d4e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/react@npm:17.0.30":
|
||||
version: 17.0.30
|
||||
resolution: "@types/react@npm:17.0.30"
|
||||
dependencies:
|
||||
"@types/prop-types": "*"
|
||||
"@types/scheduler": "*"
|
||||
csstype: ^3.0.2
|
||||
checksum: e3aaac1b8fda6e3622b75db0bd7d8dc412c2f2b77a00afdd32cae8c71fb0b1ca6926ab1fbe1c536dd51d96c0ba372738993837a8df1637637aaab7b86e421b7f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/react@npm:17.0.42":
|
||||
version: 17.0.42
|
||||
resolution: "@types/react@npm:17.0.42"
|
||||
dependencies:
|
||||
"@types/prop-types": "*"
|
||||
"@types/scheduler": "*"
|
||||
csstype: ^3.0.2
|
||||
checksum: 9a84374da1173901b5eba6b2dda9e70220842c8e70274628e5c93684fca59786b7f6215c93f492e34f8834983de096b2544f280c60da9b8fd4c3f20ffe7cc51e
|
||||
checksum: e752df961105e5127652460504785897ca6e77259e0da8f233f694f9e8f451cde7fa0709d4456ade0ff600c8ce909cfe29f9b08b9c247fa9b734e126ec53edd7
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -20160,10 +20175,10 @@ __metadata:
|
||||
"@sentry/utils": 6.19.7
|
||||
"@swc/core": 1.3.38
|
||||
"@swc/helpers": 0.4.14
|
||||
"@testing-library/dom": 8.20.0
|
||||
"@testing-library/dom": 9.0.1
|
||||
"@testing-library/jest-dom": 5.16.5
|
||||
"@testing-library/react": 12.1.4
|
||||
"@testing-library/react-hooks": 8.0.1
|
||||
"@testing-library/react": 14.0.0
|
||||
"@testing-library/react-hooks": ^8.0.1
|
||||
"@testing-library/user-event": 14.4.3
|
||||
"@types/angular": 1.8.4
|
||||
"@types/angular-route": 1.7.2
|
||||
@ -20192,16 +20207,16 @@ __metadata:
|
||||
"@types/papaparse": 5.3.7
|
||||
"@types/pluralize": ^0.0.29
|
||||
"@types/prismjs": 1.26.0
|
||||
"@types/react": 17.0.42
|
||||
"@types/react": 18.0.28
|
||||
"@types/react-beautiful-dnd": 13.1.3
|
||||
"@types/react-dom": 17.0.14
|
||||
"@types/react-dom": 18.0.11
|
||||
"@types/react-grid-layout": 1.3.2
|
||||
"@types/react-highlight-words": 0.16.4
|
||||
"@types/react-redux": 7.1.25
|
||||
"@types/react-resizable": 3.0.3
|
||||
"@types/react-router-dom": 5.3.3
|
||||
"@types/react-table": 7.7.14
|
||||
"@types/react-test-renderer": 17.0.1
|
||||
"@types/react-test-renderer": 18.0.0
|
||||
"@types/react-transition-group": 4.4.5
|
||||
"@types/react-virtualized-auto-sizer": 1.0.1
|
||||
"@types/react-window": 1.8.5
|
||||
@ -20341,11 +20356,11 @@ __metadata:
|
||||
rc-time-picker: 3.7.3
|
||||
rc-tree: 5.7.2
|
||||
re-resizable: 6.9.9
|
||||
react: 17.0.2
|
||||
react: 18.2.0
|
||||
react-awesome-query-builder: 5.4.0
|
||||
react-beautiful-dnd: 13.1.1
|
||||
react-diff-viewer: ^3.1.1
|
||||
react-dom: 17.0.2
|
||||
react-dom: 18.2.0
|
||||
react-draggable: 4.4.5
|
||||
react-dropzone: ^14.2.3
|
||||
react-enable: ^3.1.0
|
||||
@ -20361,13 +20376,13 @@ __metadata:
|
||||
react-refresh: 0.14.0
|
||||
react-resizable: 3.0.4
|
||||
react-reverse-portal: 2.1.1
|
||||
react-router-dom: ^5.2.0
|
||||
react-router-dom: 5.3.3
|
||||
react-select: 5.7.0
|
||||
react-select-event: 5.5.1
|
||||
react-simple-compat: 1.2.3
|
||||
react-split-pane: 0.1.92
|
||||
react-table: 7.8.0
|
||||
react-test-renderer: 17.0.2
|
||||
react-test-renderer: 18.2.0
|
||||
react-transition-group: 4.4.5
|
||||
react-use: 17.4.0
|
||||
react-virtual: 2.10.4
|
||||
@ -25165,12 +25180,12 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"lz-string@npm:^1.4.4":
|
||||
version: 1.4.4
|
||||
resolution: "lz-string@npm:1.4.4"
|
||||
"lz-string@npm:^1.5.0":
|
||||
version: 1.5.0
|
||||
resolution: "lz-string@npm:1.5.0"
|
||||
bin:
|
||||
lz-string: bin/bin.js
|
||||
checksum: 54e31238a61a84d8f664d9860a9fba7310c5b97a52c444f80543069bc084815eff40b8d4474ae1d93992fdf6c252dca37cf27f6adbeb4dbc3df2f3ac773d0e61
|
||||
checksum: 1ee98b4580246fd90dd54da6e346fb1caefcf05f677c686d9af237a157fdea3fd7c83a4bc58f858cd5b10a34d27afe0fdcbd0505a47e0590726a873dc8b8f65d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -30810,29 +30825,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-dom@npm:17.0.1":
|
||||
version: 17.0.1
|
||||
resolution: "react-dom@npm:17.0.1"
|
||||
"react-dom@npm:18.2.0":
|
||||
version: 18.2.0
|
||||
resolution: "react-dom@npm:18.2.0"
|
||||
dependencies:
|
||||
loose-envify: ^1.1.0
|
||||
object-assign: ^4.1.1
|
||||
scheduler: ^0.20.1
|
||||
scheduler: ^0.23.0
|
||||
peerDependencies:
|
||||
react: 17.0.1
|
||||
checksum: df2af300dd4f49a5daaccc38f5a307def2a9ae2b7ebffa3dce8fb9986129057696b86a2c94e5ae36133057c69428c500e4ee3bf5884eb44e5632ace8b7ace41f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-dom@npm:17.0.2":
|
||||
version: 17.0.2
|
||||
resolution: "react-dom@npm:17.0.2"
|
||||
dependencies:
|
||||
loose-envify: ^1.1.0
|
||||
object-assign: ^4.1.1
|
||||
scheduler: ^0.20.2
|
||||
peerDependencies:
|
||||
react: 17.0.2
|
||||
checksum: 1c1eaa3bca7c7228d24b70932e3d7c99e70d1d04e13bb0843bbf321582bc25d7961d6b8a6978a58a598af2af496d1cedcfb1bf65f6b0960a0a8161cb8dab743c
|
||||
react: ^18.2.0
|
||||
checksum: 7d323310bea3a91be2965f9468d552f201b1c27891e45ddc2d6b8f717680c95a75ae0bc1e3f5cf41472446a2589a75aed4483aee8169287909fcd59ad149e8cc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -30905,13 +30906,13 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"react-error-boundary@npm:^3.1.0":
|
||||
version: 3.1.3
|
||||
resolution: "react-error-boundary@npm:3.1.3"
|
||||
version: 3.1.4
|
||||
resolution: "react-error-boundary@npm:3.1.4"
|
||||
dependencies:
|
||||
"@babel/runtime": ^7.12.5
|
||||
peerDependencies:
|
||||
react: ">=16.13.1"
|
||||
checksum: 0a05af404aa054c54d7bc65a1814810093bf136c3ad4b3576a51d8509ee8fc302adfb66405da501fc01e839db557dd0d994b487e651897e36293907bb61458cf
|
||||
checksum: f36270a5d775a25c8920f854c0d91649ceea417b15b5bc51e270a959b0476647bb79abb4da3be7dd9a4597b029214e8fe43ea914a7f16fa7543c91f784977f1b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -31030,13 +31031,20 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-is@npm:17.0.2, react-is@npm:^16.12.0 || ^17.0.0, react-is@npm:^17.0.1, react-is@npm:^17.0.2":
|
||||
"react-is@npm:17.0.2, react-is@npm:^17.0.1, react-is@npm:^17.0.2":
|
||||
version: 17.0.2
|
||||
resolution: "react-is@npm:17.0.2"
|
||||
checksum: 9d6d111d8990dc98bc5402c1266a808b0459b5d54830bbea24c12d908b536df7883f268a7868cfaedde3dd9d4e0d574db456f84d2e6df9c4526f99bb4b5344d8
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-is@npm:^16.12.0 || ^17.0.0 || ^18.0.0, react-is@npm:^18.2.0":
|
||||
version: 18.2.0
|
||||
resolution: "react-is@npm:18.2.0"
|
||||
checksum: e72d0ba81b5922759e4aff17e0252bd29988f9642ed817f56b25a3e217e13eea8a7f2322af99a06edb779da12d5d636e9fda473d620df9a3da0df2a74141d53e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-is@npm:^16.12.0, react-is@npm:^16.13.1, react-is@npm:^16.6.0, react-is@npm:^16.7.0, react-is@npm:^16.8.1":
|
||||
version: 16.13.1
|
||||
resolution: "react-is@npm:16.13.1"
|
||||
@ -31184,26 +31192,26 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-router-dom@npm:^5.2.0":
|
||||
version: 5.3.0
|
||||
resolution: "react-router-dom@npm:5.3.0"
|
||||
"react-router-dom@npm:5.3.3":
|
||||
version: 5.3.3
|
||||
resolution: "react-router-dom@npm:5.3.3"
|
||||
dependencies:
|
||||
"@babel/runtime": ^7.12.13
|
||||
history: ^4.9.0
|
||||
loose-envify: ^1.3.1
|
||||
prop-types: ^15.6.2
|
||||
react-router: 5.2.1
|
||||
react-router: 5.3.3
|
||||
tiny-invariant: ^1.0.2
|
||||
tiny-warning: ^1.0.0
|
||||
peerDependencies:
|
||||
react: ">=15"
|
||||
checksum: 47584fd629ecca52398d7888cab193b8a74057cc99a7ef44410c405d4082f618c3c0399db5325bc3524f9c511404086169570013b61a94dfa6acdfdc850d7a1f
|
||||
checksum: e1998918e391611f09b967bce0cb88bc9794aa3d8dc5f86453467a1226ae2ace648a1f401f5282f19c84a3a61fa6a3207e2a6fdfe8c8efae0b255244631febeb
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-router@npm:5.2.1":
|
||||
version: 5.2.1
|
||||
resolution: "react-router@npm:5.2.1"
|
||||
"react-router@npm:5.3.3":
|
||||
version: 5.3.3
|
||||
resolution: "react-router@npm:5.3.3"
|
||||
dependencies:
|
||||
"@babel/runtime": ^7.12.13
|
||||
history: ^4.9.0
|
||||
@ -31217,7 +31225,7 @@ __metadata:
|
||||
tiny-warning: ^1.0.0
|
||||
peerDependencies:
|
||||
react: ">=15"
|
||||
checksum: 7daae084bf64531eb619cc5f4cc40ce5ae0a541b64f71d74ec71a38cbf6130ebdbb7cf38f157303fad5846deec259401f96c4d6c7386466dcc989719e01f9aaa
|
||||
checksum: 52a9f28fa97577fda18a8ed2922b658704eafe873e444fe07202640d55d9e81e67c03efd2b2a5b80e3a80e8be8352df826a227ce5f42b33b91bef853c74d4841
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -31259,15 +31267,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-shallow-renderer@npm:^16.13.1":
|
||||
version: 16.14.1
|
||||
resolution: "react-shallow-renderer@npm:16.14.1"
|
||||
"react-shallow-renderer@npm:^16.15.0":
|
||||
version: 16.15.0
|
||||
resolution: "react-shallow-renderer@npm:16.15.0"
|
||||
dependencies:
|
||||
object-assign: ^4.1.1
|
||||
react-is: ^16.12.0 || ^17.0.0
|
||||
react-is: ^16.12.0 || ^17.0.0 || ^18.0.0
|
||||
peerDependencies:
|
||||
react: ^16.0.0 || ^17.0.0
|
||||
checksum: f344c663c48720d19559b4198b1f63ad47a3f11bedc92ede053a6c0706b5209e6110086f3ccc6db04eda9f0d1a415845956ddfb6ce09a922167d4831fcba9314
|
||||
react: ^16.0.0 || ^17.0.0 || ^18.0.0
|
||||
checksum: 6052c7e3e9627485120ebd8257f128aad8f56386fe8d42374b7743eac1be457c33506d153c7886b4e32923c0c352d402ab805ef9ca02dbcd8393b2bdeb6e5af8
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -31307,6 +31315,20 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-split-pane@patch:react-split-pane@npm:0.1.92#.yarn/patches/react-split-pane-npm-0.1.92-93dbf51dff.patch::locator=grafana%40workspace%3A.":
|
||||
version: 0.1.92
|
||||
resolution: "react-split-pane@patch:react-split-pane@npm%3A0.1.92#.yarn/patches/react-split-pane-npm-0.1.92-93dbf51dff.patch::version=0.1.92&hash=23e19a&locator=grafana%40workspace%3A."
|
||||
dependencies:
|
||||
prop-types: ^15.7.2
|
||||
react-lifecycles-compat: ^3.0.4
|
||||
react-style-proptype: ^3.2.2
|
||||
peerDependencies:
|
||||
react: ^16.0.0-0
|
||||
react-dom: ^16.0.0-0
|
||||
checksum: 4cdcc9e5a03ee1534100ddd6d5a5cce9e083ffe1a0acf7adf085d71d003d0ac475192964e0d63b2887392871dd687ec5340e2122eb588b5685de0a219cb00b11
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-style-proptype@npm:^3.2.2":
|
||||
version: 3.2.2
|
||||
resolution: "react-style-proptype@npm:3.2.2"
|
||||
@ -31340,17 +31362,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-test-renderer@npm:17.0.2":
|
||||
version: 17.0.2
|
||||
resolution: "react-test-renderer@npm:17.0.2"
|
||||
"react-test-renderer@npm:18.2.0":
|
||||
version: 18.2.0
|
||||
resolution: "react-test-renderer@npm:18.2.0"
|
||||
dependencies:
|
||||
object-assign: ^4.1.1
|
||||
react-is: ^17.0.2
|
||||
react-shallow-renderer: ^16.13.1
|
||||
scheduler: ^0.20.2
|
||||
react-is: ^18.2.0
|
||||
react-shallow-renderer: ^16.15.0
|
||||
scheduler: ^0.23.0
|
||||
peerDependencies:
|
||||
react: 17.0.2
|
||||
checksum: e6b5c6ed2a0bde2c34f1ab9523ff9bc4c141a271daf730d6b852374e83acc0155d58ab71a318251e953ebfa65b8bebb9c5dce3eba1ccfcbef7cc4e1e8261c401
|
||||
react: ^18.2.0
|
||||
checksum: 6b6980ced93fa2b72662d5e4ab3b4896833586940047ce52ca9aca801e5432adf05fcbe28289b0af3ce6a2a7c590974e25dcc8aa43d0de658bfe8bbcd686f958
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -31475,23 +31496,12 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react@npm:17.0.1":
|
||||
version: 17.0.1
|
||||
resolution: "react@npm:17.0.1"
|
||||
"react@npm:18.2.0":
|
||||
version: 18.2.0
|
||||
resolution: "react@npm:18.2.0"
|
||||
dependencies:
|
||||
loose-envify: ^1.1.0
|
||||
object-assign: ^4.1.1
|
||||
checksum: 83b9df9529a2b489f00a4eaa608fc7d55518b258e046c100344ae068713e43ae64e477a140f87e38cfe75489bcfd26d27fce5818f89f4ec41bdbda7ead4bb426
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react@npm:17.0.2":
|
||||
version: 17.0.2
|
||||
resolution: "react@npm:17.0.2"
|
||||
dependencies:
|
||||
loose-envify: ^1.1.0
|
||||
object-assign: ^4.1.1
|
||||
checksum: b254cc17ce3011788330f7bbf383ab653c6848902d7936a87b09d835d091e3f295f7e9dd1597c6daac5dc80f90e778c8230218ba8ad599f74adcc11e33b9d61b
|
||||
checksum: 88e38092da8839b830cda6feef2e8505dec8ace60579e46aa5490fc3dc9bba0bd50336507dc166f43e3afc1c42939c09fe33b25fae889d6f402721dcd78fca1b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -32799,13 +32809,12 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"scheduler@npm:^0.20.1, scheduler@npm:^0.20.2":
|
||||
version: 0.20.2
|
||||
resolution: "scheduler@npm:0.20.2"
|
||||
"scheduler@npm:^0.23.0":
|
||||
version: 0.23.0
|
||||
resolution: "scheduler@npm:0.23.0"
|
||||
dependencies:
|
||||
loose-envify: ^1.1.0
|
||||
object-assign: ^4.1.1
|
||||
checksum: c4b35cf967c8f0d3e65753252d0f260271f81a81e427241295c5a7b783abf4ea9e905f22f815ab66676f5313be0a25f47be582254db8f9241b259213e999b8fc
|
||||
checksum: d79192eeaa12abef860c195ea45d37cbf2bbf5f66e3c4dcd16f54a7da53b17788a70d109ee3d3dde1a0fd50e6a8fc171f4300356c5aee4fc0171de526bf35f8a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user