From 55138b967bddfe107b1d1e88c752ab19e6424836 Mon Sep 17 00:00:00 2001 From: Matej Kubinec Date: Thu, 2 Apr 2026 15:44:54 +0200 Subject: [PATCH] PMM-14930 Listen for updated settings & remove settings pages --- .../ExportDataset/ExportDataset.tsx | 2 +- .../app/percona/settings/Settings.messages.ts | 89 ---- .../app/percona/settings/Settings.styles.ts | 50 --- .../components/Advanced/Advanced.constants.ts | 38 -- .../components/Advanced/Advanced.styles.ts | 124 ------ .../components/Advanced/Advanced.test.tsx | 337 --------------- .../settings/components/Advanced/Advanced.tsx | 395 ------------------ .../components/Advanced/Advanced.types.ts | 16 - .../components/Advanced/Advanced.utils.ts | 38 -- .../components/Advanced/__mocks__/stubs.ts | 5 - .../Communication/Communication.messages.ts | 69 --- .../Communication/Communication.service.ts | 9 - .../Communication/Communication.styles.ts | 21 - .../Communication/Communication.tsx | 101 ----- .../Communication/Email/Email.constants.ts | 22 - .../Communication/Email/Email.styles.ts | 14 - .../Communication/Email/Email.test.tsx | 81 ---- .../components/Communication/Email/Email.tsx | 182 -------- .../Communication/Email/Email.types.ts | 13 - .../Communication/Email/Email.utils.test.tsx | 180 -------- .../Communication/Email/Email.utils.ts | 82 ---- .../TestEmailSettings.messages.ts | 5 - .../TestEmailSettings.styles.ts | 17 - .../TestEmailSettings/TestEmailSettings.tsx | 50 --- .../TestEmailSettings.types.ts | 5 - .../Communication/Slack/Slack.test.tsx | 51 --- .../components/Communication/Slack/Slack.tsx | 63 --- .../Diagnostics/Diagnostics.styles.ts | 21 - .../Diagnostics/Diagnostics.test.tsx | 17 - .../components/Diagnostics/Diagnostics.tsx | 38 -- .../MetricsResolution.constants.ts | 37 -- .../MetricsResolution.styles.ts | 22 - .../MetricsResolution.test.tsx | 132 ------ .../MetricsResolution/MetricsResolution.tsx | 171 -------- .../MetricsResolution.types.ts | 12 - .../MetricsResolution.utils.ts | 18 - .../components/SSHKey/SSHKey.styles.ts | 14 - .../components/SSHKey/SSHKey.test.tsx | 71 ---- .../settings/components/SSHKey/SSHKey.tsx | 85 ---- .../app/percona/settings/components/index.ts | 4 - .../Elements/SwitchRow/SwitchRow.styles.ts | 23 + .../Elements/SwitchRow}/SwitchRow.tsx | 6 +- .../Elements/SwitchRow}/SwitchRow.types.ts | 0 .../components/Elements/SwitchRow/index.ts | 1 + .../PerconaBootstrapper.tsx | 9 + public/app/routes/routes.tsx | 44 -- 46 files changed, 36 insertions(+), 2748 deletions(-) delete mode 100644 public/app/percona/settings/Settings.messages.ts delete mode 100644 public/app/percona/settings/Settings.styles.ts delete mode 100644 public/app/percona/settings/components/Advanced/Advanced.constants.ts delete mode 100644 public/app/percona/settings/components/Advanced/Advanced.styles.ts delete mode 100644 public/app/percona/settings/components/Advanced/Advanced.test.tsx delete mode 100644 public/app/percona/settings/components/Advanced/Advanced.tsx delete mode 100644 public/app/percona/settings/components/Advanced/Advanced.types.ts delete mode 100644 public/app/percona/settings/components/Advanced/Advanced.utils.ts delete mode 100644 public/app/percona/settings/components/Advanced/__mocks__/stubs.ts delete mode 100644 public/app/percona/settings/components/Communication/Communication.messages.ts delete mode 100644 public/app/percona/settings/components/Communication/Communication.service.ts delete mode 100644 public/app/percona/settings/components/Communication/Communication.styles.ts delete mode 100644 public/app/percona/settings/components/Communication/Communication.tsx delete mode 100644 public/app/percona/settings/components/Communication/Email/Email.constants.ts delete mode 100644 public/app/percona/settings/components/Communication/Email/Email.styles.ts delete mode 100644 public/app/percona/settings/components/Communication/Email/Email.test.tsx delete mode 100644 public/app/percona/settings/components/Communication/Email/Email.tsx delete mode 100644 public/app/percona/settings/components/Communication/Email/Email.types.ts delete mode 100644 public/app/percona/settings/components/Communication/Email/Email.utils.test.tsx delete mode 100644 public/app/percona/settings/components/Communication/Email/Email.utils.ts delete mode 100644 public/app/percona/settings/components/Communication/Email/TestEmailSettings/TestEmailSettings.messages.ts delete mode 100644 public/app/percona/settings/components/Communication/Email/TestEmailSettings/TestEmailSettings.styles.ts delete mode 100644 public/app/percona/settings/components/Communication/Email/TestEmailSettings/TestEmailSettings.tsx delete mode 100644 public/app/percona/settings/components/Communication/Email/TestEmailSettings/TestEmailSettings.types.ts delete mode 100644 public/app/percona/settings/components/Communication/Slack/Slack.test.tsx delete mode 100644 public/app/percona/settings/components/Communication/Slack/Slack.tsx delete mode 100644 public/app/percona/settings/components/Diagnostics/Diagnostics.styles.ts delete mode 100644 public/app/percona/settings/components/Diagnostics/Diagnostics.test.tsx delete mode 100644 public/app/percona/settings/components/Diagnostics/Diagnostics.tsx delete mode 100644 public/app/percona/settings/components/MetricsResolution/MetricsResolution.constants.ts delete mode 100644 public/app/percona/settings/components/MetricsResolution/MetricsResolution.styles.ts delete mode 100644 public/app/percona/settings/components/MetricsResolution/MetricsResolution.test.tsx delete mode 100644 public/app/percona/settings/components/MetricsResolution/MetricsResolution.tsx delete mode 100644 public/app/percona/settings/components/MetricsResolution/MetricsResolution.types.ts delete mode 100644 public/app/percona/settings/components/MetricsResolution/MetricsResolution.utils.ts delete mode 100644 public/app/percona/settings/components/SSHKey/SSHKey.styles.ts delete mode 100644 public/app/percona/settings/components/SSHKey/SSHKey.test.tsx delete mode 100644 public/app/percona/settings/components/SSHKey/SSHKey.tsx delete mode 100644 public/app/percona/settings/components/index.ts create mode 100644 public/app/percona/shared/components/Elements/SwitchRow/SwitchRow.styles.ts rename public/app/percona/{settings/components/Advanced => shared/components/Elements/SwitchRow}/SwitchRow.tsx (82%) rename public/app/percona/{settings/components/Advanced => shared/components/Elements/SwitchRow}/SwitchRow.types.ts (100%) create mode 100644 public/app/percona/shared/components/Elements/SwitchRow/index.ts diff --git a/public/app/percona/pmm-dump/components/ExportDataset/ExportDataset.tsx b/public/app/percona/pmm-dump/components/ExportDataset/ExportDataset.tsx index 462ae35109b8d..f5ff5b64c8d44 100644 --- a/public/app/percona/pmm-dump/components/ExportDataset/ExportDataset.tsx +++ b/public/app/percona/pmm-dump/components/ExportDataset/ExportDataset.tsx @@ -7,7 +7,7 @@ import { SelectableValue, DateTime, dateTime, AppEvents, PageLayoutType } from ' import { LinkButton, PageToolbar, DateTimePicker, useStyles2 } from '@grafana/ui'; import appEvents from 'app/core/app_events'; import { Page } from 'app/core/components/Page/Page'; -import { SwitchRow } from 'app/percona/settings/components/Advanced/SwitchRow'; +import { SwitchRow } from 'app/percona/shared/components/Elements/SwitchRow'; import { LoaderButton } from 'app/percona/shared/components/Elements/LoaderButton'; import { MultiSelectField } from 'app/percona/shared/components/Form/MultiSelectField'; import { PMM_EXPORT_DUMP_PAGE } from 'app/percona/shared/components/PerconaBootstrapper/PerconaNavigation'; diff --git a/public/app/percona/settings/Settings.messages.ts b/public/app/percona/settings/Settings.messages.ts deleted file mode 100644 index 9383e035b1365..0000000000000 --- a/public/app/percona/settings/Settings.messages.ts +++ /dev/null @@ -1,89 +0,0 @@ -export const Messages = { - advanced: { - action: 'Apply changes', - retentionLabel: 'Data retention', - retentionTooltip: 'This is the value for how long data will be stored.', - retentionUnits: 'days', - retentionLink: `https://per.co.na/data_retention`, - telemetryLabel: 'Telemetry', - telemetryLink: `https://per.co.na/telemetry`, - telemetryTooltip: 'Option to send usage data back to Percona to let us make our product better.', - telemetrySummaryTitle: 'We gather and send the following information to Percona:', - updatesLabel: 'Check for updates', - updatesLink: `https://per.co.na/updates`, - updatesTooltip: 'Option to check new versions and ability to update PMM from UI.', - advisorsLabel: 'Advisors', - sttRareIntervalLabel: 'Rare interval', - sttStandardIntervalLabel: 'Standard interval', - sttFrequentIntervalLabel: 'Frequent interval', - sttCheckIntervalsLabel: 'Execution Intervals', - sttCheckIntervalTooltip: 'Interval between check runs', - sttCheckIntervalUnit: 'hours', - advisorsLink: `https://per.co.na/advisors`, - advisorsTooltip: 'Enable Advisors and get updated checks from Percona.', - azureDiscoverLabel: 'Microsoft Azure monitoring', - azureDiscoverTooltip: 'Option to enable/disable Microsoft Azure DB instanced discovery and monitoring', - azureDiscoverLink: `https://per.co.na/azure_monitoring`, - accessControl: 'Access control', - accessControlTooltip: 'Option to enable/disable Access control.', - accessControlLink: 'https://per.co.na/roles_permissions', - publicAddressLabel: 'Public Address', - publicAddressTooltip: 'Public Address to this PMM server.', - publicAddressButton: 'Get from browser', - alertingLabel: 'Percona Alerting', - alertingTooltip: 'Option to enable/disable Percona Alerting features.', - alertingLink: `https://per.co.na/alerting`, - backupLabel: 'Backup Management', - backupTooltip: 'Option to enable/disable Backup Management features.', - backupLink: `https://per.co.na/backup_management`, - enableInternalPgQanLabel: 'QAN for PMM Server', - enableInternalPgQanTooltip: - "Displays queries from PMM Server's internal PostgreSQL database in Query Analytics (QAN). Enable to troubleshoot PMM Server's database performance alongside your monitored instances.", - enableInternalPgQanLink: 'https://per.co.na/qan-pmm-server', - technicalPreviewLegend: 'Technical preview features', - technicalPreviewDescription: - 'These are technical preview features, not recommended to be used in production environments. Read more\n' + - ' about feature status', - technicalPreviewLinkText: 'here', - }, - diagnostics: { - action: 'Download server diagnostics', - label: 'Diagnostics', - tooltip: - 'You can download server logs to make the problem detection simpler. Please include this file if you are submitting a bug report.', - }, - metrics: { - action: 'Apply changes', - label: 'Metrics resolution, sec', - link: `https://per.co.na/metrics_resolution`, - options: { - rare: 'Rare', - standard: 'Standard', - frequent: 'Frequent', - custom: 'Custom', - }, - intervals: { - low: 'Low', - medium: 'Medium', - high: 'High', - }, - tooltip: 'This setting defines how frequently the data will be collected.', - }, - ssh: { - action: 'Apply SSH key', - label: 'SSH key', - link: `https://per.co.na/ssh_key`, - tooltip: 'Public SSH key to let you login into the server using SSH.', - }, - service: { - success: 'Settings updated', - }, - tabs: { - metrics: 'Metrics Resolution', - advanced: 'Advanced Settings', - ssh: 'SSH Key', - communication: 'Communication', - }, - tooltipLinkText: 'Read more', - unauthorized: 'Insufficient access permissions.', -}; diff --git a/public/app/percona/settings/Settings.styles.ts b/public/app/percona/settings/Settings.styles.ts deleted file mode 100644 index 73b6cc4caf5e5..0000000000000 --- a/public/app/percona/settings/Settings.styles.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { css } from '@emotion/css'; - -import { GrafanaTheme2 } from '@grafana/data'; - -export const getSettingsStyles = ({ v1: { spacing }, breakpoints }: GrafanaTheme2) => { - const mq = `@media (max-width: ${breakpoints.up('md')})`; - - return { - pageContent: css` - ${breakpoints.up('md')} { - margin-right: auto !important; - width: 45% !important; - } - @media (min-width: 2000px) { - width: 30% !important; - } - @media (min-width: 3000px) { - width: 20% !important; - } - @media (min-width: 5000px) { - width: 12% !important; - } - `, - wrapper: css` - ${mq} { - width: 100%; - } - `, - labelWrapper: css` - display: flex; - flex-wrap: wrap; - svg { - margin-left: ${spacing.xs}; - } - `, - actionButton: css` - margin-top: ${spacing.sm}; - width: fit-content; - i { - margin-right: ${spacing.sm}; - } - span { - display: flex; - } - `, - tabs: css` - background: transparent; - `, - }; -}; diff --git a/public/app/percona/settings/components/Advanced/Advanced.constants.ts b/public/app/percona/settings/components/Advanced/Advanced.constants.ts deleted file mode 100644 index f7fc1d92dac00..0000000000000 --- a/public/app/percona/settings/components/Advanced/Advanced.constants.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { Messages } from 'app/percona/settings/Settings.messages'; -import { AdvisorRunIntervals } from 'app/percona/settings/Settings.types'; - -import { AdvancedFormProps } from './Advanced.types'; - -export const SECONDS = 60; -export const MINUTES = 60; -export const HOURS = 24; -export const SECONDS_IN_DAY = SECONDS * MINUTES * HOURS; -export const MINUTES_IN_HOUR = MINUTES * HOURS; -export const MIN_DAYS = 1; -export const MAX_DAYS = 3650; -export const MIN_STT_CHECK_INTERVAL = 0.1; -export const STT_CHECK_INTERVAL_STEP = 0.1; - -const { - advanced: { sttRareIntervalLabel, sttStandardIntervalLabel, sttFrequentIntervalLabel }, -} = Messages; - -export const STT_CHECK_INTERVALS = [ - { - label: sttRareIntervalLabel, - name: AdvisorRunIntervals.rareInterval, - }, - { - label: sttStandardIntervalLabel, - name: AdvisorRunIntervals.standardInterval, - }, - { - label: sttFrequentIntervalLabel, - name: AdvisorRunIntervals.frequentInterval, - }, -]; - -export const TECHNICAL_PREVIEW_DOC_URL = 'https://per.co.na/pmm-feature-status'; - -// all feature flags -export const FEATURE_KEYS: Array = ['alerting', 'backup', 'stt', 'azureDiscover']; diff --git a/public/app/percona/settings/components/Advanced/Advanced.styles.ts b/public/app/percona/settings/components/Advanced/Advanced.styles.ts deleted file mode 100644 index f02c1c3f5b843..0000000000000 --- a/public/app/percona/settings/components/Advanced/Advanced.styles.ts +++ /dev/null @@ -1,124 +0,0 @@ -import { css } from '@emotion/css'; - -import { GrafanaTheme2 } from '@grafana/data'; - -export const getStyles = ({ v1: { breakpoints, spacing, typography, border, colors } }: GrafanaTheme2) => { - const mq = `@media (max-width: ${breakpoints.md})`; - - return { - advancedWrapper: css` - form { - width: 100%; - } - `, - advancedRow: css` - display: flex; - align-items: baseline; - padding-bottom: ${spacing.md}; - flex-wrap: wrap; - `, - advancedCol: css` - align-items: center; - display: flex; - width: 230px; - `, - advancedChildCol: css` - width: 150px; - margin-left: 30px; - `, - inputWrapper: css` - align-items: center; - display: flex; - input { - width: 60px; - } - div { - margin: 0; - div[class*='-error'] { - position: absolute; - } - } - `, - unitsLabel: css` - font-size: ${typography.size.sm}; - margin-left: ${spacing.sm}; - `, - publicAddressLabelWrapper: css` - align-items: start; - margin-top: ${spacing.sm}; - `, - publicAddressWrapper: css` - display: flex; - flex-wrap: wrap; - div { - margin-bottom: 0 !important; - } - ${mq} { - flex-direction: column; - } - `, - publicAddressInput: css` - min-width: 213px; - ${mq} { - width: 100px; - } - `, - publicAddressButton: css` - margin-left: ${spacing.md}; - margin-top: ${spacing.xxs}; - svg { - margin-right: ${spacing.sm}; - } - ${mq} { - margin-left: 0; - } - `, - sttCheckIntervalsLabel: css` - margin-top: ${spacing.sm}; - margin-bottom: ${spacing.sm}; - `, - technicalPreview: css` - border: ${border.width.sm} solid ${colors.pageHeaderBorder}; - padding: ${spacing.md}; - border-radius: ${border.radius.sm}; - - ${mq} { - width: 100%; - } - - legend { - font-size: 14px; - width: auto; - padding: 0 ${spacing.sm}; - } - `, - infoBox: css` - display: flex; - align-items: center; - border: ${border.width.sm} solid ${colors.pageHeaderBorder}; - border-radius: ${border.radius.sm}; - color: ${colors.textWeak}; - padding: ${spacing.sm}; - margin-bottom: ${spacing.lg}; - - p { - margin: 0; - } - - a { - color: ${colors.linkExternal}; - } - `, - infoBoxIcon: css` - margin: ${spacing.sm}; - fill: ${colors.linkExternal}; - `, - telemetryTooltip: css` - overflow: auto; - max-height: 80vh; - `, - telemetryListTooltip: css` - padding-left: ${spacing.sm}; - `, - }; -}; diff --git a/public/app/percona/settings/components/Advanced/Advanced.test.tsx b/public/app/percona/settings/components/Advanced/Advanced.test.tsx deleted file mode 100644 index 0a95152f23512..0000000000000 --- a/public/app/percona/settings/components/Advanced/Advanced.test.tsx +++ /dev/null @@ -1,337 +0,0 @@ -import { render, screen, fireEvent, waitForElementToBeRemoved, waitFor } from '@testing-library/react'; -import { Provider } from 'react-redux'; - -import * as reducers from 'app/percona/shared/core/reducers'; -import { wrapWithGrafanaContextMock } from 'app/percona/shared/helpers/testUtils'; -import { configureStore } from 'app/store/configureStore'; -import { StoreState } from 'app/types'; - -import { Advanced } from './Advanced'; - -jest.mock('app/percona/settings/Settings.service'); - -const updateSettingsSpy = jest.spyOn(reducers, 'updateSettingsAction'); - -const setup = (pmmMonitoringEnabled = true) => - render( - - {wrapWithGrafanaContextMock()} - - ); - -describe('Advanced::', () => { - beforeEach(() => { - updateSettingsSpy.mockClear(); - }); - - it('renders correctly with props', async () => { - render( - - {wrapWithGrafanaContextMock()} - - ); - - await waitFor(() => expect(screen.getByTestId('retention-number-input')).toHaveValue(30)); - await waitFor(() => expect(screen.getByTestId('publicAddress-text-input')).toHaveValue('localhost')); - }); - - it('calls apply changes', async () => { - render( - - {wrapWithGrafanaContextMock()} - - ); - - fireEvent.change(screen.getByTestId('retention-number-input'), { target: { value: 70 } }); - fireEvent.submit(screen.getByTestId('advanced-button')); - - await waitForElementToBeRemoved(() => screen.getByTestId('Spinner')); - - expect(updateSettingsSpy).toHaveBeenCalled(); - }); - - it('sets correct URL from browser', async () => { - const location = { - ...window.location, - host: 'pmmtest.percona.com', - }; - - Object.defineProperty(window, 'location', { - writable: true, - value: location, - }); - - render( - - {wrapWithGrafanaContextMock()} - - ); - - fireEvent.click(screen.getByTestId('public-address-button')); - - await waitFor(() => expect(screen.getByTestId('publicAddress-text-input')).toHaveValue('pmmtest.percona.com')); - }); - - it('does not include STT check intervals in the change request if STT checks are disabled', async () => { - render( - - {wrapWithGrafanaContextMock()} - - ); - - fireEvent.change(screen.getByTestId('retention-number-input'), { target: { value: 70 } }); - fireEvent.submit(screen.getByTestId('advanced-button')); - - await waitForElementToBeRemoved(() => screen.getByTestId('Spinner')); - - expect(updateSettingsSpy).toHaveBeenLastCalledWith( - expect.objectContaining({ - body: expect.objectContaining({ - advisor_run_intervals: undefined, - }), - }) - ); - }); - - it('Includes STT check intervals in the change request if STT checks are enabled', async () => { - render( - - {wrapWithGrafanaContextMock()} - - ); - - fireEvent.change(screen.getByTestId('retention-number-input'), { target: { value: 70 } }); - fireEvent.submit(screen.getByTestId('advanced-button')); - await waitForElementToBeRemoved(() => screen.getByTestId('Spinner')); - - // expect(spy.calls.mostRecent().args[0].body.stt_check_intervals).toBeDefined(); - expect(updateSettingsSpy).toHaveBeenLastCalledWith( - expect.objectContaining({ - body: expect.objectContaining({ - advisor_run_intervals: { - frequent_interval: '14400s', - rare_interval: '280800s', - standard_interval: '86400s', - }, - }), - }) - ); - }); - - it('updates internal monitoring when pmm server monitoring is turned on', async () => { - const { container } = setup(); - - const monitoringSwitch = container.querySelector( - '[data-testid="enable-internal-pg-qan"] [name="enableInternalPgQan"]' - ); - - expect(monitoringSwitch).toBeInTheDocument(); - - fireEvent.click(monitoringSwitch!); - - fireEvent.submit(screen.getByTestId('advanced-button')); - - await waitForElementToBeRemoved(() => screen.getByTestId('Spinner')); - - expect(updateSettingsSpy).toHaveBeenCalledWith( - expect.objectContaining({ - body: expect.objectContaining({ - enable_internal_pg_qan: false, - }), - }) - ); - }); - - it('updates internal monitoring when pmm server monitoring is turned off', async () => { - const { container } = setup(false); - - const monitoringSwitch = container.querySelector( - '[data-testid="enable-internal-pg-qan"] [name="enableInternalPgQan"]' - ); - - expect(monitoringSwitch).toBeInTheDocument(); - - fireEvent.click(monitoringSwitch!); - - fireEvent.submit(screen.getByTestId('advanced-button')); - - await waitForElementToBeRemoved(() => screen.getByTestId('Spinner')); - - expect(updateSettingsSpy).toHaveBeenCalledWith( - expect.objectContaining({ - body: expect.objectContaining({ - enable_internal_pg_qan: true, - }), - }) - ); - }); - - it("doesn't update internal monitoring when pmm server monitoring doesn't change", async () => { - setup(); - - fireEvent.submit(screen.getByTestId('advanced-button')); - - await waitForElementToBeRemoved(() => screen.getByTestId('Spinner')); - - expect(updateSettingsSpy).toHaveBeenCalledWith( - expect.objectContaining({ - body: expect.objectContaining({ - enable_internal_pg_qan: true, - }), - }) - ); - }); -}); diff --git a/public/app/percona/settings/components/Advanced/Advanced.tsx b/public/app/percona/settings/components/Advanced/Advanced.tsx deleted file mode 100644 index 7f55594b22076..0000000000000 --- a/public/app/percona/settings/components/Advanced/Advanced.tsx +++ /dev/null @@ -1,395 +0,0 @@ -import { cx } from '@emotion/css'; -import { FC, useState } from 'react'; -import { Field, withTypes } from 'react-final-form'; - -import { Button, Icon, Spinner, useStyles2 } from '@grafana/ui'; -import { Messages } from 'app/percona/settings/Settings.messages'; -import { getSettingsStyles } from 'app/percona/settings/Settings.styles'; -import { FeatureLoader } from 'app/percona/shared/components/Elements/FeatureLoader'; -import { LinkTooltip } from 'app/percona/shared/components/Elements/LinkTooltip/LinkTooltip'; -import { NumberInputField } from 'app/percona/shared/components/Form/NumberInput'; -import { TextInputField } from 'app/percona/shared/components/Form/TextInput'; -import { TabbedPage, TabbedPageContents } from 'app/percona/shared/components/TabbedPage'; -import { useCancelToken } from 'app/percona/shared/components/hooks/cancelToken.hook'; -import { updateSettingsAction } from 'app/percona/shared/core/reducers'; -import { getPerconaSettings } from 'app/percona/shared/core/selectors'; -import validators from 'app/percona/shared/helpers/validators'; -import { useAppDispatch } from 'app/store/store'; -import { useSelector } from 'app/types'; - -import { SET_SETTINGS_CANCEL_TOKEN } from '../../Settings.constants'; -import { AdvancedChangePayload } from '../../Settings.types'; - -import { - MAX_DAYS, - MIN_DAYS, - MIN_STT_CHECK_INTERVAL, - SECONDS_IN_DAY, - STT_CHECK_INTERVALS, - STT_CHECK_INTERVAL_STEP, - TECHNICAL_PREVIEW_DOC_URL, -} from './Advanced.constants'; -import { getStyles } from './Advanced.styles'; -import { AdvancedFormProps } from './Advanced.types'; -import { convertCheckIntervalsToHours, convertHoursStringToSeconds, convertSecondsToDays } from './Advanced.utils'; -import { SwitchRow } from './SwitchRow'; - -const { - tooltipLinkText, - advanced: { - action, - retentionLabel, - retentionTooltip, - retentionUnits, - telemetryLabel, - telemetryLink, - telemetryTooltip, - telemetrySummaryTitle, - updatesLabel, - updatesLink, - updatesTooltip, - advisorsLabel, - advisorsLink, - advisorsTooltip, - publicAddressLabel, - publicAddressTooltip, - publicAddressButton, - accessControl, - accessControlTooltip, - accessControlLink, - alertingLabel, - alertingTooltip, - alertingLink, - azureDiscoverLabel, - azureDiscoverTooltip, - azureDiscoverLink, - technicalPreviewLegend, - technicalPreviewDescription, - technicalPreviewLinkText, - backupLabel, - backupLink, - backupTooltip, - enableInternalPgQanLabel, - enableInternalPgQanLink, - enableInternalPgQanTooltip, - sttCheckIntervalsLabel, - sttCheckIntervalTooltip, - sttCheckIntervalUnit, - }, -} = Messages; - -export const Advanced: FC = () => { - const styles = useStyles2(getStyles); - const [generateToken] = useCancelToken(); - const { result: settings } = useSelector(getPerconaSettings); - const dispatch = useAppDispatch(); - const { - advisorRunIntervals: sttCheckIntervals, - dataRetention, - telemetryEnabled, - updatesEnabled, - backupEnabled, - advisorEnabled: sttEnabled, - azureDiscoverEnabled, - publicAddress, - alertingEnabled, - telemetrySummaries, - enableAccessControl, - enableInternalPgQan, - } = settings!; - const settingsStyles = useStyles2(getSettingsStyles); - const { rareInterval, standardInterval, frequentInterval } = convertCheckIntervalsToHours(sttCheckIntervals); - - const initialValues: AdvancedFormProps = { - retention: convertSecondsToDays(dataRetention), - telemetry: telemetryEnabled, - updates: updatesEnabled, - backup: backupEnabled, - stt: sttEnabled, - azureDiscover: azureDiscoverEnabled, - publicAddress, - alerting: alertingEnabled, - rareInterval, - standardInterval, - frequentInterval, - telemetrySummaries, - accessControl: enableAccessControl, - enableInternalPgQan, - }; - const [loading, setLoading] = useState(false); - - const applyChanges = async (values: AdvancedFormProps) => { - const { - retention, - telemetry, - stt, - publicAddress, - alerting, - backup, - azureDiscover, - rareInterval, - standardInterval, - frequentInterval, - updates, - accessControl, - enableInternalPgQan, - } = values; - const sttCheckIntervals = { - rare_interval: `${convertHoursStringToSeconds(rareInterval)}s`, - standard_interval: `${convertHoursStringToSeconds(standardInterval)}s`, - frequent_interval: `${convertHoursStringToSeconds(frequentInterval)}s`, - }; - - const body: AdvancedChangePayload = { - data_retention: `${+retention * SECONDS_IN_DAY}s`, - enable_telemetry: telemetry, - enable_advisor: stt, - enable_azurediscover: azureDiscover, - pmm_public_address: publicAddress || '', - enable_alerting: alerting, - advisor_run_intervals: !!stt ? sttCheckIntervals : undefined, - enable_backup_management: backup, - enable_updates: updates, - enable_access_control: accessControl, - enable_internal_pg_qan: enableInternalPgQan, - }; - - setLoading(true); - await dispatch( - updateSettingsAction({ - body, - token: generateToken(SET_SETTINGS_CANCEL_TOKEN), - }) - ); - setLoading(false); - }; - const { Form } = withTypes(); - - return ( - - - -
-
{ - if (!state?.lastFormState?.values['publicAddress']) { - changeValue(state, 'publicAddress', () => publicAddressValue); - } - }, - }} - render={({ form: { change, mutators }, values, handleSubmit, valid, pristine }) => ( - -
-
-
- {retentionLabel} - -
-
-
- -
- {retentionUnits} -
- - } - tooltipLinkText={tooltipLinkText} - link={telemetryLink} - dataTestId="advanced-telemetry" - component={SwitchRow} - /> - - - - -
-
-
- {publicAddressLabel} - -
-
-
- - -
-
- -
-
-
- {sttCheckIntervalsLabel} - -
-
-
- {STT_CHECK_INTERVALS.map(({ label, name }) => ( -
-
-
- {label} -
-
-
- -
- {sttCheckIntervalUnit} -
- ))} -
- {technicalPreviewLegend} -
- -

- {technicalPreviewDescription}{' '} - - {technicalPreviewLinkText} - -

-
- - -
- - - )} - /> -
-
-
-
- ); -}; - -interface TelemetryTooltipProps { - telemetryTooltip: string; - telemetrySummaryTitle: string; - telemetrySummaries: string[]; -} - -const TelemetryTooltip: FC = ({ - telemetryTooltip, - telemetrySummaryTitle, - telemetrySummaries, -}) => { - const styles = useStyles2(getStyles); - - return ( -
-

{telemetryTooltip}

-

{telemetrySummaryTitle}

-
    - {telemetrySummaries.map((summary) => ( -
  • {summary}
  • - ))} -
-
- ); -}; - -export default Advanced; diff --git a/public/app/percona/settings/components/Advanced/Advanced.types.ts b/public/app/percona/settings/components/Advanced/Advanced.types.ts deleted file mode 100644 index 5df711ea6e25f..0000000000000 --- a/public/app/percona/settings/components/Advanced/Advanced.types.ts +++ /dev/null @@ -1,16 +0,0 @@ -export interface AdvancedFormProps { - retention: number | string; - telemetry: boolean; - updates: boolean; - backup: boolean; - stt: boolean; - publicAddress?: string; - alerting?: boolean; - azureDiscover?: boolean; - rareInterval: string; - standardInterval: string; - frequentInterval: string; - telemetrySummaries: string[]; - accessControl?: boolean; - enableInternalPgQan?: boolean; -} diff --git a/public/app/percona/settings/components/Advanced/Advanced.utils.ts b/public/app/percona/settings/components/Advanced/Advanced.utils.ts deleted file mode 100644 index e52d923e83f25..0000000000000 --- a/public/app/percona/settings/components/Advanced/Advanced.utils.ts +++ /dev/null @@ -1,38 +0,0 @@ -import moment from 'moment/moment'; - -import { AdvisorRunIntervalsSettings } from 'app/percona/settings/Settings.types'; - -import { HOURS, MINUTES_IN_HOUR, SECONDS_IN_DAY } from './Advanced.constants'; - -export const convertSecondsToDays = (dataRetention: string) => { - const [count, units] = [+dataRetention.slice(0, -1), dataRetention.slice(-1)]; - - switch (units) { - case 'h': - return count / HOURS; - case 'm': - return count / MINUTES_IN_HOUR; - case 's': - return count / SECONDS_IN_DAY; - default: - return ''; - } -}; - -export const convertSecondsStringToHour = (seconds: string) => - moment.duration(parseInt(seconds, 10), 'seconds').asHours(); - -export const convertHoursStringToSeconds = (hours: string) => moment.duration(parseFloat(hours), 'hours').asSeconds(); - -export const convertCheckIntervalsToHours = (sttCheckIntervals: AdvisorRunIntervalsSettings) => { - const { - rareInterval: rawRareInterval, - standardInterval: rawStandardInterval, - frequentInterval: rawFrequentInterval, - } = sttCheckIntervals; - return { - rareInterval: `${convertSecondsStringToHour(rawRareInterval)}`, - standardInterval: `${convertSecondsStringToHour(rawStandardInterval)}`, - frequentInterval: `${convertSecondsStringToHour(rawFrequentInterval)}`, - }; -}; diff --git a/public/app/percona/settings/components/Advanced/__mocks__/stubs.ts b/public/app/percona/settings/components/Advanced/__mocks__/stubs.ts deleted file mode 100644 index 040028102d79c..0000000000000 --- a/public/app/percona/settings/components/Advanced/__mocks__/stubs.ts +++ /dev/null @@ -1,5 +0,0 @@ -export const sttCheckIntervalsStub = { - rareInterval: '280800s', - standardInterval: '86400s', - frequentInterval: '14400s', -}; diff --git a/public/app/percona/settings/components/Communication/Communication.messages.ts b/public/app/percona/settings/components/Communication/Communication.messages.ts deleted file mode 100644 index fe7089cb5bd5d..0000000000000 --- a/public/app/percona/settings/components/Communication/Communication.messages.ts +++ /dev/null @@ -1,69 +0,0 @@ -// page is deprecated, so shortener is not needed -const COMMUNICATION_LINK = - 'https://docs.percona.com/percona-monitoring-and-management/how-to/integrate-platform.html#communication'; - -export const Messages = { - fields: { - type: { - label: 'Auth Type', - tooltipText: 'Authentication type', - tooltipLinkText: 'Read more', - tooltipLink: COMMUNICATION_LINK, - }, - from: { - label: 'From', - tooltipText: 'The sender address', - tooltipLinkText: 'Read more', - tooltipLink: COMMUNICATION_LINK, - }, - smarthost: { - label: 'Server Address', - tooltipText: - 'The default SMTP smarthost used for sending emails, including port number (e.g. smtp.example.org:587)', - tooltipLinkText: 'Read more', - tooltipLink: COMMUNICATION_LINK, - }, - hello: { - label: 'Hello', - tooltipText: 'The hostname to identify the SMTP server', - tooltipLinkText: 'Read more', - tooltipLink: COMMUNICATION_LINK, - }, - username: { - label: 'Username', - tooltipText: 'SMTP authentication information', - tooltipLinkText: 'Read more', - tooltipLink: COMMUNICATION_LINK, - }, - password: { - label: 'Password', - tooltipText: 'SMTP authentication information', - tooltipLinkText: 'Read more', - tooltipLink: COMMUNICATION_LINK, - }, - identity: { - label: 'Identity', - tooltipText: 'SMTP authentication information', - tooltipLinkText: 'Read more', - tooltipLink: COMMUNICATION_LINK, - }, - slackURL: { - label: 'URL', - tooltipText: 'Slack incoming webhook URL', - tooltipLinkText: 'Read more', - tooltipLink: COMMUNICATION_LINK, - }, - }, - actionButton: 'Apply changes', - emailSent: 'Email sent', - tabs: { - slack: { - key: 'slack', - label: 'Slack', - }, - email: { - key: 'email', - label: 'Email', - }, - }, -}; diff --git a/public/app/percona/settings/components/Communication/Communication.service.ts b/public/app/percona/settings/components/Communication/Communication.service.ts deleted file mode 100644 index f21a239f4b069..0000000000000 --- a/public/app/percona/settings/components/Communication/Communication.service.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { api } from 'app/percona/shared/helpers/api'; - -import { EmailPayload } from '../../Settings.types'; - -export const CommunicationService = { - async testEmailSettings(settings: EmailPayload, email: string): Promise { - return api.post('/v1/Settings/TestEmailAlertingSettings', { ...settings, email_to: email }); - }, -}; diff --git a/public/app/percona/settings/components/Communication/Communication.styles.ts b/public/app/percona/settings/components/Communication/Communication.styles.ts deleted file mode 100644 index 9cfc9c96f1079..0000000000000 --- a/public/app/percona/settings/components/Communication/Communication.styles.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { css } from '@emotion/css'; - -import { GrafanaTheme } from '@grafana/data'; -import { stylesFactory } from '@grafana/ui'; - -export const getStyles = stylesFactory(({ spacing }: GrafanaTheme) => ({ - advancedWrapper: css` - form { - width: 100%; - } - `, - advancedRow: css` - display: flex; - padding-bottom: ${spacing.md}; - `, - advancedCol: css` - align-items: center; - display: flex; - width: 180px; - `, -})); diff --git a/public/app/percona/settings/components/Communication/Communication.tsx b/public/app/percona/settings/components/Communication/Communication.tsx deleted file mode 100644 index abdb0792f6861..0000000000000 --- a/public/app/percona/settings/components/Communication/Communication.tsx +++ /dev/null @@ -1,101 +0,0 @@ -import { cx } from '@emotion/css'; -import { FC, useCallback, useMemo, useState } from 'react'; - -import { Alert, Tab, TabContent, TabsBar, useStyles2 } from '@grafana/ui'; -import { Page } from 'app/core/components/Page/Page'; -import { getSettingsStyles } from 'app/percona/settings/Settings.styles'; -import { FeatureLoader } from 'app/percona/shared/components/Elements/FeatureLoader'; -import { useCancelToken } from 'app/percona/shared/components/hooks/cancelToken.hook'; -import { usePerconaNavModel } from 'app/percona/shared/components/hooks/perconaNavModel'; -import { updateSettingsAction } from 'app/percona/shared/core/reducers'; -import { getPerconaSettings } from 'app/percona/shared/core/selectors'; -import { useAppDispatch } from 'app/store/store'; -import { useSelector } from 'app/types'; - -import { SET_SETTINGS_CANCEL_TOKEN } from '../../Settings.constants'; -import { EmailPayload, SettingsAPIChangePayload } from '../../Settings.types'; - -import { Messages } from './Communication.messages'; -import { CommunicationService } from './Communication.service'; -import { Email } from './Email/Email'; -import { Slack } from './Slack/Slack'; - -export const Communication: FC = () => { - const settingsStyles = useStyles2(getSettingsStyles); - const [activeTab, setActiveTab] = useState(Messages.tabs.email.key); - const dispatch = useAppDispatch(); - const [generateToken] = useCancelToken(); - const navModel = usePerconaNavModel('settings-communication'); - const { result: settings } = useSelector(getPerconaSettings); - const { alertingSettings } = settings!; - - const testEmailSetting = async (settings: EmailPayload, email: string): Promise => - CommunicationService.testEmailSettings(settings, email); - - const updateSettings = useCallback( - async (body: Partial) => { - await dispatch( - updateSettingsAction({ - body, - token: generateToken(SET_SETTINGS_CANCEL_TOKEN), - }) - ); - }, - [dispatch, generateToken] - ); - - const tabs = useMemo( - () => [ - { - label: Messages.tabs.email.label, - key: Messages.tabs.email.key, - active: activeTab === Messages.tabs.email.key, - component: ( - - ), - }, - { - label: Messages.tabs.slack.label, - key: Messages.tabs.slack.key, - active: activeTab === Messages.tabs.slack.key, - component: , - }, - ], - [activeTab, updateSettings, alertingSettings.email, alertingSettings.slack] - ); - - return ( - - - -
- - This page is deprecated for now. Please resort to Grafana's SMTP settings via .ini file and use - Contact Points to setup Slack notifications. - - - {tabs.map((tab, index) => ( - setActiveTab(tab.key)} - /> - ))} - - - {tabs.map((tab) => tab.key === activeTab && tab.component)} - -
-
-
-
- ); -}; - -export default Communication; diff --git a/public/app/percona/settings/components/Communication/Email/Email.constants.ts b/public/app/percona/settings/components/Communication/Email/Email.constants.ts deleted file mode 100644 index f6f5079167552..0000000000000 --- a/public/app/percona/settings/components/Communication/Email/Email.constants.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { SelectableValue } from '@grafana/data'; - -import { EmailAuthType } from '../../../Settings.types'; - -export const emailOptions: Array> = [ - { - value: EmailAuthType.NONE, - label: 'None', - }, - { - value: EmailAuthType.PLAIN, - label: 'Plain', - }, - { - value: EmailAuthType.LOGIN, - label: 'Login', - }, - { - value: EmailAuthType.CRAM, - label: 'CRAM-MD5', - }, -]; diff --git a/public/app/percona/settings/components/Communication/Email/Email.styles.ts b/public/app/percona/settings/components/Communication/Email/Email.styles.ts deleted file mode 100644 index 14a709a42b17a..0000000000000 --- a/public/app/percona/settings/components/Communication/Email/Email.styles.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { css } from '@emotion/css'; - -import { GrafanaTheme2 } from '@grafana/data'; - -export const getStyles = ({ v1: { spacing } }: GrafanaTheme2) => ({ - emailForm: css` - margin-top: ${spacing.md}; - `, - authRadioGroup: css` - & input[type='radio'] + label { - white-space: nowrap; - } - `, -}); diff --git a/public/app/percona/settings/components/Communication/Email/Email.test.tsx b/public/app/percona/settings/components/Communication/Email/Email.test.tsx deleted file mode 100644 index d16c4ca223399..0000000000000 --- a/public/app/percona/settings/components/Communication/Email/Email.test.tsx +++ /dev/null @@ -1,81 +0,0 @@ -import { render, screen } from '@testing-library/react'; - -import { Email } from './Email'; - -describe('Email::', () => { - it('Renders with props', () => { - render( - Promise.resolve()} - testSettings={() => Promise.resolve()} - /> - ); - - expect(screen.getByTestId('username-text-input')).toHaveProperty('value', 'test'); - }); - - it('Disables apply changes on initial values', () => { - render( - Promise.resolve()} - testSettings={() => Promise.resolve()} - /> - ); - const buttons = screen.getAllByRole('button'); - - expect(buttons[0]).toBeDisabled(); - expect(buttons[1]).toBeDisabled(); - }); - - it('Disables username and password when NONE is selected', () => { - render( - Promise.resolve()} - testSettings={() => Promise.resolve()} - /> - ); - - expect(screen.getByTestId('username-text-input')).toBeDisabled(); - expect(screen.getByTestId('password-password-input')).toBeDisabled(); - }); - - it('Enabled username and password when NONE is not selected', () => { - render( - Promise.resolve()} - testSettings={() => Promise.resolve()} - /> - ); - - expect(screen.getByTestId('username-text-input')).not.toBeDisabled(); - expect(screen.getByTestId('password-password-input')).not.toBeDisabled(); - }); -}); diff --git a/public/app/percona/settings/components/Communication/Email/Email.tsx b/public/app/percona/settings/components/Communication/Email/Email.tsx deleted file mode 100644 index 046ce2b14f20c..0000000000000 --- a/public/app/percona/settings/components/Communication/Email/Email.tsx +++ /dev/null @@ -1,182 +0,0 @@ -import { FormApi } from 'final-form'; -import { FC, useRef, useState } from 'react'; -import { createPortal } from 'react-dom'; -import { withTypes } from 'react-final-form'; - -import { AppEvents } from '@grafana/data'; -import { Button, Spinner, useStyles2 } from '@grafana/ui'; -import { appEvents } from 'app/core/app_events'; -import { EmailAuthType } from 'app/percona/settings/Settings.types'; -import { CheckboxField } from 'app/percona/shared/components/Elements/Checkbox'; -import { LinkTooltip } from 'app/percona/shared/components/Elements/LinkTooltip/LinkTooltip'; -import { PasswordInputField } from 'app/percona/shared/components/Form/PasswordInput'; -import { RadioButtonGroupField } from 'app/percona/shared/components/Form/RadioButtonGroup'; -import { TextInputField } from 'app/percona/shared/components/Form/TextInput'; -import { logger } from 'app/percona/shared/helpers/logger'; -import { validators } from 'app/percona/shared/helpers/validatorsForm'; - -import { getSettingsStyles } from '../../../Settings.styles'; -import { Messages } from '../Communication.messages'; - -import { emailOptions } from './Email.constants'; -import { getStyles } from './Email.styles'; -import { EmailProps, FormEmailSettings } from './Email.types'; -import { cleanupFormValues, getInitialValues } from './Email.utils'; -import { TestEmailSettings } from './TestEmailSettings/TestEmailSettings'; - -export const Email: FC = ({ updateSettings, settings, testSettings }) => { - const testRef = useRef(null); - const applyRef = useRef(null); - const testEmailRef = useRef(settings.test_email); - const settingsStyles = useStyles2(getSettingsStyles); - const styles = useStyles2(getStyles); - const [loading, setLoading] = useState(false); - - const applyChanges = async (values: FormEmailSettings) => { - await updateSettings( - { - email_alerting_settings: { ...cleanupFormValues(values), test_email: testEmailRef.current }, - }, - setLoading - ); - }; - - const resetUsernameAndPasswordState = (form: FormApi) => { - form.resetFieldState('username'); - form.resetFieldState('password'); - }; - - const handleTestClick = async (values: FormEmailSettings, email: string) => { - try { - await testSettings({ email_alerting_settings: cleanupFormValues(values) }, email); - appEvents.emit(AppEvents.alertSuccess, [Messages.emailSent]); - } catch (e) { - logger.error(e); - } - }; - - const initialValues = getInitialValues(settings); - const { Form } = withTypes(); - - return ( - <> -
( - -
- {Messages.fields.smarthost.label} - -
- - -
- {Messages.fields.hello.label} - -
- - -
- {Messages.fields.from.label} - -
- - -
- {Messages.fields.type.label} - -
- resetUsernameAndPasswordState(form), - }} - className={styles.authRadioGroup} - options={emailOptions} - name="authType" - fullWidth - /> - -
- {Messages.fields.username.label} - -
- - -
- {Messages.fields.password.label} - -
- - - - {testRef.current && - createPortal( - (testEmailRef.current = email)} - onTest={(email) => handleTestClick(values, email)} - initialValue={settings.test_email} - />, - testRef.current - )} - - {applyRef.current && - createPortal( - , - applyRef.current - )} - - )} - /> -
(testRef.current = e)}>
-
(applyRef.current = e)}>
- - ); -}; diff --git a/public/app/percona/settings/components/Communication/Email/Email.types.ts b/public/app/percona/settings/components/Communication/Email/Email.types.ts deleted file mode 100644 index ced67bafcbf1a..0000000000000 --- a/public/app/percona/settings/components/Communication/Email/Email.types.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { LoadingCallback } from '../../../Settings.service'; -import { EmailAuthType, EmailPayload, EmailSettings } from '../../../Settings.types'; - -export interface EmailProps { - settings: EmailSettings; - updateSettings: (body: EmailPayload, callback: LoadingCallback) => Promise; - testSettings: (body: EmailPayload, testEmail: string) => Promise; -} - -export interface FormEmailSettings extends Omit { - authType: EmailAuthType; - requireTls: boolean; -} diff --git a/public/app/percona/settings/components/Communication/Email/Email.utils.test.tsx b/public/app/percona/settings/components/Communication/Email/Email.utils.test.tsx deleted file mode 100644 index 3b88e45271d6d..0000000000000 --- a/public/app/percona/settings/components/Communication/Email/Email.utils.test.tsx +++ /dev/null @@ -1,180 +0,0 @@ -import { EmailAuthType } from 'app/percona/settings/Settings.types'; - -import { FormEmailSettings } from './Email.types'; -import { isEmailFieldNeeded, getAuthTypeFromFields, getInitialValues, cleanupFormValues } from './Email.utils'; - -describe('Communication::Email::utils', () => { - describe('isEmailFieldNeeded', () => { - it('should return true for common fields', () => { - expect(isEmailFieldNeeded('smarthost', EmailAuthType.NONE)).toBe(true); - expect(isEmailFieldNeeded('hello', EmailAuthType.LOGIN)).toBe(true); - expect(isEmailFieldNeeded('from', EmailAuthType.PLAIN)).toBe(true); - }); - - it('should return false for unneeded fields', () => { - expect(isEmailFieldNeeded('password', EmailAuthType.NONE)).toBe(false); - expect(isEmailFieldNeeded('identity', EmailAuthType.LOGIN)).toBe(false); - expect(isEmailFieldNeeded('secret', EmailAuthType.LOGIN)).toBe(false); - }); - - it('should return true for needed fields', () => { - expect(isEmailFieldNeeded('password', EmailAuthType.LOGIN)).toBe(true); - expect(isEmailFieldNeeded('password', EmailAuthType.PLAIN)).toBe(true); - expect(isEmailFieldNeeded('identity', EmailAuthType.PLAIN)).toBe(true); - expect(isEmailFieldNeeded('secret', EmailAuthType.CRAM)).toBe(true); - }); - }); - - describe('getAuthTypeFromFields', () => { - it('should return PLAIN when there is identity', () => { - expect( - getAuthTypeFromFields({ - identity: 'ident_sample', - from: 'from@mail.com', - smarthost: 'host.com', - hello: 'hello', - require_tls: false, - }) - ).toBe(EmailAuthType.PLAIN); - }); - - it('should return CRAM-MD5 when there is secret', () => { - expect( - getAuthTypeFromFields({ - secret: 'secret', - from: 'from@mail.com', - smarthost: 'host.com', - hello: 'hello', - require_tls: false, - }) - ).toBe(EmailAuthType.CRAM); - }); - - it('should return LOGIN when there is username but no identity', () => { - expect( - getAuthTypeFromFields({ - username: 'username', - from: 'from@mail.com', - smarthost: 'host.com', - hello: 'hello', - require_tls: false, - }) - ).toBe(EmailAuthType.LOGIN); - }); - - it('should return NONE when only common fields are present', () => { - expect( - getAuthTypeFromFields({ - from: 'from@mail.com', - smarthost: 'host.com', - hello: 'hello', - require_tls: false, - }) - ).toBe(EmailAuthType.NONE); - }); - }); - - describe('getInitialValues', () => { - it('should return authType and remove identity', () => { - expect( - getInitialValues({ - from: 'from@mail.com', - smarthost: 'host.com', - hello: 'hello', - username: 'user', - password: 'pass', - identity: 'ident', - require_tls: true, - }) - ).toEqual({ - from: 'from@mail.com', - smarthost: 'host.com', - hello: 'hello', - username: 'user', - password: 'pass', - authType: EmailAuthType.PLAIN, - requireTls: true, - }); - }); - }); - - describe('cleanupFormValues', () => { - it('should take form values and return only necessary fields', () => { - jest.spyOn(window, 'btoa').mockReturnValue('fakeBtoa'); - expect( - cleanupFormValues({ - from: 'from@mail.com', - smarthost: 'host.com', - hello: 'hello', - username: 'user', - password: 'pass', - authType: EmailAuthType.LOGIN, - requireTls: false, - }) - ).toEqual({ - from: 'from@mail.com', - smarthost: 'host.com', - hello: 'hello', - username: 'user', - password: 'pass', - require_tls: false, - }); - - expect( - cleanupFormValues({ - from: 'from@mail.com', - smarthost: 'host.com', - hello: 'hello', - username: 'user', - password: 'pass', - authType: EmailAuthType.PLAIN, - requireTls: true, - }) - ).toEqual({ - from: 'from@mail.com', - smarthost: 'host.com', - hello: 'hello', - username: 'user', - password: 'pass', - identity: 'fakeBtoa', - require_tls: true, - }); - - expect( - cleanupFormValues({ - from: 'from@mail.com', - smarthost: 'host.com', - hello: 'hello', - username: 'user', - password: 'pass', - authType: EmailAuthType.CRAM, - requireTls: false, - }) - ).toEqual({ - from: 'from@mail.com', - smarthost: 'host.com', - hello: 'hello', - username: 'user', - secret: 'pass', - require_tls: false, - }); - - expect( - cleanupFormValues({ - from: 'from@mail.com', - smarthost: 'host.com', - hello: 'hello', - username: 'user', - password: 'pass', - authType: EmailAuthType.NONE, - requireTls: false, - }) - ).toEqual({ - from: 'from@mail.com', - smarthost: 'host.com', - hello: 'hello', - require_tls: false, - }); - }); - }); -}); diff --git a/public/app/percona/settings/components/Communication/Email/Email.utils.ts b/public/app/percona/settings/components/Communication/Email/Email.utils.ts deleted file mode 100644 index 82e4cfa8ed408..0000000000000 --- a/public/app/percona/settings/components/Communication/Email/Email.utils.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { EmailSettings, EmailAuthType } from '../../../Settings.types'; - -import { FormEmailSettings } from './Email.types'; - -export const isEmailFieldNeeded = (field: keyof EmailSettings, authType: EmailAuthType): boolean => { - let needingAuths: EmailAuthType[] = []; - - switch (field) { - case 'username': - needingAuths = [EmailAuthType.CRAM, EmailAuthType.LOGIN, EmailAuthType.PLAIN]; - break; - case 'password': - needingAuths = [EmailAuthType.LOGIN, EmailAuthType.PLAIN]; - break; - case 'secret': - needingAuths = [EmailAuthType.CRAM]; - break; - case 'identity': - needingAuths = [EmailAuthType.PLAIN]; - break; - case 'smarthost': - case 'from': - case 'hello': - needingAuths = [EmailAuthType.CRAM, EmailAuthType.LOGIN, EmailAuthType.PLAIN, EmailAuthType.NONE]; - break; - default: - break; - } - - return needingAuths.length > 0 && needingAuths.includes(authType); -}; - -export const getAuthTypeFromFields = (settings: EmailSettings): EmailAuthType => { - if (settings.identity) { - return EmailAuthType.PLAIN; - } - - if (settings.secret) { - return EmailAuthType.CRAM; - } - - if (settings.username) { - return EmailAuthType.LOGIN; - } - - return EmailAuthType.NONE; -}; - -export const getInitialValues = (settings: EmailSettings): FormEmailSettings => { - const authType = getAuthTypeFromFields(settings); - const settingsCopy = { ...settings }; - delete settingsCopy.secret; - delete settingsCopy.identity; - delete settingsCopy.require_tls; - const resultSettings: FormEmailSettings = { - ...settingsCopy, - hello: settings.hello || 'localhost', - password: authType === EmailAuthType.CRAM ? settings.secret : settings.password, - authType, - requireTls: !!settings.require_tls, - }; - - return resultSettings; -}; - -export const cleanupFormValues = (values: FormEmailSettings): EmailSettings => { - const baseSettings: EmailSettings = { ...values, require_tls: values.requireTls }; - - if (values.authType === EmailAuthType.PLAIN) { - baseSettings.identity = btoa(`${values.username}${values.password}`); - } else if (values.authType === EmailAuthType.CRAM) { - baseSettings.secret = baseSettings.password; - } - - Object.keys(baseSettings).forEach((field) => { - if (field !== 'require_tls' && !isEmailFieldNeeded(field as keyof EmailSettings, values.authType)) { - delete baseSettings[field as keyof EmailSettings]; - } - }); - - return baseSettings; -}; diff --git a/public/app/percona/settings/components/Communication/Email/TestEmailSettings/TestEmailSettings.messages.ts b/public/app/percona/settings/components/Communication/Email/TestEmailSettings/TestEmailSettings.messages.ts deleted file mode 100644 index 7efd06ee180e1..0000000000000 --- a/public/app/percona/settings/components/Communication/Email/TestEmailSettings/TestEmailSettings.messages.ts +++ /dev/null @@ -1,5 +0,0 @@ -export const Messages = { - test: 'Test', - testEmail: 'Test Email', - tooltip: 'Send a test email to this address', -}; diff --git a/public/app/percona/settings/components/Communication/Email/TestEmailSettings/TestEmailSettings.styles.ts b/public/app/percona/settings/components/Communication/Email/TestEmailSettings/TestEmailSettings.styles.ts deleted file mode 100644 index 0a09bbb4e8146..0000000000000 --- a/public/app/percona/settings/components/Communication/Email/TestEmailSettings/TestEmailSettings.styles.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { css } from '@emotion/css'; - -import { GrafanaTheme } from '@grafana/data'; - -export const getStyles = ({ spacing }: GrafanaTheme) => ({ - form: css` - display: flex; - `, - input: css` - flex-grow: 1; - `, - button: css` - height: 37px; - margin-left: ${spacing.md}; - margin-top: 20px; - `, -}); diff --git a/public/app/percona/settings/components/Communication/Email/TestEmailSettings/TestEmailSettings.tsx b/public/app/percona/settings/components/Communication/Email/TestEmailSettings/TestEmailSettings.tsx deleted file mode 100644 index 0622e1484224a..0000000000000 --- a/public/app/percona/settings/components/Communication/Email/TestEmailSettings/TestEmailSettings.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import { FC, useState } from 'react'; -import { Form } from 'react-final-form'; - -import { Button, useStyles } from '@grafana/ui'; -import { TextInputField } from 'app/percona/shared/components/Form/TextInput'; -import { validators } from 'app/percona/shared/helpers/validatorsForm'; - -import { Messages } from './TestEmailSettings.messages'; -import { getStyles } from './TestEmailSettings.styles'; -import { TestEmailSettingsProps } from './TestEmailSettings.types'; - -export const TestEmailSettings: FC = ({ onTest, onInput = () => null, initialValue = '' }) => { - const [testingSettings, setTestingSettings] = useState(false); - const styles = useStyles(getStyles); - - const handleClick = async (email: string) => { - setTestingSettings(true); - await onTest(email); - setTestingSettings(false); - }; - - return ( -
{}} - initialValues={{ testEmail: initialValue }} - render={({ values, valid }) => ( - - onInput(e.currentTarget.value), - }} - /> - - - )} - > - ); -}; diff --git a/public/app/percona/settings/components/Communication/Email/TestEmailSettings/TestEmailSettings.types.ts b/public/app/percona/settings/components/Communication/Email/TestEmailSettings/TestEmailSettings.types.ts deleted file mode 100644 index 498d50403ba81..0000000000000 --- a/public/app/percona/settings/components/Communication/Email/TestEmailSettings/TestEmailSettings.types.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface TestEmailSettingsProps { - onTest: (email: string) => Promise; - onInput?: (email: string) => void; - initialValue?: string; -} diff --git a/public/app/percona/settings/components/Communication/Slack/Slack.test.tsx b/public/app/percona/settings/components/Communication/Slack/Slack.test.tsx deleted file mode 100644 index 7d6619ce40e04..0000000000000 --- a/public/app/percona/settings/components/Communication/Slack/Slack.test.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import { fireEvent, render, screen } from '@testing-library/react'; - -import { Slack } from './Slack'; - -describe('Slack::', () => { - it('Renders with props', () => { - render( - {}} - /> - ); - - expect(screen.getByTestId('url-text-input')).toHaveValue('test'); - }); - - it('Disables apply changes on initial values', () => { - render( - {}} - /> - ); - const button = screen.getByRole('button'); - - expect(button).toBeDisabled(); - }); - - it('Calls apply changes', () => { - const updateSettings = jest.fn(); - render( - - ); - - const input = screen.getByTestId('url-text-input'); - fireEvent.change(input, { target: { value: 'new key' } }); - - fireEvent.submit(screen.getByTestId('slack-form')); - - expect(updateSettings).toHaveBeenCalled(); - }); -}); diff --git a/public/app/percona/settings/components/Communication/Slack/Slack.tsx b/public/app/percona/settings/components/Communication/Slack/Slack.tsx deleted file mode 100644 index 89aa0d052dc2b..0000000000000 --- a/public/app/percona/settings/components/Communication/Slack/Slack.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import { FC, useState } from 'react'; -import { Form } from 'react-final-form'; - -import { Button, Spinner, useStyles2 } from '@grafana/ui'; -import { getSettingsStyles } from 'app/percona/settings/Settings.styles'; -import { LinkTooltip } from 'app/percona/shared/components/Elements/LinkTooltip/LinkTooltip'; -import { TextInputField } from 'app/percona/shared/components/Form/TextInput'; - -import { LoadingCallback } from '../../../Settings.service'; -import { SlackPayload, SlackSettings } from '../../../Settings.types'; -import { Messages } from '../Communication.messages'; - -export interface SlackProps { - settings: SlackSettings; - updateSettings: (body: SlackPayload, callback: LoadingCallback) => void; -} - -export const Slack: FC = ({ updateSettings, settings }) => { - const settingsStyles = useStyles2(getSettingsStyles); - const [loading, setLoading] = useState(false); - - const applyChanges = (values: SlackSettings) => { - updateSettings( - { - slack_alerting_settings: values, - }, - setLoading - ); - }; - - return ( - <> -
( - -
- {Messages.fields.slackURL.label} - -
- - - - - )} - /> - - ); -}; diff --git a/public/app/percona/settings/components/Diagnostics/Diagnostics.styles.ts b/public/app/percona/settings/components/Diagnostics/Diagnostics.styles.ts deleted file mode 100644 index 45100a946a0b1..0000000000000 --- a/public/app/percona/settings/components/Diagnostics/Diagnostics.styles.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { css } from '@emotion/css'; - -import { GrafanaTheme2 } from '@grafana/data'; - -export const getStyles = ({ v1: { spacing } }: GrafanaTheme2) => ({ - diagnosticsWrapper: css` - flex: 1; - `, - diagnosticsLabel: css` - display: flex; - i { - margin-left: ${spacing.xs}; - } - `, - diagnosticsButton: css` - margin-top: ${spacing.md}; - svg { - margin-right: ${spacing.sm}; - } - `, -}); diff --git a/public/app/percona/settings/components/Diagnostics/Diagnostics.test.tsx b/public/app/percona/settings/components/Diagnostics/Diagnostics.test.tsx deleted file mode 100644 index a9a848c387556..0000000000000 --- a/public/app/percona/settings/components/Diagnostics/Diagnostics.test.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { render, screen } from '@testing-library/react'; - -import { Messages } from 'app/percona/settings/Settings.messages'; - -import { Diagnostics } from './Diagnostics'; - -describe('Diagnostics::', () => { - it('Renders diagnostics correctly', () => { - const { - diagnostics: { action, label }, - } = Messages; - render(); - - expect(screen.getByTestId('diagnostics-label')).toHaveTextContent(label); - expect(screen.getByTestId('diagnostics-button')).toHaveTextContent(action); - }); -}); diff --git a/public/app/percona/settings/components/Diagnostics/Diagnostics.tsx b/public/app/percona/settings/components/Diagnostics/Diagnostics.tsx deleted file mode 100644 index 457353b48ac24..0000000000000 --- a/public/app/percona/settings/components/Diagnostics/Diagnostics.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import { FC } from 'react'; - -import { Icon, LinkButton, Tooltip, useStyles2 } from '@grafana/ui'; -import { Messages } from 'app/percona/settings/Settings.messages'; -import { getSettingsStyles } from 'app/percona/settings/Settings.styles'; - -import { getStyles } from './Diagnostics.styles'; - -export const Diagnostics: FC = () => { - const styles = useStyles2(getStyles); - const settingsStyles = useStyles2(getSettingsStyles); - const { - diagnostics: { action, label, tooltip }, - } = Messages; - - return ( -
-
- {label} - -
- -
-
-
- - - {action} - -
- ); -}; diff --git a/public/app/percona/settings/components/MetricsResolution/MetricsResolution.constants.ts b/public/app/percona/settings/components/MetricsResolution/MetricsResolution.constants.ts deleted file mode 100644 index c6781dad0b2fd..0000000000000 --- a/public/app/percona/settings/components/MetricsResolution/MetricsResolution.constants.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { SelectableValue } from '@grafana/data'; -import { Messages } from 'app/percona/settings/Settings.messages'; -import { MetricsResolutions } from 'app/percona/settings/Settings.types'; - -import { MetricsResolutionPresets } from './MetricsResolution.types'; - -const { - metrics: { options }, -} = Messages; - -export const resolutionsOptions: SelectableValue[] = [ - { value: MetricsResolutionPresets.rare, label: options.rare }, - { value: MetricsResolutionPresets.standard, label: options.standard }, - { value: MetricsResolutionPresets.frequent, label: options.frequent }, - { value: MetricsResolutionPresets.custom, label: options.custom }, -]; - -export const defaultResolutions: MetricsResolutions[] = [ - { - hr: '60s', - mr: '180s', - lr: '300s', - }, - { - hr: '5s', - mr: '10s', - lr: '60s', - }, - { - hr: '1s', - mr: '5s', - lr: '30s', - }, -]; - -export const resolutionMin = 1; -export const resolutionMax = 1000000000; diff --git a/public/app/percona/settings/components/MetricsResolution/MetricsResolution.styles.ts b/public/app/percona/settings/components/MetricsResolution/MetricsResolution.styles.ts deleted file mode 100644 index 3806ee2bc8b3e..0000000000000 --- a/public/app/percona/settings/components/MetricsResolution/MetricsResolution.styles.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { css } from '@emotion/css'; - -import { GrafanaTheme2 } from '@grafana/data'; - -export const getStyles = ({ v1: { spacing } }: GrafanaTheme2) => ({ - resolutionsWrapper: css` - display: flex; - flex-direction: column; - `, - resolutionsRadioButtonGroup: css` - padding: ${spacing.lg} 0 ${spacing.xl} 0; - `, - resolutionInput: css` - input { - width: 60px; - } - `, - numericFieldWrapper: css` - width: 100px; - white-space: nowrap; - `, -}); diff --git a/public/app/percona/settings/components/MetricsResolution/MetricsResolution.test.tsx b/public/app/percona/settings/components/MetricsResolution/MetricsResolution.test.tsx deleted file mode 100644 index 875bff6a38e8f..0000000000000 --- a/public/app/percona/settings/components/MetricsResolution/MetricsResolution.test.tsx +++ /dev/null @@ -1,132 +0,0 @@ -import { fireEvent, render, screen } from '@testing-library/react'; -import { Provider } from 'react-redux'; - -import { wrapWithGrafanaContextMock } from 'app/percona/shared/helpers/testUtils'; -import { configureStore } from 'app/store/configureStore'; -import { StoreState } from 'app/types'; - -import { MetricsResolution } from './MetricsResolution'; -import { defaultResolutions } from './MetricsResolution.constants'; -import { removeUnits } from './MetricsResolution.utils'; - -describe('MetricsResolution::', () => { - it('Renders correctly with props for standard resolution', () => { - render( - - {wrapWithGrafanaContextMock()} - - ); - - const standardRes = removeUnits(defaultResolutions[1]); - - expect(screen.getByTestId('lr-number-input')).toHaveValue(+standardRes.lr); - expect(screen.getByTestId('mr-number-input')).toHaveValue(+standardRes.mr); - expect(screen.getByTestId('hr-number-input')).toHaveValue(+standardRes.hr); - }); - - it('Renders correctly with props for rare resolution', () => { - render( - - {wrapWithGrafanaContextMock()} - - ); - - const standardRes = removeUnits(defaultResolutions[0]); - - expect(screen.getByTestId('lr-number-input')).toHaveValue(+standardRes.lr); - expect(screen.getByTestId('mr-number-input')).toHaveValue(+standardRes.mr); - expect(screen.getByTestId('hr-number-input')).toHaveValue(+standardRes.hr); - }); - - it('Renders correctly with props for frequent resolution', () => { - render( - - {wrapWithGrafanaContextMock()} - - ); - - const standardRes = removeUnits(defaultResolutions[2]); - - expect(screen.getByTestId('lr-number-input')).toHaveValue(+standardRes.lr); - expect(screen.getByTestId('mr-number-input')).toHaveValue(+standardRes.mr); - expect(screen.getByTestId('hr-number-input')).toHaveValue(+standardRes.hr); - }); - - it('Changes input values when changing resolution', () => { - render( - - {wrapWithGrafanaContextMock()} - - ); - const radio = screen.getAllByTestId('resolutions-radio-button')[2]; - - fireEvent.click(radio); - - const standardRes = removeUnits(defaultResolutions[2]); - - expect(screen.getByTestId('lr-number-input')).toHaveValue(+standardRes.lr); - expect(screen.getByTestId('mr-number-input')).toHaveValue(+standardRes.mr); - expect(screen.getByTestId('hr-number-input')).toHaveValue(+standardRes.hr); - }); - - it('Disables apply changes on initial values', () => { - render( - - {wrapWithGrafanaContextMock()} - - ); - const button = screen.getByTestId('metrics-resolution-button'); - - expect(button).toBeDisabled(); - }); -}); diff --git a/public/app/percona/settings/components/MetricsResolution/MetricsResolution.tsx b/public/app/percona/settings/components/MetricsResolution/MetricsResolution.tsx deleted file mode 100644 index 1c3307ce50f9c..0000000000000 --- a/public/app/percona/settings/components/MetricsResolution/MetricsResolution.tsx +++ /dev/null @@ -1,171 +0,0 @@ -import { FormApi } from 'final-form'; -import { FC, useEffect, useState } from 'react'; -import { Form } from 'react-final-form'; - -import { Button, Spinner, useStyles2 } from '@grafana/ui'; -import { Messages } from 'app/percona/settings/Settings.messages'; -import { getSettingsStyles } from 'app/percona/settings/Settings.styles'; -import { MetricsResolutions } from 'app/percona/settings/Settings.types'; -import { FeatureLoader } from 'app/percona/shared/components/Elements/FeatureLoader'; -import { LinkTooltip } from 'app/percona/shared/components/Elements/LinkTooltip/LinkTooltip'; -import { NumberInputField } from 'app/percona/shared/components/Form/NumberInput'; -import { RadioButtonGroupField } from 'app/percona/shared/components/Form/RadioButtonGroup'; -import { TabbedPage, TabbedPageContents } from 'app/percona/shared/components/TabbedPage'; -import { useCancelToken } from 'app/percona/shared/components/hooks/cancelToken.hook'; -import { updateSettingsAction } from 'app/percona/shared/core/reducers'; -import { getPerconaSettings } from 'app/percona/shared/core/selectors'; -import validators from 'app/percona/shared/helpers/validators'; -import { useAppDispatch } from 'app/store/store'; -import { useSelector } from 'app/types'; - -import { SET_SETTINGS_CANCEL_TOKEN } from '../../Settings.constants'; -import { MAX_DAYS, MIN_DAYS } from '../Advanced/Advanced.constants'; - -import { defaultResolutions, resolutionsOptions } from './MetricsResolution.constants'; -import { getStyles } from './MetricsResolution.styles'; -import { MetricsResolutionIntervals, MetricsResolutionPresets } from './MetricsResolution.types'; -import { addUnits, getResolutionValue, removeUnits } from './MetricsResolution.utils'; - -export const MetricsResolution: FC = () => { - const styles = useStyles2(getStyles); - const settingsStyles = useStyles2(getSettingsStyles); - const [initialValues, setInitialValues] = useState({}); - const [loading, setLoading] = useState(false); - const [generateToken] = useCancelToken(); - const { result: settings } = useSelector(getPerconaSettings); - const dispatch = useAppDispatch(); - const { metricsResolutions } = settings!; - const [resolution, setResolution] = useState(getResolutionValue(metricsResolutions).value); - const [fieldsResolutions, updateFieldsResolutions] = useState(removeUnits(metricsResolutions)); - const [customResolutions, updateCustomResolutions] = useState(fieldsResolutions); - - useEffect(() => { - setInitialValues({ ...removeUnits(metricsResolutions), resolutions: getResolutionValue(metricsResolutions).value }); - }, [metricsResolutions]); - - const { - metrics: { - action, - label, - link, - tooltip, - intervals: { low, medium, high }, - }, - tooltipLinkText, - } = Messages; - const resolutionValidators = [validators.required, validators.range(MIN_DAYS, MAX_DAYS)]; - - const applyChanges = async (values: MetricsResolutions) => { - setLoading(true); - await dispatch( - updateSettingsAction({ - body: { metrics_resolutions: addUnits(values) }, - token: generateToken(SET_SETTINGS_CANCEL_TOKEN), - }) - ); - setLoading(false); - }; - - const updateResolutions = ( - form: FormApi<{ hr: string; mr: string; lr: string; resolutions: MetricsResolutionPresets }> - ) => { - const { hr, mr, lr, resolutions: newResolution } = form.getState().values; - - if (resolution === newResolution) { - return; - } - - if (resolution === MetricsResolutionPresets.custom) { - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions - updateCustomResolutions({ hr, mr, lr } as MetricsResolutions); - } - - if (newResolution !== MetricsResolutionPresets.custom) { - const newResolutionKey = resolutionsOptions.findIndex((r) => r.value === newResolution); - const resolutions = removeUnits(defaultResolutions[newResolutionKey]); - - updateFieldsResolutions(resolutions); - form.change(MetricsResolutionIntervals.lr, resolutions.lr); - form.change(MetricsResolutionIntervals.mr, resolutions.mr); - form.change(MetricsResolutionIntervals.hr, resolutions.hr); - } else { - updateFieldsResolutions(customResolutions); - form.change(MetricsResolutionIntervals.lr, customResolutions.lr); - form.change(MetricsResolutionIntervals.mr, customResolutions.mr); - form.change(MetricsResolutionIntervals.hr, customResolutions.hr); - } - - setResolution(newResolution); - }; - - return ( - - - -
-
( - updateResolutions(form)} - data-testid="metrics-resolution-form" - > -
- {label} - -
- -
- -
-
- -
-
- -
- - - )} - /> -
-
-
-
- ); -}; - -export default MetricsResolution; diff --git a/public/app/percona/settings/components/MetricsResolution/MetricsResolution.types.ts b/public/app/percona/settings/components/MetricsResolution/MetricsResolution.types.ts deleted file mode 100644 index ced924ab13f2b..0000000000000 --- a/public/app/percona/settings/components/MetricsResolution/MetricsResolution.types.ts +++ /dev/null @@ -1,12 +0,0 @@ -export enum MetricsResolutionIntervals { - lr = 'lr', - mr = 'mr', - hr = 'hr', -} - -export enum MetricsResolutionPresets { - rare = 'rare', - standard = 'standard', - frequent = 'frequent', - custom = 'custom', -} diff --git a/public/app/percona/settings/components/MetricsResolution/MetricsResolution.utils.ts b/public/app/percona/settings/components/MetricsResolution/MetricsResolution.utils.ts deleted file mode 100644 index da154edb39505..0000000000000 --- a/public/app/percona/settings/components/MetricsResolution/MetricsResolution.utils.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { isEqual } from 'lodash'; - -import { SelectableValue } from '@grafana/data'; -import { MetricsResolutions } from 'app/percona/settings/Settings.types'; - -import { defaultResolutions, resolutionsOptions } from './MetricsResolution.constants'; - -export const getResolutionValue = (metricsResolutions: MetricsResolutions): SelectableValue => { - const index = defaultResolutions.findIndex((resolution) => isEqual(resolution, metricsResolutions)); - - return index !== -1 ? resolutionsOptions[index] : resolutionsOptions[resolutionsOptions.length - 1]; -}; - -const replaceS = (r: string) => r.replace('s', ''); - -// eslint-disable-next-line max-len -export const removeUnits = (r: MetricsResolutions) => ({ lr: replaceS(r.lr), mr: replaceS(r.mr), hr: replaceS(r.hr) }); -export const addUnits = (r: MetricsResolutions) => ({ lr: `${r.lr}s`, mr: `${r.mr}s`, hr: `${r.hr}s` }); diff --git a/public/app/percona/settings/components/SSHKey/SSHKey.styles.ts b/public/app/percona/settings/components/SSHKey/SSHKey.styles.ts deleted file mode 100644 index f538c4b394395..0000000000000 --- a/public/app/percona/settings/components/SSHKey/SSHKey.styles.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { css } from '@emotion/css'; - -import { GrafanaTheme2 } from '@grafana/data'; - -export const getStyles = ({ v1: { spacing } }: GrafanaTheme2) => ({ - sshKeyWrapper: css` - display: flex; - flex-direction: column; - `, - textarea: css` - margin: ${spacing.md} 0; - min-height: 150px; - `, -}); diff --git a/public/app/percona/settings/components/SSHKey/SSHKey.test.tsx b/public/app/percona/settings/components/SSHKey/SSHKey.test.tsx deleted file mode 100644 index b1dbfc3b98dfd..0000000000000 --- a/public/app/percona/settings/components/SSHKey/SSHKey.test.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import { render, screen, fireEvent, waitForElementToBeRemoved, waitFor } from '@testing-library/react'; -import { Provider } from 'react-redux'; - -import * as reducers from 'app/percona/shared/core/reducers'; -import { wrapWithGrafanaContextMock } from 'app/percona/shared/helpers/testUtils'; -import { configureStore } from 'app/store/configureStore'; -import { StoreState } from 'app/types'; - -import { SSHKey } from './SSHKey'; - -jest.mock('app/percona/settings/Settings.service'); - -describe('SSHKey::', () => { - it('Renders correctly', () => { - render( - - {wrapWithGrafanaContextMock()} - - ); - - expect(screen.getByText('fake_key')).toBeInTheDocument(); - }); - - it('Disables apply changes on initial values', () => { - render( - - {wrapWithGrafanaContextMock()} - - ); - - expect(screen.getByTestId('ssh-key-button')).toBeDisabled(); - }); - - it('Calls apply changes', async () => { - const spy = jest.spyOn(reducers, 'updateSettingsAction'); - render( - - {wrapWithGrafanaContextMock()} - - ); - - fireEvent.change(screen.getByTestId('ssh-key'), { target: { value: 'new key' } }); - await waitFor(() => expect(screen.getByTestId('ssh-key-button')).not.toBeDisabled()); - fireEvent.submit(screen.getByTestId('ssh-key-button')); - - await waitForElementToBeRemoved(() => screen.getByTestId('Spinner')); - - expect(spy).toHaveBeenCalled(); - }); -}); diff --git a/public/app/percona/settings/components/SSHKey/SSHKey.tsx b/public/app/percona/settings/components/SSHKey/SSHKey.tsx deleted file mode 100644 index eeee671f02baa..0000000000000 --- a/public/app/percona/settings/components/SSHKey/SSHKey.tsx +++ /dev/null @@ -1,85 +0,0 @@ -import { cx } from '@emotion/css'; -import { FC, useCallback, useState } from 'react'; -import { Field, Form } from 'react-final-form'; - -import { Button, Spinner, TextArea, useStyles2 } from '@grafana/ui'; -import { Messages } from 'app/percona/settings/Settings.messages'; -import { getSettingsStyles } from 'app/percona/settings/Settings.styles'; -import { FeatureLoader } from 'app/percona/shared/components/Elements/FeatureLoader'; -import { LinkTooltip } from 'app/percona/shared/components/Elements/LinkTooltip/LinkTooltip'; -import { TabbedPage, TabbedPageContents } from 'app/percona/shared/components/TabbedPage'; -import { useCancelToken } from 'app/percona/shared/components/hooks/cancelToken.hook'; -import { updateSettingsAction } from 'app/percona/shared/core/reducers'; -import { getPerconaSettings } from 'app/percona/shared/core/selectors'; -import { useAppDispatch } from 'app/store/store'; -import { useSelector } from 'app/types'; - -import { SET_SETTINGS_CANCEL_TOKEN } from '../../Settings.constants'; - -import { getStyles } from './SSHKey.styles'; - -export const SSHKey: FC = () => { - const styles = useStyles2(getStyles); - const settingsStyles = useStyles2(getSettingsStyles); - const { - ssh: { action, label, link, tooltip }, - tooltipLinkText, - } = Messages; - const [loading, setLoading] = useState(false); - const [generateToken] = useCancelToken(); - const { result: settings } = useSelector(getPerconaSettings); - const dispatch = useAppDispatch(); - const { sshKey } = settings!; - const isEqual = (a: string, b: string) => (!a && !b) || a === b; - - const applyChanges = useCallback(async ({ key }: { key: string }) => { - setLoading(true); - await dispatch( - updateSettingsAction({ - body: { ssh_key: key }, - token: generateToken(SET_SETTINGS_CANCEL_TOKEN), - }) - ); - setLoading(false); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - return ( - - - -
-
( - -
- {label} - -
-