From 40c8247a34fd7e313ede381fa56f4fe1a5dce208 Mon Sep 17 00:00:00 2001 From: Fabio Silva Date: Wed, 25 Mar 2026 17:04:59 +0000 Subject: [PATCH 1/5] chore: remove tour --- package.json | 1 - public/app/AppWrapper.tsx | 3 - .../components/AppChrome/AppChromeMenu.tsx | 7 +- .../PerconaBootstrapper.messages.ts | 3 - .../PerconaBootstrapper.tsx | 99 +------------ .../PerconaTour/PerconaTour.tsx | 41 ------ .../PerconaBootstrapper/PerconaTour/index.ts | 3 - public/app/percona/shared/core/hooks/tour.ts | 86 ----------- .../app/percona/shared/core/reducers/index.ts | 6 +- .../shared/core/reducers/tour/index.ts | 5 - .../percona/shared/core/reducers/tour/tour.ts | 51 ------- .../shared/core/reducers/tour/tour.types.ts | 30 ---- .../percona/shared/core/reducers/user/user.ts | 23 +-- .../shared/core/reducers/user/user.types.ts | 2 - .../shared/core/reducers/user/user.utils.ts | 2 - public/app/percona/shared/core/selectors.ts | 1 - .../shared/services/user/User.service.ts | 8 - .../shared/services/user/User.types.ts | 4 - public/app/percona/tour/TourProvider.tsx | 44 ------ public/app/percona/tour/components/Badge.tsx | 28 ---- .../percona/tour/components/Close.styles.ts | 11 -- public/app/percona/tour/components/Close.tsx | 16 -- .../percona/tour/components/Navigation.tsx | 29 ---- .../percona/tour/components/NextButton.tsx | 19 --- .../percona/tour/components/PrevButton.tsx | 17 --- .../percona/tour/components/SidebarStep.tsx | 16 -- .../tour/steps/alerting/alerting.messages.ts | 46 ------ .../tour/steps/alerting/alerting.steps.tsx | 91 ------------ .../app/percona/tour/steps/alerting/index.ts | 3 - .../app/percona/tour/steps/product/index.ts | 3 - .../tour/steps/product/product.messages.ts | 74 ---------- .../tour/steps/product/product.steps.tsx | 138 ------------------ .../tour/steps/product/product.utils.tsx | 37 ----- public/sass/_grafana.scss | 2 - public/sass/components/_pmm_tour.scss | 5 - yarn.lock | 57 -------- 36 files changed, 11 insertions(+), 1000 deletions(-) delete mode 100644 public/app/percona/shared/components/PerconaBootstrapper/PerconaTour/PerconaTour.tsx delete mode 100644 public/app/percona/shared/components/PerconaBootstrapper/PerconaTour/index.ts delete mode 100644 public/app/percona/shared/core/hooks/tour.ts delete mode 100644 public/app/percona/shared/core/reducers/tour/index.ts delete mode 100644 public/app/percona/shared/core/reducers/tour/tour.ts delete mode 100644 public/app/percona/shared/core/reducers/tour/tour.types.ts delete mode 100644 public/app/percona/tour/TourProvider.tsx delete mode 100644 public/app/percona/tour/components/Badge.tsx delete mode 100644 public/app/percona/tour/components/Close.styles.ts delete mode 100644 public/app/percona/tour/components/Close.tsx delete mode 100644 public/app/percona/tour/components/Navigation.tsx delete mode 100644 public/app/percona/tour/components/NextButton.tsx delete mode 100644 public/app/percona/tour/components/PrevButton.tsx delete mode 100644 public/app/percona/tour/components/SidebarStep.tsx delete mode 100644 public/app/percona/tour/steps/alerting/alerting.messages.ts delete mode 100644 public/app/percona/tour/steps/alerting/alerting.steps.tsx delete mode 100644 public/app/percona/tour/steps/alerting/index.ts delete mode 100644 public/app/percona/tour/steps/product/index.ts delete mode 100644 public/app/percona/tour/steps/product/product.messages.ts delete mode 100644 public/app/percona/tour/steps/product/product.steps.tsx delete mode 100644 public/app/percona/tour/steps/product/product.utils.tsx delete mode 100644 public/sass/components/_pmm_tour.scss diff --git a/package.json b/package.json index d053f7ce24757..1a703c34e4453 100644 --- a/package.json +++ b/package.json @@ -310,7 +310,6 @@ "@react-aria/overlays": "3.25.0", "@react-aria/utils": "3.27.0", "@react-awesome-query-builder/ui": "6.6.4", - "@reactour/tour": "^3.0.0", "@reduxjs/toolkit": "2.5.1", "@testing-library/react-hooks": "^8.0.1", "@visx/event": "3.12.0", diff --git a/public/app/AppWrapper.tsx b/public/app/AppWrapper.tsx index c18f54ee91a41..c0141ff24552c 100644 --- a/public/app/AppWrapper.tsx +++ b/public/app/AppWrapper.tsx @@ -25,7 +25,6 @@ import { LiveConnectionWarning } from './features/live/LiveConnectionWarning'; import { ExtensionRegistriesProvider } from './features/plugins/extensions/ExtensionRegistriesContext'; import { pluginExtensionRegistries } from './features/plugins/extensions/registry/setup'; import { PerconaBootstrapper } from './percona/shared/components/PerconaBootstrapper'; -import PerconaTourProvider from './percona/tour/TourProvider'; import { ExperimentalSplitPaneRouterWrapper, RouterWrapper } from './routes/RoutesWrapper'; interface AppWrapperProps { @@ -128,7 +127,6 @@ export class AppWrapper extends Component { actions={[]} options={{ enableHistory: true, callbacks: { onSelectAction: commandPaletteActionSelected } }} > - @@ -145,7 +143,6 @@ export class AppWrapper extends Component { - diff --git a/public/app/core/components/AppChrome/AppChromeMenu.tsx b/public/app/core/components/AppChrome/AppChromeMenu.tsx index f3defc23763fb..66afe19ebc664 100644 --- a/public/app/core/components/AppChrome/AppChromeMenu.tsx +++ b/public/app/core/components/AppChrome/AppChromeMenu.tsx @@ -2,7 +2,6 @@ import { css } from '@emotion/css'; import { useDialog } from '@react-aria/dialog'; import { FocusScope } from '@react-aria/focus'; import { OverlayContainer, useOverlay } from '@react-aria/overlays'; -import { useTour } from '@reactour/tour'; import { useRef } from 'react'; import CSSTransition from 'react-transition-group/CSSTransition'; @@ -28,15 +27,13 @@ export function AppChromeMenu({}: Props) { const isOpen = state.megaMenuOpen && !state.megaMenuDocked; const onClose = () => chrome.setMegaMenuOpen(false); - // @PERCONA - const { isOpen: isTourOpen } = useTour(); const { overlayProps, underlayProps } = useOverlay( { - isDismissable: !isTourOpen, + isDismissable: true, isOpen: true, onClose, - isKeyboardDismissDisabled: !!isTourOpen, + isKeyboardDismissDisabled: false, shouldCloseOnInteractOutside: (element) => { // don't close when interacting with a select menu inside the mega menu // e.g. for the org switcher diff --git a/public/app/percona/shared/components/PerconaBootstrapper/PerconaBootstrapper.messages.ts b/public/app/percona/shared/components/PerconaBootstrapper/PerconaBootstrapper.messages.ts index da53c5c5640ec..2b0c991cad83b 100644 --- a/public/app/percona/shared/components/PerconaBootstrapper/PerconaBootstrapper.messages.ts +++ b/public/app/percona/shared/components/PerconaBootstrapper/PerconaBootstrapper.messages.ts @@ -11,7 +11,4 @@ export const Messages = { backup: 'Back up your critical data with zero-downtime and minimal performance impact.', moreInfo: 'For more information, please check out the ', pmmOnlineHelp: 'PMM online help', - skip: 'Skip', - checkLater: 'Check later', - startTour: 'Start tour', }; diff --git a/public/app/percona/shared/components/PerconaBootstrapper/PerconaBootstrapper.tsx b/public/app/percona/shared/components/PerconaBootstrapper/PerconaBootstrapper.tsx index ee16c7bfb780d..47eb61aa2dc94 100644 --- a/public/app/percona/shared/components/PerconaBootstrapper/PerconaBootstrapper.tsx +++ b/public/app/percona/shared/components/PerconaBootstrapper/PerconaBootstrapper.tsx @@ -1,56 +1,30 @@ -import { useEffect, useState } from 'react'; +import { useEffect } from 'react'; import { config } from '@grafana/runtime'; -import { Button, HorizontalGroup, Icon, Modal, useStyles2, useTheme2 } from '@grafana/ui'; import { fetchSettingsAction } from 'app/percona/shared/core/reducers'; import { fetchAdvisors } from 'app/percona/shared/core/reducers/advisors/advisors'; -import { TourType } from 'app/percona/shared/core/reducers/tour/tour.types'; -import { fetchUserDetailsAction, setAuthorized } from 'app/percona/shared/core/reducers/user/user'; +import { setAuthorized } from 'app/percona/shared/core/reducers/user/user'; import { getUpdatesInfo } from 'app/percona/shared/core/selectors'; import { useAppDispatch } from 'app/store/store'; import { useSelector } from 'app/types'; import { Telemetry } from '../../../ui-events/components/Telemetry'; -import usePerconaTour from '../../core/hooks/tour'; +import { fetchHighAvailabilityStatus } from '../../core/reducers/highAvailability/highAvailability'; import { checkUpdatesAction } from '../../core/reducers/updates'; import { logger } from '../../helpers/logger'; import { isPmmAdmin, isViewer } from '../../helpers/permissions'; +import { isPmmNavEnabled } from '../../helpers/plugin'; -import { Messages } from './PerconaBootstrapper.messages'; -import { getStyles } from './PerconaBootstrapper.styles'; import { PerconaBootstrapperProps } from './PerconaBootstrapper.types'; import PerconaNavigation from './PerconaNavigation/PerconaNavigation'; -import PerconaTourBootstrapper from './PerconaTour'; import PerconaUpdateVersion from './PerconaUpdateVersion/PerconaUpdateVersion'; -import { isPmmNavEnabled } from '../../helpers/plugin'; -import { fetchHighAvailabilityStatus } from '../../core/reducers/highAvailability/highAvailability'; // This component is only responsible for populating the store with Percona's settings initially export const PerconaBootstrapper = ({ onReady }: PerconaBootstrapperProps) => { const dispatch = useAppDispatch(); - const { setSteps, startTour: startPerconaTour, endTour } = usePerconaTour(); const { updateAvailable, isLoading: isLoadingUpdates, showUpdateModal } = useSelector(getUpdatesInfo); - const [modalIsOpen, setModalIsOpen] = useState(true); - const [showTour, setShowTour] = useState(false); - const styles = useStyles2(getStyles); const { user } = config.bootData; const { isSignedIn } = user; - const theme = useTheme2(); - - const dismissModal = () => { - setModalIsOpen(false); - }; - - const finishTour = () => { - setModalIsOpen(false); - setShowTour(false); - endTour(TourType.Product); - }; - - const startTour = () => { - setModalIsOpen(false); - startPerconaTour(TourType.Product); - }; useEffect(() => { const getSettings = async () => { @@ -69,16 +43,6 @@ export const PerconaBootstrapper = ({ onReady }: PerconaBootstrapperProps) => { return null; }; - - const getUserDetails = async () => { - try { - const details = await dispatch(fetchUserDetailsAction()).unwrap(); - setShowTour(!details.productTourCompleted); - } catch (e) { - setShowTour(false); - } - }; - const bootstrap = async () => { const settings = await getSettings(); @@ -92,7 +56,6 @@ export const PerconaBootstrapper = ({ onReady }: PerconaBootstrapperProps) => { } } - await getUserDetails(); await dispatch(fetchHighAvailabilityStatus()); onReady(); }; @@ -102,63 +65,13 @@ export const PerconaBootstrapper = ({ onReady }: PerconaBootstrapperProps) => { } else { onReady(); } - }, [dispatch, isSignedIn, setSteps, onReady, user]); + }, [dispatch, isSignedIn, onReady, user]); return ( <> {isSignedIn && } - {!isPmmNavEnabled() && } - {!isPmmNavEnabled() && updateAvailable && showUpdateModal && !isLoadingUpdates ? ( - - ) : ( - !isPmmNavEnabled() && - isSignedIn && - showTour && ( - -
- -
-

- {Messages.pmm} - {Messages.pmmIs} -

-

- {Messages.pmmEnables} -

    -
  • {Messages.spotCriticalPerformance}
  • -
  • {Messages.ensureDbPerformance}
  • -
  • {Messages.backup}
  • -
-

-

- {Messages.moreInfo} - - {Messages.pmmOnlineHelp} - - . -

- - - - - - - -
- ) - )} + {!isPmmNavEnabled() && updateAvailable && showUpdateModal && !isLoadingUpdates && } ); }; diff --git a/public/app/percona/shared/components/PerconaBootstrapper/PerconaTour/PerconaTour.tsx b/public/app/percona/shared/components/PerconaBootstrapper/PerconaTour/PerconaTour.tsx deleted file mode 100644 index 81c80122cd1f9..0000000000000 --- a/public/app/percona/shared/components/PerconaBootstrapper/PerconaTour/PerconaTour.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { FC, useEffect } from 'react'; -import { useLocation } from 'react-router-dom'; - -import { contextSrv } from 'app/core/core'; -import usePerconaTour from 'app/percona/shared/core/hooks/tour'; -import { TourType } from 'app/percona/shared/core/reducers/tour'; -import { getPerconaSettings, getPerconaUser, getServices } from 'app/percona/shared/core/selectors'; -import { isPmmAdmin } from 'app/percona/shared/helpers/permissions'; -import getAlertingTourSteps from 'app/percona/tour/steps/alerting'; -import getProductTourSteps from 'app/percona/tour/steps/product'; -import { useSelector } from 'app/types'; - -const PerconaTourBootstrapper: FC = () => { - const { startTour, setSteps } = usePerconaTour(); - const location = useLocation(); - const user = useSelector(getPerconaUser); - const { result: settings } = useSelector(getPerconaSettings); - const { activeTypes } = useSelector(getServices); - - useEffect(() => { - setSteps(TourType.Alerting, getAlertingTourSteps(isPmmAdmin(contextSrv.user))); - }, [setSteps]); - - useEffect(() => { - setSteps(TourType.Product, getProductTourSteps(isPmmAdmin(contextSrv.user), settings, activeTypes)); - }, [setSteps, settings, activeTypes]); - - useEffect(() => { - if (!user.productTourCompleted) { - return; - } - - if (!user.alertingTourCompleted && location.pathname.startsWith('/alerting')) { - startTour(TourType.Alerting); - } - }, [startTour, user, location.pathname]); - - return null; -}; - -export default PerconaTourBootstrapper; diff --git a/public/app/percona/shared/components/PerconaBootstrapper/PerconaTour/index.ts b/public/app/percona/shared/components/PerconaBootstrapper/PerconaTour/index.ts deleted file mode 100644 index e10f6750de697..0000000000000 --- a/public/app/percona/shared/components/PerconaBootstrapper/PerconaTour/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import PerconaTourBootstrapper from './PerconaTour'; - -export default PerconaTourBootstrapper; diff --git a/public/app/percona/shared/core/hooks/tour.ts b/public/app/percona/shared/core/hooks/tour.ts deleted file mode 100644 index 84229d61a9262..0000000000000 --- a/public/app/percona/shared/core/hooks/tour.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { useTour } from '@reactour/tour'; -import { useCallback, useEffect, useMemo } from 'react'; - -import { useGrafana } from 'app/core/context/GrafanaContext'; -import * as TourActions from 'app/percona/shared/core/reducers/tour'; -import { TourStep, TourType } from 'app/percona/shared/core/reducers/tour'; -import { useAppDispatch } from 'app/store/store'; -import { useSelector } from 'app/types'; - -import { waitForVisible } from '../../helpers/observer'; -import { getTour } from '../selectors'; - -const usePerconaTour = () => { - const dispatch = useAppDispatch(); - const { steps, tour } = useSelector(getTour); - const reactTour = useTour(); - const tourSteps = useMemo(() => (tour ? steps[tour] : []), [tour, steps]); - const { chrome } = useGrafana(); - - useEffect(() => { - if (reactTour.setSteps) { - reactTour.setSteps(tour ? steps[tour] : []); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [steps, tour]); - - const setSteps = useCallback( - (tour: TourType, steps: TourStep[]) => { - dispatch(TourActions.setSteps({ tour, steps })); - }, - [dispatch] - ); - - const startTour = useCallback( - async (tour: TourType) => { - chrome.setMegaMenuOpen(true); - - const firstStep = steps[tour][0]; - - // wait for the first step element to visible - if (firstStep?.selector) { - await waitForVisible(firstStep.selector); - } - dispatch(TourActions.startTour(tour)); - reactTour.setIsOpen(true); - reactTour.setCurrentStep(0); - }, - // eslint-disable-next-line react-hooks/exhaustive-deps - [steps, dispatch] - ); - - const endTour = useCallback( - (tour: TourType) => { - dispatch(TourActions.endTourAction(tour)); - reactTour.setIsOpen(false); - reactTour.setCurrentStep(0); - }, - // eslint-disable-next-line react-hooks/exhaustive-deps - [dispatch] - ); - - const nextStep = useCallback(() => { - reactTour.setCurrentStep((step: number) => (step === reactTour.steps.length - 1 ? step : step + 1)); - }, [reactTour]); - - const previousStep = useCallback(() => { - reactTour.setCurrentStep((step: number) => (step === 0 ? 0 : step - 1)); - }, [reactTour]); - - return { - tour, - isOpen: reactTour.isOpen, - steps: tourSteps, - currentStep: reactTour.currentStep, - navMenuId: tourSteps[reactTour.currentStep]?.navMenuId, - setSteps, - startTour, - endTour, - nextStep, - previousStep, - isFirstStep: reactTour.currentStep === 0, - isLastStep: reactTour.currentStep === tourSteps.length - 1, - }; -}; - -export default usePerconaTour; diff --git a/public/app/percona/shared/core/reducers/index.ts b/public/app/percona/shared/core/reducers/index.ts index 070bdd779beea..ee7926d7086b9 100644 --- a/public/app/percona/shared/core/reducers/index.ts +++ b/public/app/percona/shared/core/reducers/index.ts @@ -3,6 +3,7 @@ import { combineReducers, createAsyncThunk } from '@reduxjs/toolkit'; import { CancelToken } from 'axios'; import { config } from '@grafana/runtime'; +import appEvents from 'app/core/app_events'; import { createAsyncSlice, withAppEvents, withSerializedError } from 'app/features/alerting/unified/utils/redux'; import { AlertRuleTemplateService } from 'app/percona/integrated-alerting/components/AlertRuleTemplate/AlertRuleTemplate.service'; import { TemplatesList } from 'app/percona/integrated-alerting/components/AlertRuleTemplate/AlertRuleTemplate.types'; @@ -11,6 +12,7 @@ import { Settings, SettingsAPIChangePayload } from 'app/percona/settings/Setting import { uiEventsReducer } from 'app/percona/ui-events/reducer'; import { isPmmAdmin } from '../../helpers/permissions'; +import { SettingsUpdatedEvent } from '../events'; import advisorsReducers from './advisors/advisors'; import perconaBackupLocations from './backups/backupLocations'; @@ -20,12 +22,9 @@ import nodesReducer from './nodes'; import pmmDumpsReducers from './pmmDump/pmmDump'; import rolesReducers from './roles/roles'; import servicesReducer from './services'; -import tourReducer from './tour/tour'; import updatesReducers from './updates'; import perconaUserReducers from './user/user'; import usersReducers from './users/users'; -import appEvents from 'app/core/app_events'; -import { SettingsUpdatedEvent } from '../events'; const initialSettingsState: Settings = { updatesEnabled: false, @@ -151,7 +150,6 @@ export default { services: servicesReducer, nodes: nodesReducer, backupLocations: perconaBackupLocations, - tour: tourReducer, telemetry: uiEventsReducer, roles: rolesReducers, users: usersReducers, diff --git a/public/app/percona/shared/core/reducers/tour/index.ts b/public/app/percona/shared/core/reducers/tour/index.ts deleted file mode 100644 index 85a337cc34bd4..0000000000000 --- a/public/app/percona/shared/core/reducers/tour/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -import tourReducer from './tour'; -export * from './tour'; -export * from './tour.types'; - -export default tourReducer; diff --git a/public/app/percona/shared/core/reducers/tour/tour.ts b/public/app/percona/shared/core/reducers/tour/tour.ts deleted file mode 100644 index 62d479f9e49e2..0000000000000 --- a/public/app/percona/shared/core/reducers/tour/tour.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit'; - -import { setAlertingTourCompleted, setProductTourCompleted } from '../user/user'; - -import { SetStepsActionPayload, TourState, TourType } from './tour.types'; - -const initialState: TourState = { - isOpen: false, - steps: { - [TourType.Alerting]: [], - [TourType.Product]: [], - }, -}; - -const tourSlice = createSlice({ - name: 'tour', - initialState, - reducers: { - setSteps: (state, { payload }: PayloadAction) => ({ - ...state, - steps: { - ...state.steps, - [payload.tour]: payload.steps, - }, - }), - startTour: (state, { payload }: PayloadAction) => ({ - ...state, - isOpen: true, - tour: payload, - }), - resetTour: (state) => ({ - ...state, - isOpen: false, - tour: undefined, - }), - }, -}); - -export const endTourAction = createAsyncThunk('percona/endTour', (tour: TourType, { dispatch }) => { - if (tour === TourType.Product) { - dispatch(setProductTourCompleted(true)); - } else if (tour === TourType.Alerting) { - dispatch(setAlertingTourCompleted(true)); - } - - dispatch(tourSlice.actions.resetTour()); -}); - -export const { setSteps, startTour } = tourSlice.actions; - -export default tourSlice.reducer; diff --git a/public/app/percona/shared/core/reducers/tour/tour.types.ts b/public/app/percona/shared/core/reducers/tour/tour.types.ts deleted file mode 100644 index 833d8ad4feeb1..0000000000000 --- a/public/app/percona/shared/core/reducers/tour/tour.types.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { ReactElement } from 'react'; - -export interface TourStep { - navMenuId?: string; - // Props used from StepType from @reactour/tour - // Extending the whole type is causing a TS error: - // "Type instantiation is excessively deep and possibly infinite." - selector: string; - content: ReactElement; - position?: 'top' | 'right' | 'bottom' | 'left' | 'center' | [number, number]; - highlightedSelectors?: string[]; - resizeObservables?: string[]; - mutationObservables?: string[]; -} - -export enum TourType { - Product = 'product', - Alerting = 'alerting', -} - -export interface TourState { - isOpen: boolean; - tour?: TourType; - steps: Record; -} - -export interface SetStepsActionPayload { - tour: TourType; - steps: TourStep[]; -} diff --git a/public/app/percona/shared/core/reducers/user/user.ts b/public/app/percona/shared/core/reducers/user/user.ts index 1c83e47982e36..a7a4bb5f69b5a 100644 --- a/public/app/percona/shared/core/reducers/user/user.ts +++ b/public/app/percona/shared/core/reducers/user/user.ts @@ -7,8 +7,6 @@ import { toUserDetailsModel } from './user.utils'; export const initialUserState: PerconaUserState = { userId: 0, - productTourCompleted: true, - alertingTourCompleted: true, isAuthorized: false, snoozedPmmVersion: '', }; @@ -38,18 +36,9 @@ export const fetchUserDetailsAction = createAsyncThunk( } ); -export const setProductTourCompleted = createAsyncThunk( - 'percona/setProductTourCompleted', - async (productTourCompleted: boolean, thunkAPI): Promise => { - const res = await UserService.setProductTourCompleted(productTourCompleted); - const details = toUserDetailsModel(res); - thunkAPI.dispatch(setUserDetails(details)); - return details; - } -); export const setSnoozedVersion = createAsyncThunk( - 'percona/setProductTourCompleted', + 'percona/setSnoozedVersion', async (version: string, thunkAPI): Promise => { const res = await UserService.setSnoozedVersion(version); const details = toUserDetailsModel(res); @@ -58,16 +47,6 @@ export const setSnoozedVersion = createAsyncThunk( } ); -export const setAlertingTourCompleted = createAsyncThunk( - 'percona/setAlertingTourCompleted', - async (alertingTourCompleted: boolean, thunkAPI): Promise => { - const res = await UserService.setAlertingTourCompeted(alertingTourCompleted); - const details = toUserDetailsModel(res); - thunkAPI.dispatch(setUserDetails(details)); - return details; - } -); - export const { setAuthorized, setUserDetails } = perconaUserSlice.actions; export default perconaUserSlice.reducer; diff --git a/public/app/percona/shared/core/reducers/user/user.types.ts b/public/app/percona/shared/core/reducers/user/user.types.ts index 7ea710d558ff6..0ad1838f6f0c4 100644 --- a/public/app/percona/shared/core/reducers/user/user.types.ts +++ b/public/app/percona/shared/core/reducers/user/user.types.ts @@ -1,7 +1,5 @@ export interface UserDetails { userId: number; - productTourCompleted: boolean; - alertingTourCompleted: boolean; snoozedPmmVersion?: string; } diff --git a/public/app/percona/shared/core/reducers/user/user.utils.ts b/public/app/percona/shared/core/reducers/user/user.utils.ts index 5e972077d1bd8..9cf5af29faeeb 100644 --- a/public/app/percona/shared/core/reducers/user/user.utils.ts +++ b/public/app/percona/shared/core/reducers/user/user.utils.ts @@ -4,7 +4,5 @@ import { UserDetails } from './user.types'; export const toUserDetailsModel = (res: UserDetailsResponse): UserDetails => ({ userId: res.user_id, - productTourCompleted: !!res.product_tour_completed, - alertingTourCompleted: !!res.alerting_tour_completed, snoozedPmmVersion: res.snoozed_pmm_version, }); diff --git a/public/app/percona/shared/core/selectors.ts b/public/app/percona/shared/core/selectors.ts index c58fd9b930068..70dbcafee66c7 100644 --- a/public/app/percona/shared/core/selectors.ts +++ b/public/app/percona/shared/core/selectors.ts @@ -13,7 +13,6 @@ export const getTemplates = (state: StoreState) => state.percona.templates; export const getServices = (state: StoreState) => state.percona.services; export const getNodes = (state: StoreState) => state.percona.nodes; export const getBackupLocations = (state: StoreState) => state.percona.backupLocations; -export const getTour = (state: StoreState) => state.percona.tour; export const getAccessRoles = (state: StoreState) => state.percona.roles; export const getUsers = (state: StoreState) => state.users; export const getUsersInfo = (state: StoreState) => state.percona.users; diff --git a/public/app/percona/shared/services/user/User.service.ts b/public/app/percona/shared/services/user/User.service.ts index eeefbe6be117c..b82e69b1924da 100644 --- a/public/app/percona/shared/services/user/User.service.ts +++ b/public/app/percona/shared/services/user/User.service.ts @@ -14,14 +14,6 @@ export const UserService = { return is_platform_user; }, getUserDetails: async (): Promise => await api.get('/v1/users/me', true), - async setProductTourCompleted(completed: boolean): Promise { - const payload: UserDetailsPutPayload = { product_tour_completed: completed }; - return await api.put('/v1/users/me', payload); - }, - async setAlertingTourCompeted(completed: boolean): Promise { - const payload: UserDetailsPutPayload = { alerting_tour_completed: completed }; - return await api.put('/v1/users/me', payload); - }, async setSnoozedVersion(version: string): Promise { const payload: UserDetailsPutPayload = { snoozed_pmm_version: version }; return await api.put('/v1/users/me', payload); diff --git a/public/app/percona/shared/services/user/User.types.ts b/public/app/percona/shared/services/user/User.types.ts index a31cadb6fc239..7f1576ae3c7b2 100644 --- a/public/app/percona/shared/services/user/User.types.ts +++ b/public/app/percona/shared/services/user/User.types.ts @@ -4,14 +4,10 @@ export interface UserStatusResponse { export interface UserDetailsResponse { user_id: number; - product_tour_completed?: boolean; - alerting_tour_completed?: boolean; snoozed_pmm_version?: string; } export interface UserDetailsPutPayload { - product_tour_completed?: boolean; - alerting_tour_completed?: boolean; snoozed_pmm_version?: string; } diff --git a/public/app/percona/tour/TourProvider.tsx b/public/app/percona/tour/TourProvider.tsx deleted file mode 100644 index c40fcf9ec4fc8..0000000000000 --- a/public/app/percona/tour/TourProvider.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import { TourProvider } from '@reactour/tour'; -import { FC, PropsWithChildren } from 'react'; - -import { config } from '@grafana/runtime'; -import { getTheme } from '@grafana/ui'; -import usePerconaTour from 'app/percona/shared/core/hooks/tour'; - -import Close from './components/Close'; -import Navigation from './components/Navigation'; - -const PerconaTourProvider: FC = ({ children }) => { - const { tour, steps, endTour } = usePerconaTour(); - - return ( - `${currentStep + 1}/${totalSteps}`} - disableFocusLock - onClickClose={({ setIsOpen, setCurrentStep }) => { - tour && endTour(tour); - setCurrentStep(0); - setIsOpen(false); - }} - onClickMask={({ setCurrentStep, setIsOpen }) => { - tour && endTour(tour); - setCurrentStep(0); - setIsOpen(false); - }} - className="pmm-tour" - styles={{ - popover: (base) => ({ - ...base, - backgroundColor: getTheme(config.bootData.user.lightTheme ? 'light' : 'dark').colors.bg1, - }), - }} - > - {children} - - ); -}; - -export default PerconaTourProvider; diff --git a/public/app/percona/tour/components/Badge.tsx b/public/app/percona/tour/components/Badge.tsx deleted file mode 100644 index 052e5798c8c70..0000000000000 --- a/public/app/percona/tour/components/Badge.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { components } from '@reactour/tour'; -// there is a problem with exported types from react tour -// @ts-ignore -import { BadgeProps } from '@reactour/tour/dist/components/Badge'; -import { FC } from 'react'; - -import { useTheme2 } from '@grafana/ui'; - -const Badge: FC = ({ children }) => { - const theme = useTheme2(); - - return ( - ({ - ...base, - background: theme.colors.primary.main, - fontFamily: theme.typography.fontFamily, - fontSize: '0.8em', - }), - }} - > - {children} - - ); -}; - -export default Badge; diff --git a/public/app/percona/tour/components/Close.styles.ts b/public/app/percona/tour/components/Close.styles.ts deleted file mode 100644 index d43d3b5c678c6..0000000000000 --- a/public/app/percona/tour/components/Close.styles.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { css } from '@emotion/css'; - -export const getStyles = () => ({ - button: css` - position: absolute; - right: 10px; - top: 10px; - outline: none; - margin: 0; - `, -}); diff --git a/public/app/percona/tour/components/Close.tsx b/public/app/percona/tour/components/Close.tsx deleted file mode 100644 index dcd8da7ad3294..0000000000000 --- a/public/app/percona/tour/components/Close.tsx +++ /dev/null @@ -1,16 +0,0 @@ -// there is a problem with exported types from react tour -// @ts-ignore -import { CloseProps } from '@reactour/tour/dist/components/Close'; -import { FC } from 'react'; - -import { IconButton, useStyles2 } from '@grafana/ui'; - -import { getStyles } from './Close.styles'; - -const Close: FC = ({ onClick }) => { - const styles = useStyles2(getStyles); - - return ; -}; - -export default Close; diff --git a/public/app/percona/tour/components/Navigation.tsx b/public/app/percona/tour/components/Navigation.tsx deleted file mode 100644 index fcb4e014b53a3..0000000000000 --- a/public/app/percona/tour/components/Navigation.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { components } from '@reactour/tour'; -// there is a problem with exported members from react tour -// @ts-ignore -import { NavigationProps } from '@reactour/tour/dist/components/Navigation'; -import { FC } from 'react'; - -import { useTheme2 } from '@grafana/ui'; - -import NextButton from './NextButton'; -import PrevButton from './PrevButton'; - -const Navigation: FC = ({ setCurrentStep, steps, currentStep, disableDots, setIsOpen }) => { - const theme = useTheme2(); - - return ( - ({ ...base, background: theme.colors.primary.main, color: theme.colors.primary.main }) }} - /> - ); -}; - -export default Navigation; diff --git a/public/app/percona/tour/components/NextButton.tsx b/public/app/percona/tour/components/NextButton.tsx deleted file mode 100644 index 3bc52030ae8b4..0000000000000 --- a/public/app/percona/tour/components/NextButton.tsx +++ /dev/null @@ -1,19 +0,0 @@ -// there is a problem with exported types from react tour -// @ts-ignore -import { BtnFnProps } from '@reactour/tour/dist/types'; -import { FC } from 'react'; - -import { Button, IconButton } from '@grafana/ui'; -import usePerconaTour from 'app/percona/shared/core/hooks/tour'; - -const NextButton: FC = () => { - const { tour, endTour, nextStep, isLastStep } = usePerconaTour(); - - return isLastStep ? ( - - ) : ( - - ); -}; - -export default NextButton; diff --git a/public/app/percona/tour/components/PrevButton.tsx b/public/app/percona/tour/components/PrevButton.tsx deleted file mode 100644 index 4ed720a8804f2..0000000000000 --- a/public/app/percona/tour/components/PrevButton.tsx +++ /dev/null @@ -1,17 +0,0 @@ -// there is a problem with exported types from react tour -// @ts-ignore -import { BtnFnProps } from '@reactour/tour/dist/types'; -import { FC } from 'react'; - -import { IconButton } from '@grafana/ui'; -import usePerconaTour from 'app/percona/shared/core/hooks/tour'; - -const PrevButton: FC = () => { - const { previousStep, isFirstStep } = usePerconaTour(); - - return ( - - ); -}; - -export default PrevButton; diff --git a/public/app/percona/tour/components/SidebarStep.tsx b/public/app/percona/tour/components/SidebarStep.tsx deleted file mode 100644 index 9aff8e33eadd4..0000000000000 --- a/public/app/percona/tour/components/SidebarStep.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { FC, PropsWithChildren } from 'react'; - -interface Props extends PropsWithChildren { - title: string; -} - -const SidebarStep: FC = ({ title, children }) => ( - <> -

- {title} -

- {children} - -); - -export default SidebarStep; diff --git a/public/app/percona/tour/steps/alerting/alerting.messages.ts b/public/app/percona/tour/steps/alerting/alerting.messages.ts deleted file mode 100644 index f6b6d8bea9b85..0000000000000 --- a/public/app/percona/tour/steps/alerting/alerting.messages.ts +++ /dev/null @@ -1,46 +0,0 @@ -export const Messages = { - firedAlerts: { - title: 'Fired Alerts', - view: 'View all the alerts generated by your active alert rules.', - check: 'Check this tab regularly for an overview of current issues in your environment.', - }, - alertRuleTemplates: { - title: 'Alert Rule Templates', - effortlessly: 'Templates help you create complex alert rules effortlessly.', - offers: - 'Percona offers a set of default templates for common events and expressions, but you can also create custom templates to fit your unique requirements.', - }, - alertRules: { - title: 'Alert Rules', - rules: 'Alert rules specify the conditions for firing alerts.', - start: - 'Start from your available templates to pre-fill some of these conditions, and create your rule by adding more conditions and changing the template values.', - create: "If you need to create an alert rule from scratch, use Grafana's complex alerting configuration instead.", - }, - contactPoints: { - title: 'Contact Points', - define: 'Define how your contacts are notified when an alert fires.', - grafana: - 'Grafana supports a multitude of ChatOps tools to ensure that your team is notified via the most relevant channel.', - }, - notificationPolicies: { - title: 'Notification Policies', - routed: 'Set where, when, and how the alerts get routed.', - policy: 'A notification policy has a contact point assigned to it that consists of one or more notifiers.', - }, - silences: { - title: 'Silences', - create: 'Create silences when you want to stop notifications from one or more alerting rules.', - silences: - 'Silences will prevent notifications from getting created, but they will not prevent alerting rules from being evaluated or recorded in the Fired Alerts tab. A silence only lasts for a specified window of time.', - }, - alertGroups: { - title: 'Alert Groups', - alert: 'Alert Groups show grouped alerts.', - grouping: "Group common alerts into a single alert group to ensure that PMM doesn't fire duplicate alerts.", - }, - settings: { - title: 'Settings', - configure: 'Use this to configure Alertmanagers in raw JSON format.', - }, -}; diff --git a/public/app/percona/tour/steps/alerting/alerting.steps.tsx b/public/app/percona/tour/steps/alerting/alerting.steps.tsx deleted file mode 100644 index 17f47b3ead0dd..0000000000000 --- a/public/app/percona/tour/steps/alerting/alerting.steps.tsx +++ /dev/null @@ -1,91 +0,0 @@ -import { TourStep } from 'app/percona/shared/core/reducers/tour'; -import SidebarStep from 'app/percona/tour/components/SidebarStep'; - -import { Messages } from './alerting.messages'; - -export const getAlertingTourSteps = (isAdmin = false): TourStep[] => [ - ...(isAdmin - ? [ - { - selector: '[aria-label="Fired alerts"]', - mutationObservables: ['.page-body'], - resizeObservables: ['.page-body'], - content: ( - -

{Messages.firedAlerts.view}

-

{Messages.firedAlerts.check}

-
- ), - }, - { - selector: '[aria-label="Alert rule templates"]', - content: ( - -

{Messages.alertRuleTemplates.effortlessly}

-

{Messages.alertRuleTemplates.offers}

-
- ), - }, - ] - : []), - { - selector: '[aria-label="Alert rules"]', - content: ( - -

{Messages.alertRules.rules}

-

{Messages.alertRules.start}

-

{Messages.alertRules.create}

-
- ), - }, - { - selector: '[aria-label="Contact points"]', - content: ( - -

{Messages.contactPoints.define}

-

{Messages.contactPoints.grafana}

-
- ), - }, - { - selector: '[aria-label="Notification policies"]', - content: ( - -

{Messages.notificationPolicies.routed}

-

{Messages.notificationPolicies.policy}

-
- ), - }, - { - selector: '[aria-label="Silences"]', - content: ( - -

{Messages.silences.create}

-

{Messages.silences.silences}

-
- ), - }, - { - selector: '[aria-label="Alert groups"]', - content: ( - -

{Messages.alertGroups.alert}

-

{Messages.alertGroups.grouping}

-
- ), - }, - ...(isAdmin - ? [ - { - selector: '[aria-label="Settings"]', - content: ( - -

{Messages.settings.configure}

-
- ), - }, - ] - : []), -]; - -export default getAlertingTourSteps; diff --git a/public/app/percona/tour/steps/alerting/index.ts b/public/app/percona/tour/steps/alerting/index.ts deleted file mode 100644 index 1447e6093823f..0000000000000 --- a/public/app/percona/tour/steps/alerting/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import getAlertingTourSteps from './alerting.steps'; - -export default getAlertingTourSteps; diff --git a/public/app/percona/tour/steps/product/index.ts b/public/app/percona/tour/steps/product/index.ts deleted file mode 100644 index fb25130942d2d..0000000000000 --- a/public/app/percona/tour/steps/product/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import getProductTourSteps from './product.steps'; - -export default getProductTourSteps; diff --git a/public/app/percona/tour/steps/product/product.messages.ts b/public/app/percona/tour/steps/product/product.messages.ts deleted file mode 100644 index 818f369a6a18a..0000000000000 --- a/public/app/percona/tour/steps/product/product.messages.ts +++ /dev/null @@ -1,74 +0,0 @@ -export const Messages = { - dashboards: { - title: 'Dashboards', - browse: 'Here you can browse, create or import the dashboards.', - folders: 'Dashboards are grouped into folders. You can customize these by renaming them or creating new ones.', - playlists: - 'You can also create and browse playlists. A Playlist can be a great way to show specific dashboards to your team or visitors.', - }, - pmmDashboards: { - title: 'PMM Dashboards', - grafanaTechnology: - 'PMM dashboards built on Grafana technology are powered by decades of Percona expertise in database performance optimization.', - observe: - 'Use technology-specific or Operating System dashboards to observe top to bottom performance metrics and get to the root of the database problems in minutes.', - zoomIn: - 'Zoom in and drill-down to observe database performance from node to single query levels. Get insights about your database no matter where they are stored on-premises, in the cloud, or in hybrid environments.', - }, - qan: { - title: 'PMM Query Analytics', - queries: 'Query Analytics (QAN) dashboard shows how queries are executed along with the query count and time.', - analyze: - 'It helps you analyze the database queries over time, optimize database performance, and find and remedy the source of problems.', - }, - explore: { - title: 'Explore', - data: 'If you want to explore your data but do not want to create a dashboard, then Explore is the option for you.', - graphs: 'If your data source supports graph and table data, then Explore shows the results as a graph and a table.', - query: 'Explore panel strips away the dashboard and panel options so that you can focus on the query.', - }, - alerting: { - title: 'Alerting', - simplerToUse: 'PMM comes with a simpler-to-use alerting system ', - admin: 'for admin users ', - thatWorks: "that works side-by-side with Grafana's", - youDefine: - 'You define what system metrics are critical to your environment, and what thresholds are acceptable for each metric. When something needs your attention, PMM automatically sends you an alert through your specified communication channels.', - howToUse: 'To use PMM Alerting, make sure to activate it via Settings, on this sidebar.', - moreInfo: 'For more information, see ', - docs: 'Integrated Alerting documentation', - }, - configPanel: { - title: 'PMM Configuration Panel', - services: - "Here you can check Services, Agents and Nodes in your PMM's Inventory, and add new instances for monitoring: PostgreSQL, MySQL, MongoDB, HAProxy, etc.", - settings: - 'PMM Settings also live here. From there, you can change more advanced settings, for example to enable PMM Alerting, etc.', - settingsDocs: 'Documentation for PMM Settings ', - settingsDocsLink: 'here', - }, - serverAdmin: { - title: 'Administration', - userManagement: 'In the Administration panel you can assign and control user management for PMM:', - addEditRemove: 'Add, edit, and remove users.', - grant: 'Grant or Revoke admin privileges for a user.', - manageOrg: 'Manage organizations to which the user belongs and their assigned role.', - changeOrg: 'Change the organization role assigned to the user account.', - }, - advisors: { - title: 'Advisors', - pmmIncludes: - 'PMM includes a set of Advisors that run checks against the databases connected to PMM. The checks identify and alert you of potential security threats, performance degradation, data loss, data corruption, non-compliance issues, etc.', - findOutMore: 'To find out more, check out the ', - docs: 'Advisors documentation', - }, - backup: { - title: 'Backup', - feature: - 'The backup feature allows you to back up the databases that PMM is monitoring. PMM supports backup for MySQL and MongoDB (Point-In-Time-Recoverable Backups) databases.', - onDemand: - 'You can set up backup on demand. In case of failures, you can predefine the retry mode, either manual or auto, along with the retry times and retry intervals.', - shedule: - 'You can also set up a backup schedule where the backup will automatically run on the scheduled day and time, with the option to run the backup in either full or incremental mode.', - }, -}; diff --git a/public/app/percona/tour/steps/product/product.steps.tsx b/public/app/percona/tour/steps/product/product.steps.tsx deleted file mode 100644 index 0b785d9061671..0000000000000 --- a/public/app/percona/tour/steps/product/product.steps.tsx +++ /dev/null @@ -1,138 +0,0 @@ -import { Settings } from 'app/percona/settings/Settings.types'; -import { TourStep } from 'app/percona/shared/core/reducers/tour'; -import { ServiceType } from 'app/percona/shared/services/services/Services.types'; -import SidebarStep from 'app/percona/tour/components/SidebarStep'; - -import { Messages } from './product.messages'; -import { getPMMDashboardsStep } from './product.utils'; - -export const getProductTourSteps = ( - isPmmAdmin = true, - settings?: Settings, - activeServices?: ServiceType[] -): TourStep[] => [ - { - selector: '[aria-label="Dashboards"]', - content: ( - -

{Messages.dashboards.browse}

-

{Messages.dashboards.folders}

-

{Messages.dashboards.playlists}

-
- ), - }, - getPMMDashboardsStep(activeServices || []), - { - selector: '[aria-label="Query Analytics (QAN)"]', - content: ( - -

{Messages.qan.queries}

-

{Messages.qan.analyze}

-
- ), - }, - ...(isPmmAdmin - ? [ - { - selector: '[aria-label="Explore"]', - content: ( - -

{Messages.explore.data}

-

{Messages.explore.graphs}

-

{Messages.explore.query}

-
- ), - }, - ] - : []), - { - selector: '[aria-label="Alerting"]', - content: ( - -

- {Messages.alerting.simplerToUse} - {Messages.alerting.admin} - {Messages.alerting.thatWorks} -

-

{Messages.alerting.youDefine}

-

{Messages.alerting.howToUse}

-

- {Messages.alerting.moreInfo} - - {Messages.alerting.docs} - - . -

-
- ), - }, - ...(isPmmAdmin && !!settings?.advisorEnabled - ? [ - { - selector: '[aria-label="Advisors"]', - content: ( - -

{Messages.advisors.pmmIncludes}

-

- {Messages.advisors.findOutMore} - - {Messages.advisors.docs} - - . -

-
- ), - }, - ] - : []), - ...(isPmmAdmin && !!settings?.backupEnabled - ? [ - { - selector: '[aria-label="Backup"]', - content: ( - -

{Messages.backup.feature}

-

{Messages.backup.onDemand}

-

{Messages.backup.shedule}

-
- ), - }, - ] - : []), - ...(isPmmAdmin - ? [ - { - selector: '[aria-label="PMM Configuration"]', - content: ( - -

{Messages.configPanel.services}

-

{Messages.configPanel.settings}

-

- {Messages.configPanel.settingsDocs}{' '} - - {Messages.configPanel.settingsDocsLink} - - . -

-
- ), - }, - { - selector: '[aria-label="Administration"]', - content: ( - -

{Messages.serverAdmin.userManagement}

-
    -
  • {Messages.serverAdmin.addEditRemove}
  • -
  • {Messages.serverAdmin.grant}
  • -
  • {Messages.serverAdmin.manageOrg}
  • -
  • {Messages.serverAdmin.changeOrg}
  • -
-
- ), - }, - ] - : []), -]; - -export default getProductTourSteps; diff --git a/public/app/percona/tour/steps/product/product.utils.tsx b/public/app/percona/tour/steps/product/product.utils.tsx deleted file mode 100644 index 748cc583adeb9..0000000000000 --- a/public/app/percona/tour/steps/product/product.utils.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { TourStep } from 'app/percona/shared/core/reducers/tour'; -import { ServiceType } from 'app/percona/shared/services/services/Services.types'; - -import SidebarStep from '../../components/SidebarStep'; - -import { Messages } from './product.messages'; - -export const getPMMDashboardsStep = (services: ServiceType[]): TourStep => { - if (services.includes(ServiceType.mysql)) { - return getStep('MySQL', 'mysql'); - } else if (services.includes(ServiceType.posgresql)) { - return getStep('PostgreSQL', 'postgre'); - } else if (services.includes(ServiceType.mongodb)) { - return getStep('MongoDB', 'mongo'); - } else if (services.includes(ServiceType.proxysql)) { - return getStep('ProxySQL', 'proxysql'); - } else if (services.includes(ServiceType.haproxy)) { - return getStep('HAProxy', 'haproxy'); - } - - return getStep('Operating System (OS)', 'system'); -}; - -const getStep = (ariaLabel: string, navMenuId: string): TourStep => ({ - selector: '.scrollbar-view [role="dialog"]', - content: ( - -

{Messages.pmmDashboards.grafanaTechnology}

-

{Messages.pmmDashboards.observe}

-

{Messages.pmmDashboards.zoomIn}

-
- ), - navMenuId, - highlightedSelectors: [`[aria-label="${ariaLabel}"]`, '.scrollbar-view [role="dialog"]'], - resizeObservables: ['.scrollbar-view'], - position: 'right', -}); diff --git a/public/sass/_grafana.scss b/public/sass/_grafana.scss index ed1dbbf38463a..3af45726256c5 100644 --- a/public/sass/_grafana.scss +++ b/public/sass/_grafana.scss @@ -23,5 +23,3 @@ body { // ANGULAR @import 'angular'; -// PMM -@import 'components/pmm_tour'; diff --git a/public/sass/components/_pmm_tour.scss b/public/sass/components/_pmm_tour.scss deleted file mode 100644 index 238265142e0ff..0000000000000 --- a/public/sass/components/_pmm_tour.scss +++ /dev/null @@ -1,5 +0,0 @@ -.pmm-tour { - a { - text-decoration: underline; - } -} diff --git a/yarn.lock b/yarn.lock index aa127e261ab31..8a74e8c7124b9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6640,53 +6640,6 @@ __metadata: languageName: node linkType: hard -"@reactour/mask@npm:*": - version: 1.2.0 - resolution: "@reactour/mask@npm:1.2.0" - dependencies: - "@reactour/utils": "npm:*" - peerDependencies: - react: 16.x || 17.x || 18.x || 19.x - checksum: 10/c866cd9bbc269b9eb808f2a71566737df261b72c6db8b67674d4af9059531cd233541ff24f7ac200a9c9a03f7eb0c0fa5dd4d8bf36d50f09b87632902b2101da - languageName: node - linkType: hard - -"@reactour/popover@npm:*": - version: 1.3.0 - resolution: "@reactour/popover@npm:1.3.0" - dependencies: - "@reactour/utils": "npm:*" - peerDependencies: - react: 16.x || 17.x || 18.x || 19.x - checksum: 10/5c4512bf2aeb356c4ed863ba562d54b8a4944196ffa3dec3b866d71f3a0cf085aa34c1637eb76af19c96527005312a8c26357e726a4e083672e7e60e0f10ab93 - languageName: node - linkType: hard - -"@reactour/tour@npm:^3.0.0": - version: 3.8.0 - resolution: "@reactour/tour@npm:3.8.0" - dependencies: - "@reactour/mask": "npm:*" - "@reactour/popover": "npm:*" - "@reactour/utils": "npm:*" - peerDependencies: - react: 16.x || 17.x || 18.x || 19.x - checksum: 10/f3c591900e242610ea3130ddc6c99d589e5f4a26f7f8fad08486276fe6211af6adfad009ee571a43e83ff0764efdf65da60013e6dd04abbb014063427acd3579 - languageName: node - linkType: hard - -"@reactour/utils@npm:*": - version: 0.6.0 - resolution: "@reactour/utils@npm:0.6.0" - dependencies: - "@rooks/use-mutation-observer": "npm:^4.11.2" - resize-observer-polyfill: "npm:^1.5.1" - peerDependencies: - react: 16.x || 17.x || 18.x || 19.x - checksum: 10/84330cac1c68d0ed69b6d57730f9aeda9b412382fed86429f0071380b626aa169a0afd2b57a353c8cd1b540a0c4b85e308085661e608a7dbe162515d66bad98f - languageName: node - linkType: hard - "@reduxjs/toolkit@npm:2.5.1": version: 2.5.1 resolution: "@reduxjs/toolkit@npm:2.5.1" @@ -6944,15 +6897,6 @@ __metadata: languageName: node linkType: hard -"@rooks/use-mutation-observer@npm:^4.11.2": - version: 4.11.2 - resolution: "@rooks/use-mutation-observer@npm:4.11.2" - peerDependencies: - react: ">=16.8.0" - checksum: 10/ae7f8e4f347068acd064a2abe3d69cd674809c1437df942ac73a780ed9675363d167226fc9a30798d3fcd724eab364e1fcc07a37e7744ca5d639f470a853231f - languageName: node - linkType: hard - "@rsdoctor/client@npm:0.4.13": version: 0.4.13 resolution: "@rsdoctor/client@npm:0.4.13" @@ -18116,7 +18060,6 @@ __metadata: "@react-types/menu": "npm:3.9.14" "@react-types/overlays": "npm:3.8.12" "@react-types/shared": "npm:3.27.0" - "@reactour/tour": "npm:^3.0.0" "@reduxjs/toolkit": "npm:2.5.1" "@rsdoctor/webpack-plugin": "npm:^0.4.6" "@rtk-query/codegen-openapi": "npm:^2.0.0" From afb522b9b45266e56134fc71d04c1a1ff9be8089 Mon Sep 17 00:00:00 2001 From: Fabio Silva Date: Thu, 26 Mar 2026 10:33:47 +0000 Subject: [PATCH 2/5] chore: remove changes related to side menu --- packages/grafana-data/src/types/navModel.ts | 6 - .../AppChrome/MegaMenu/MegaMenu.tsx | 3 +- .../AppChrome/MegaMenu/MegaMenuItem.tsx | 40 +--- .../AppChrome/MegaMenu/MegaMenuItemText.tsx | 7 +- .../PerconaBootstrapper.tsx | 2 - .../PerconaNavigation.constants.ts | 4 - .../PerconaNavigation/PerconaNavigation.tsx | 142 ------------ .../PerconaNavigation.utils.ts | 216 ------------------ .../PerconaNavigation/index.ts | 1 - 9 files changed, 7 insertions(+), 414 deletions(-) delete mode 100644 public/app/percona/shared/components/PerconaBootstrapper/PerconaNavigation/PerconaNavigation.tsx delete mode 100644 public/app/percona/shared/components/PerconaBootstrapper/PerconaNavigation/PerconaNavigation.utils.ts diff --git a/packages/grafana-data/src/types/navModel.ts b/packages/grafana-data/src/types/navModel.ts index 264c02ce9fa59..f9ebb23fc075c 100644 --- a/packages/grafana-data/src/types/navModel.ts +++ b/packages/grafana-data/src/types/navModel.ts @@ -40,12 +40,6 @@ export interface NavModelItem extends NavLinkDTO { tabCounter?: number; hideFromBreadcrumbs?: boolean; emptyMessage?: string; - - // @PERCONA - isDivider?: boolean; - isHeading?: boolean; - showChildren?: boolean; - showDot?: boolean; } /** diff --git a/public/app/core/components/AppChrome/MegaMenu/MegaMenu.tsx b/public/app/core/components/AppChrome/MegaMenu/MegaMenu.tsx index 1a26fa75d19db..8d707e5fdeb66 100644 --- a/public/app/core/components/AppChrome/MegaMenu/MegaMenu.tsx +++ b/public/app/core/components/AppChrome/MegaMenu/MegaMenu.tsx @@ -20,8 +20,7 @@ import { MegaMenuItem } from './MegaMenuItem'; import { usePinnedItems } from './hooks'; import { enrichWithInteractionTracking, findByUrl, getActiveItem } from './utils'; -// @PERCONA - increase menu width to fit PMM name -export const MENU_WIDTH = '350px'; +export const MENU_WIDTH = '300px'; export interface Props extends DOMAttributes { onClose: () => void; diff --git a/public/app/core/components/AppChrome/MegaMenu/MegaMenuItem.tsx b/public/app/core/components/AppChrome/MegaMenu/MegaMenuItem.tsx index b695d9a8e0a66..f643f7199d5e2 100644 --- a/public/app/core/components/AppChrome/MegaMenu/MegaMenuItem.tsx +++ b/public/app/core/components/AppChrome/MegaMenu/MegaMenuItem.tsx @@ -7,7 +7,6 @@ import { useLocalStorage } from 'react-use'; import { FeatureState, GrafanaTheme2, NavModelItem, toIconName } from '@grafana/data'; import { useStyles2, Text, IconButton, Icon, Stack, FeatureBadge } from '@grafana/ui'; import { useGrafana } from 'app/core/context/GrafanaContext'; -import { Dot } from 'app/percona/shared/components/Elements/Dot'; import { Indent } from '../../Indent/Indent'; @@ -88,11 +87,7 @@ export function MegaMenuItem({ link, activeItem, level = 0, onClick, onPin, isPi > {level !== 0 && } {level === MAX_DEPTH &&
} -
+
{ @@ -107,30 +102,11 @@ export function MegaMenuItem({ link, activeItem, level = 0, onClick, onPin, isPi
- {/* @PERCONA - show icons for inner items */} - {level <= 1 && link.icon && ( - - <> - 0 && styles.deepIcon)} - name={toIconName(link.icon) ?? 'link'} - size={level === 0 ? 'lg' : 'md'} - /> - {/* @PERCONA */} - {!!link.showDot && } - - - )} - {/* @PERCONA */} -
- {link.text} - {/* @PERCONA */} - {!!link.showDot && !link.icon && } -
+ {level === 0 && iconElement && {iconElement}} + {link.text} {link.isNew && }
@@ -250,14 +226,6 @@ const getStyles = (theme: GrafanaTheme2) => ({ fontStyle: 'italic', padding: theme.spacing(1, 1.5, 1, 7), }), - // @PERCONA - relativeText: css({ - position: 'relative', - }), - // @PERCONA - deepIcon: css({ - marginRight: theme.spacing(-1.5), - }), }); function linkHasChildren(link: NavModelItem): link is NavModelItem & { children: NavModelItem[] } { diff --git a/public/app/core/components/AppChrome/MegaMenu/MegaMenuItemText.tsx b/public/app/core/components/AppChrome/MegaMenu/MegaMenuItemText.tsx index 22f38532bab86..b6d18b50d9dca 100644 --- a/public/app/core/components/AppChrome/MegaMenu/MegaMenuItemText.tsx +++ b/public/app/core/components/AppChrome/MegaMenu/MegaMenuItemText.tsx @@ -7,7 +7,6 @@ import { config } from '@grafana/runtime'; import { Icon, IconButton, Link, useTheme2 } from '@grafana/ui'; import { t } from 'app/core/internationalization'; import { contextSrv } from 'app/core/services/context_srv'; -import { useLinkWithVariables } from 'app/percona/shared/helpers/navigation'; export interface Props { children: React.ReactNode; @@ -23,8 +22,6 @@ export function MegaMenuItemText({ children, isActive, onClick, target, url, onP const theme = useTheme2(); const styles = getStyles(theme, isActive); const LinkComponent = !target && url.startsWith('/') ? Link : 'a'; - // @PERCONA - const urlWithVariables = useLinkWithVariables(url); const linkContent = (
@@ -47,7 +44,7 @@ export function MegaMenuItemText({ children, isActive, onClick, target, url, onP onPin(urlWithVariables)} + onClick={() => onPin(url)} aria-label={ isPinned ? t('navigation.item.remove-bookmark', 'Remove from Bookmarks') diff --git a/public/app/percona/shared/components/PerconaBootstrapper/PerconaBootstrapper.tsx b/public/app/percona/shared/components/PerconaBootstrapper/PerconaBootstrapper.tsx index 47eb61aa2dc94..488d098a3047a 100644 --- a/public/app/percona/shared/components/PerconaBootstrapper/PerconaBootstrapper.tsx +++ b/public/app/percona/shared/components/PerconaBootstrapper/PerconaBootstrapper.tsx @@ -16,7 +16,6 @@ import { isPmmAdmin, isViewer } from '../../helpers/permissions'; import { isPmmNavEnabled } from '../../helpers/plugin'; import { PerconaBootstrapperProps } from './PerconaBootstrapper.types'; -import PerconaNavigation from './PerconaNavigation/PerconaNavigation'; import PerconaUpdateVersion from './PerconaUpdateVersion/PerconaUpdateVersion'; // This component is only responsible for populating the store with Percona's settings initially @@ -70,7 +69,6 @@ export const PerconaBootstrapper = ({ onReady }: PerconaBootstrapperProps) => { return ( <> {isSignedIn && } - {!isPmmNavEnabled() && updateAvailable && showUpdateModal && !isLoadingUpdates && } ); diff --git a/public/app/percona/shared/components/PerconaBootstrapper/PerconaNavigation/PerconaNavigation.constants.ts b/public/app/percona/shared/components/PerconaBootstrapper/PerconaNavigation/PerconaNavigation.constants.ts index d0e02e314a008..fbb3a9753d0c1 100644 --- a/public/app/percona/shared/components/PerconaBootstrapper/PerconaNavigation/PerconaNavigation.constants.ts +++ b/public/app/percona/shared/components/PerconaBootstrapper/PerconaNavigation/PerconaNavigation.constants.ts @@ -104,7 +104,6 @@ export const PMM_UPDATES_LINK: NavModelItem = { url: '/pmm-ui/updates', hideFromTabs: true, target: '_self', - showDot: false, }; export const PMM_HEADING_LINK: NavModelItem = { @@ -346,7 +345,6 @@ export const PMM_NAV_MYSQL: NavModelItem = { text: 'High availability', icon: 'percona-cluster', hideFromTabs: true, - showChildren: true, url: `${config.appSubUrl}/d/mysql-group-replicaset-summary`, children: [ { @@ -453,7 +451,6 @@ export const PMM_NAV_MONGO: NavModelItem = { text: 'High availability', icon: 'percona-cluster', hideFromTabs: true, - showChildren: true, url: `${config.appSubUrl}/d/mongodb-cluster-summary`, children: [ { @@ -530,7 +527,6 @@ export const PMM_NAV_POSTGRE: NavModelItem = { text: 'High availability', icon: 'percona-cluster', hideFromTabs: true, - showChildren: true, url: `${config.appSubUrl}/d/postgresql-replication-overview`, children: [ { diff --git a/public/app/percona/shared/components/PerconaBootstrapper/PerconaNavigation/PerconaNavigation.tsx b/public/app/percona/shared/components/PerconaBootstrapper/PerconaNavigation/PerconaNavigation.tsx deleted file mode 100644 index e7df52a149834..0000000000000 --- a/public/app/percona/shared/components/PerconaBootstrapper/PerconaNavigation/PerconaNavigation.tsx +++ /dev/null @@ -1,142 +0,0 @@ -import { cloneDeep } from 'lodash'; -import { FC, useEffect, useState } from 'react'; - -import { config } from '@grafana/runtime'; -import { contextSrv } from 'app/core/core'; -import { initialState } from 'app/core/reducers/navBarTree'; -import { updateNavIndex } from 'app/core/reducers/navModel'; -import { fetchFolders } from 'app/features/manage-dashboards/state/actions'; -import { updateNavTree } from 'app/percona/shared/core/reducers/navigation'; -import { fetchActiveServiceTypesAction } from 'app/percona/shared/core/reducers/services'; -import { isPmmAdmin, isViewer } from 'app/percona/shared/helpers/permissions'; -import { useAppDispatch } from 'app/store/store'; -import { FolderDTO, useSelector } from 'app/types'; - -import { getCategorizedAdvisors, getPerconaSettings, getServices, getUpdatesInfo } from '../../../core/selectors'; - -import { - ACTIVE_SERVICE_TYPES_CHECK_INTERVAL_MS, - getPmmSettingsPage, - PMM_NAV_QAN, - PMM_ACCESS_ROLES_PAGE, - PMM_ACCESS_ROLE_CREATE_PAGE, - PMM_ACCESS_ROLE_EDIT_PAGE, - PMM_ADD_INSTANCE_PAGE, - PMM_BACKUP_PAGE, - PMM_EDIT_INSTANCE_PAGE, - PMM_INVENTORY_PAGE, - PMM_DUMP_PAGE, - PMM_EXPORT_DUMP_PAGE, -} from './PerconaNavigation.constants'; -import { - addAccessRolesLink, - addDashboardsLinks, - addFolderLinks, - buildAdvisorsNavItem, - buildIntegratedAlertingMenuItem, - buildInventoryAndSettings, - filterByServices, - removeAlertingMenuItem, - sortNavigation, -} from './PerconaNavigation.utils'; - -const PerconaNavigation: FC = () => { - const [folders, setFolders] = useState([]); - const { result } = useSelector(getPerconaSettings); - const { alertingEnabled, advisorEnabled, backupEnabled } = result || {}; - const categorizedAdvisors = useSelector(getCategorizedAdvisors); - const isLoggedIn = !!contextSrv.user.isSignedIn; - const dispatch = useAppDispatch(); - const { activeTypes } = useSelector(getServices); - const advisorsPage = buildAdvisorsNavItem(categorizedAdvisors); - const { updateAvailable } = useSelector(getUpdatesInfo); - - dispatch(updateNavIndex(getPmmSettingsPage(alertingEnabled))); - dispatch(updateNavIndex(PMM_EXPORT_DUMP_PAGE)); - dispatch(updateNavIndex(PMM_BACKUP_PAGE)); - dispatch(updateNavIndex(PMM_INVENTORY_PAGE)); - dispatch(updateNavIndex(PMM_ADD_INSTANCE_PAGE)); - dispatch(updateNavIndex(PMM_EDIT_INSTANCE_PAGE)); - dispatch(updateNavIndex(PMM_ACCESS_ROLE_CREATE_PAGE)); - dispatch(updateNavIndex(PMM_ACCESS_ROLE_EDIT_PAGE)); - dispatch(updateNavIndex(advisorsPage)); - - useEffect(() => { - let interval: NodeJS.Timeout; - - if (isLoggedIn) { - fetchFolders().then(setFolders); - dispatch(fetchActiveServiceTypesAction()); - - interval = setInterval(() => { - dispatch(fetchActiveServiceTypesAction()); - }, ACTIVE_SERVICE_TYPES_CHECK_INTERVAL_MS); - } - - return () => clearInterval(interval); - }, [dispatch, isLoggedIn]); - - useEffect(() => { - const updatedNavTree = cloneDeep(initialState); - - // Add Dashboards - addDashboardsLinks(updatedNavTree); - - // QAN - updatedNavTree.push(PMM_NAV_QAN); - - if (isPmmAdmin(config.bootData.user)) { - // PMM Dump - const help = updatedNavTree.find((i) => i.id === 'help'); - if (help) { - help.children = help.children || []; - help.children.push(PMM_DUMP_PAGE); - - dispatch(updateNavIndex(PMM_DUMP_PAGE)); - dispatch(updateNavIndex(help)); - } - - if (result?.enableAccessControl) { - const cfg = cloneDeep(initialState).find((i) => i.id === 'cfg'); - - // update nav index with the access roles tab - if (cfg) { - addAccessRolesLink(cfg); - dispatch(updateNavIndex(PMM_ACCESS_ROLES_PAGE)); - dispatch(updateNavIndex(cfg)); - } - } - - buildInventoryAndSettings(updatedNavTree, result, updateAvailable); - - if (backupEnabled) { - updatedNavTree.push(PMM_BACKUP_PAGE); - } - } else { - dispatch(updateNavIndex(PMM_ACCESS_ROLES_PAGE)); - } - - const iaMenuItem = alertingEnabled - ? buildIntegratedAlertingMenuItem(updatedNavTree) - : removeAlertingMenuItem(updatedNavTree); - - if (advisorEnabled && !isViewer(config.bootData.user)) { - updatedNavTree.push(advisorsPage); - } - - if (iaMenuItem) { - dispatch(updateNavIndex(iaMenuItem)); - } - - addFolderLinks(updatedNavTree, folders); - - sortNavigation(updatedNavTree); - - dispatch(updateNavTree(filterByServices(updatedNavTree, activeTypes))); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [result, folders, activeTypes, advisorsPage, updateAvailable]); - - return null; -}; - -export default PerconaNavigation; diff --git a/public/app/percona/shared/components/PerconaBootstrapper/PerconaNavigation/PerconaNavigation.utils.ts b/public/app/percona/shared/components/PerconaBootstrapper/PerconaNavigation/PerconaNavigation.utils.ts deleted file mode 100644 index b3e524a5b4ec4..0000000000000 --- a/public/app/percona/shared/components/PerconaBootstrapper/PerconaNavigation/PerconaNavigation.utils.ts +++ /dev/null @@ -1,216 +0,0 @@ -import { NavModelItem } from '@grafana/data'; -import { config } from 'app/core/config'; -import { Settings } from 'app/percona/settings/Settings.types'; -import { isViewer } from 'app/percona/shared/helpers/permissions'; -import { CategorizedAdvisor } from 'app/percona/shared/services/advisors/Advisors.types'; -import { ServiceType } from 'app/percona/shared/services/services/Services.types'; -import { FolderDTO } from 'app/types'; - -import { - NAV_FOLDER_MAP, - PMM_NAV_HAPROXY, - NAV_ID_TO_SERVICE, - PMM_NAV_MONGO, - PMM_NAV_MYSQL, - PMM_NAV_POSTGRE, - PMM_NAV_PROXYSQL, - PMM_NAV_OS, - PMM_ACCESS_ROLES_PAGE, - PMM_ADD_INSTANCE_PAGE, - WEIGHTS, - PMM_ACCESS_ROLE_CREATE_PAGE, - PMM_ADD_INSTANCE_CREATE_PAGE, - getPmmSettingsPage, - PMM_INVENTORY_PAGE, - PMM_UPDATES_LINK, - PMM_ALERTING_FIRED_ALERTS, - PMM_ALERTING_PERCONA_ALERTS, - PMM_NAV_VALKEY, -} from './PerconaNavigation.constants'; - -export const buildIntegratedAlertingMenuItem = (mainLinks: NavModelItem[]): NavModelItem | undefined => { - const alertingItem = mainLinks.find(({ id }) => id === 'alerting'); - - if (alertingItem?.url) { - alertingItem.url = `${config.appSubUrl}/alerting/alerts`; - } - - if (isViewer(config.bootData.user)) { - alertingItem?.children?.unshift(PMM_ALERTING_FIRED_ALERTS); - } else { - alertingItem?.children?.unshift(...PMM_ALERTING_PERCONA_ALERTS); - } - - return alertingItem; -}; - -export const removeAlertingMenuItem = (mainLinks: NavModelItem[]) => { - const alertingItem = mainLinks.find(({ id }) => id === 'alerting'); - - PMM_ALERTING_PERCONA_ALERTS.forEach((alertingTab, idx) => { - const item = alertingItem?.children?.find((c) => c.id === alertingTab.id); - - if (item) { - alertingItem?.children?.splice(idx, 1); - } - }); - - if (alertingItem?.url) { - alertingItem.url = `${config.appSubUrl}/alerting/list`; - } - - return alertingItem; -}; - -export const buildInventoryAndSettings = ( - mainLinks: NavModelItem[], - settings?: Settings, - updateAvailable?: boolean -): NavModelItem[] => { - const inventoryLink: NavModelItem = PMM_INVENTORY_PAGE; - const orgLink: NavModelItem = { - id: 'main-organization', - text: 'Organization', - isSection: true, - }; - const settingsLink: NavModelItem = getPmmSettingsPage(); - const configNode = mainLinks.find((link) => link.id === 'cfg'); - const pmmConfigNode = mainLinks.find((link) => link.id === 'pmmcfg'); - - if (!pmmConfigNode) { - const updatesLink = { - ...PMM_UPDATES_LINK, - showDot: updateAvailable, - }; - const pmmcfgNode: NavModelItem = { - id: 'pmmcfg', - text: 'PMM Configuration', - icon: 'percona-nav-logo', - url: `${config.appSubUrl}/inventory`, - subTitle: 'Configuration', - children: [PMM_ADD_INSTANCE_PAGE, PMM_ADD_INSTANCE_CREATE_PAGE, inventoryLink, settingsLink, updatesLink], - sortWeight: -600, - showDot: updateAvailable, - }; - mainLinks.push(pmmcfgNode); - } - - if (!configNode) { - const cfgNode: NavModelItem = { - id: 'cfg', - text: 'Configuration', - icon: 'cog', - url: `${config.appSubUrl}/admin`, - subTitle: 'Configuration', - children: [], - }; - if (settings?.enableAccessControl) { - addAccessRolesLink(cfgNode); - } - mainLinks.push(cfgNode); - } else { - if (!configNode.children) { - configNode.children = []; - } - if (configNode.subTitle) { - orgLink.text = configNode.subTitle || ''; - configNode.subTitle = ''; - } - configNode.url = `${config.appSubUrl}/admin`; - if (settings?.enableAccessControl) { - addAccessRolesLink(configNode); - } - } - - return mainLinks; -}; - -export const addAccessRolesLink = (configNode: NavModelItem) => { - if (configNode.children) { - const accessNode = configNode.children.find((item) => item.id === 'cfg/access'); - - if (accessNode && accessNode.children) { - const usersIdx = accessNode.children.findIndex((item) => item.id === 'global-users'); - accessNode.children = [ - ...accessNode.children.slice(0, usersIdx + 1), - PMM_ACCESS_ROLES_PAGE, - // Add to have a create action for adding a role - PMM_ACCESS_ROLE_CREATE_PAGE, - ...accessNode.children.slice(usersIdx + 1), - ]; - } - } -}; - -export const addFolderLinks = (navTree: NavModelItem[], folders: FolderDTO[]) => { - for (const rootNode of navTree) { - const id = rootNode.id + '-other-dashboards'; - const folder = folders.find((f) => rootNode.id && NAV_FOLDER_MAP[rootNode.id] === f.title); - const exists = rootNode.children?.some((i) => i.id === id); - - if (folder && !exists) { - rootNode.children?.push({ - id, - icon: 'search', - text: 'Other dashboards', - url: `/graph/dashboards/f/${folder.uid}/${rootNode.id}`, - }); - } - } -}; - -export const filterByServices = (navTree: NavModelItem[], activeServices: ServiceType[]): NavModelItem[] => { - const showNavLink = (node: NavModelItem) => { - if (node.id) { - const serviceType = NAV_ID_TO_SERVICE[node.id]; - return !serviceType || activeServices.some((s) => s === serviceType); - } - - return true; - }; - - return navTree.filter(showNavLink); -}; - -export const buildAdvisorsNavItem = (categorizedAdvisors: CategorizedAdvisor) => { - const modelItem: NavModelItem = { - id: `advisors`, - icon: 'percona-database-checks', - text: 'Advisors', - sortWeight: WEIGHTS.alerting, - subTitle: 'Run and analyze all checks', - url: `${config.appSubUrl}/advisors`, - children: [], - }; - const categories = Object.keys(categorizedAdvisors); - - modelItem.children!.push({ - id: 'advisors-insights', - text: 'Advisor Insights', - url: `${config.appSubUrl}/advisors/insights`, - }); - - categories.forEach((category) => { - modelItem.children!.push({ - id: `advisors-${category}`, - text: `${category[0].toUpperCase()}${category.substring(1)} Advisors`, - url: `${config.appSubUrl}/advisors/${category}`, - }); - }); - - return modelItem; -}; - -export const addDashboardsLinks = (items: NavModelItem[]) => { - items.push(PMM_NAV_OS); - items.push(PMM_NAV_MYSQL); - items.push(PMM_NAV_MONGO); - items.push(PMM_NAV_POSTGRE); - items.push(PMM_NAV_PROXYSQL); - items.push(PMM_NAV_HAPROXY); - items.push(PMM_NAV_VALKEY); -}; - -export const sortNavigation = (items: NavModelItem[]) => { - items.sort((a, b) => (a.sortWeight || 0) - (b.sortWeight || 0)); -}; diff --git a/public/app/percona/shared/components/PerconaBootstrapper/PerconaNavigation/index.ts b/public/app/percona/shared/components/PerconaBootstrapper/PerconaNavigation/index.ts index d1560932ad44e..f513700d21794 100644 --- a/public/app/percona/shared/components/PerconaBootstrapper/PerconaNavigation/index.ts +++ b/public/app/percona/shared/components/PerconaBootstrapper/PerconaNavigation/index.ts @@ -1,2 +1 @@ -export * from './PerconaNavigation'; export * from './PerconaNavigation.constants'; From 0a90e5a03a6be20dd572be9ffe0cc4249661c0fa Mon Sep 17 00:00:00 2001 From: Fabio Silva Date: Thu, 26 Mar 2026 11:16:39 +0000 Subject: [PATCH 3/5] chore: remove percona code on NewsDrawer --- .../app/core/components/AppChrome/News/NewsDrawer.tsx | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/public/app/core/components/AppChrome/News/NewsDrawer.tsx b/public/app/core/components/AppChrome/News/NewsDrawer.tsx index 4845619988aef..7211823430d63 100644 --- a/public/app/core/components/AppChrome/News/NewsDrawer.tsx +++ b/public/app/core/components/AppChrome/News/NewsDrawer.tsx @@ -4,6 +4,7 @@ import { GrafanaTheme2 } from '@grafana/data'; import { selectors } from '@grafana/e2e-selectors'; import { IconButton, Drawer, useStyles2, Text } from '@grafana/ui'; import { t } from 'app/core/internationalization'; +import { DEFAULT_FEED_URL } from 'app/plugins/panel/news/constants'; import { NewsWrapper } from './NewsWrapper'; @@ -20,15 +21,14 @@ export function NewsContainer({ onClose }: NewsContainerProps) { title={
{t('news.title', 'Latest from the blog')} - {/* @PERCONA - point to percona blog */} - Percona logo + Grot reading news
- {/* @PERCONA */} - + ); } From 21224e8ee099ca54df8e90a6b4343ef97b22ee1a Mon Sep 17 00:00:00 2001 From: Fabio Silva Date: Thu, 26 Mar 2026 14:37:15 +0000 Subject: [PATCH 4/5] chore: remove further unused code --- .../PerconaBootstrapper.tsx | 3 +- .../app/percona/shared/helpers/navigation.ts | 48 ------------------- 2 files changed, 2 insertions(+), 49 deletions(-) delete mode 100644 public/app/percona/shared/helpers/navigation.ts diff --git a/public/app/percona/shared/components/PerconaBootstrapper/PerconaBootstrapper.tsx b/public/app/percona/shared/components/PerconaBootstrapper/PerconaBootstrapper.tsx index 488d098a3047a..006ea720a8480 100644 --- a/public/app/percona/shared/components/PerconaBootstrapper/PerconaBootstrapper.tsx +++ b/public/app/percona/shared/components/PerconaBootstrapper/PerconaBootstrapper.tsx @@ -3,7 +3,7 @@ import { useEffect } from 'react'; import { config } from '@grafana/runtime'; import { fetchSettingsAction } from 'app/percona/shared/core/reducers'; import { fetchAdvisors } from 'app/percona/shared/core/reducers/advisors/advisors'; -import { setAuthorized } from 'app/percona/shared/core/reducers/user/user'; +import { fetchUserDetailsAction, setAuthorized } from 'app/percona/shared/core/reducers/user/user'; import { getUpdatesInfo } from 'app/percona/shared/core/selectors'; import { useAppDispatch } from 'app/store/store'; import { useSelector } from 'app/types'; @@ -55,6 +55,7 @@ export const PerconaBootstrapper = ({ onReady }: PerconaBootstrapperProps) => { } } + await dispatch(fetchUserDetailsAction()); await dispatch(fetchHighAvailabilityStatus()); onReady(); }; diff --git a/public/app/percona/shared/helpers/navigation.ts b/public/app/percona/shared/helpers/navigation.ts deleted file mode 100644 index 9cfcdcf7caa16..0000000000000 --- a/public/app/percona/shared/helpers/navigation.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { getLinkSrv } from 'app/features/panel/panellinks/link_srv'; - -export const useLinkWithVariables = (url?: string) => { - if (url && isDashboardUrl(url) && isDashboardUrl(window.location.pathname)) { - const urlWithLinks = getLinkSrv().getLinkUrl({ - url: url, - keepTime: true, - // Check if the DB type matches the current one used - includeVars: checkDbType(url), - asDropdown: false, - icon: '', - tags: [], - targetBlank: false, - title: '', - tooltip: '', - type: 'link', - }); - return cleanupVariables(urlWithLinks); - } else { - return url ? url : '#'; - } -}; - -const isDashboardUrl = (url?: string) => url?.includes('/d/'); - -const checkDbType = (url: string): boolean => { - const currentDB = window.location.pathname?.split('/')[3]?.split('-')[0]; - const urlDB = url?.split('/')[3]?.split('-')[0]; - - // enable variable sharing between same db types and db type -> os/node - return (currentDB !== undefined && currentDB === urlDB) || urlDB === 'node'; -}; - -const cleanupVariables = (urlWithLinks: string) => { - const [base, params] = urlWithLinks.split('?'); - - if (params) { - // remove variables which have the All value or the value is empty - const variables = params - .split('&') - .filter((param) => !(param.includes('All') || param.endsWith('='))) - .join('&'); - - return base + '?' + variables; - } - - return base; -}; From 1c8bc4ebfb2bec678635290bae51f471df918f3f Mon Sep 17 00:00:00 2001 From: Fabio Silva Date: Mon, 30 Mar 2026 10:45:28 +0100 Subject: [PATCH 5/5] chore: prettier --- public/app/AppWrapper.tsx | 32 +++++++++---------- .../components/AppChrome/AppChromeMenu.tsx | 1 - .../percona/shared/core/reducers/user/user.ts | 1 - public/sass/_grafana.scss | 1 - 4 files changed, 16 insertions(+), 19 deletions(-) diff --git a/public/app/AppWrapper.tsx b/public/app/AppWrapper.tsx index c0141ff24552c..c2fe6ed8c83ef 100644 --- a/public/app/AppWrapper.tsx +++ b/public/app/AppWrapper.tsx @@ -127,22 +127,22 @@ export class AppWrapper extends Component { actions={[]} options={{ enableHistory: true, callbacks: { onSelectAction: commandPaletteActionSelected } }} > - - - - -
- {config.featureToggles.appSidecar ? ( - - ) : ( - - )} - - -
-
-
-
+ + + + +
+ {config.featureToggles.appSidecar ? ( + + ) : ( + + )} + + +
+
+
+
diff --git a/public/app/core/components/AppChrome/AppChromeMenu.tsx b/public/app/core/components/AppChrome/AppChromeMenu.tsx index 66afe19ebc664..b1010d95052c8 100644 --- a/public/app/core/components/AppChrome/AppChromeMenu.tsx +++ b/public/app/core/components/AppChrome/AppChromeMenu.tsx @@ -27,7 +27,6 @@ export function AppChromeMenu({}: Props) { const isOpen = state.megaMenuOpen && !state.megaMenuDocked; const onClose = () => chrome.setMegaMenuOpen(false); - const { overlayProps, underlayProps } = useOverlay( { isDismissable: true, diff --git a/public/app/percona/shared/core/reducers/user/user.ts b/public/app/percona/shared/core/reducers/user/user.ts index a7a4bb5f69b5a..bc59b9fbf93bb 100644 --- a/public/app/percona/shared/core/reducers/user/user.ts +++ b/public/app/percona/shared/core/reducers/user/user.ts @@ -36,7 +36,6 @@ export const fetchUserDetailsAction = createAsyncThunk( } ); - export const setSnoozedVersion = createAsyncThunk( 'percona/setSnoozedVersion', async (version: string, thunkAPI): Promise => { diff --git a/public/sass/_grafana.scss b/public/sass/_grafana.scss index 3af45726256c5..480b73ee71e59 100644 --- a/public/sass/_grafana.scss +++ b/public/sass/_grafana.scss @@ -22,4 +22,3 @@ body { // ANGULAR @import 'angular'; -