diff --git a/public/app/core/reducers/navBarTree.ts b/public/app/core/reducers/navBarTree.ts
index 49951bd181b..d5fba3cd666 100644
--- a/public/app/core/reducers/navBarTree.ts
+++ b/public/app/core/reducers/navBarTree.ts
@@ -63,8 +63,15 @@ const navTreeSlice = createSlice({
}
}
},
+ removePluginFromNavTree: (state, action: PayloadAction<{ pluginID: string }>) => {
+ const navID = 'plugin-page-' + action.payload.pluginID;
+ const pluginItemIndex = state.findIndex((navItem) => navItem.id === navID);
+ if (pluginItemIndex > -1) {
+ state.splice(pluginItemIndex, 1);
+ }
+ },
},
});
-export const { setStarred, updateDashboardName } = navTreeSlice.actions;
+export const { setStarred, removePluginFromNavTree, updateDashboardName } = navTreeSlice.actions;
export const navTreeReducer = navTreeSlice.reducer;
diff --git a/public/app/features/plugins/admin/components/InstallControls/InstallControlsButton.tsx b/public/app/features/plugins/admin/components/InstallControls/InstallControlsButton.tsx
index cf7ad12181f..c79e754c0a9 100644
--- a/public/app/features/plugins/admin/components/InstallControls/InstallControlsButton.tsx
+++ b/public/app/features/plugins/admin/components/InstallControls/InstallControlsButton.tsx
@@ -6,6 +6,8 @@ import { locationService } from '@grafana/runtime';
import { Button, HorizontalGroup, ConfirmModal } from '@grafana/ui';
import appEvents from 'app/core/app_events';
import { useQueryParams } from 'app/core/hooks/useQueryParams';
+import { removePluginFromNavTree } from 'app/core/reducers/navBarTree';
+import { useDispatch } from 'app/types';
import { useInstallStatus, useUninstallStatus, useInstall, useUninstall } from '../../state/hooks';
import { trackPluginInstalled, trackPluginUninstalled } from '../../tracking';
@@ -15,9 +17,16 @@ type InstallControlsButtonProps = {
plugin: CatalogPlugin;
pluginStatus: PluginStatus;
latestCompatibleVersion?: Version;
+ setNeedReload: (needReload: boolean) => void;
};
-export function InstallControlsButton({ plugin, pluginStatus, latestCompatibleVersion }: InstallControlsButtonProps) {
+export function InstallControlsButton({
+ plugin,
+ pluginStatus,
+ latestCompatibleVersion,
+ setNeedReload,
+}: InstallControlsButtonProps) {
+ const dispatch = useDispatch();
const [queryParams] = useQueryParams();
const location = useLocation();
const { isInstalling, error: errorInstalling } = useInstallStatus();
@@ -39,6 +48,9 @@ export function InstallControlsButton({ plugin, pluginStatus, latestCompatibleVe
await install(plugin.id, latestCompatibleVersion?.version);
if (!errorInstalling) {
appEvents.emit(AppEvents.alertSuccess, [`Installed ${plugin.name}`]);
+ if (plugin.type === 'app') {
+ setNeedReload(true);
+ }
}
};
@@ -54,6 +66,10 @@ export function InstallControlsButton({ plugin, pluginStatus, latestCompatibleVe
locationService.replace(`${location.pathname}?page=${PluginTabIds.OVERVIEW}`);
}
appEvents.emit(AppEvents.alertSuccess, [`Uninstalled ${plugin.name}`]);
+ if (plugin.type === 'app') {
+ dispatch(removePluginFromNavTree({ pluginID: plugin.id }));
+ setNeedReload(false);
+ }
}
};
diff --git a/public/app/features/plugins/admin/components/PluginActions.tsx b/public/app/features/plugins/admin/components/PluginActions.tsx
index 6819da2b6e0..055050ef066 100644
--- a/public/app/features/plugins/admin/components/PluginActions.tsx
+++ b/public/app/features/plugins/admin/components/PluginActions.tsx
@@ -1,6 +1,9 @@
-import React from 'react';
+import { css } from '@emotion/css';
+import React, { useState } from 'react';
+import { GrafanaTheme2 } from '@grafana/data';
import { config } from '@grafana/runtime';
+import { HorizontalGroup, Icon, useStyles2, VerticalGroup } from '@grafana/ui';
import { GetStartedWithPlugin } from '../components/GetStartedWithPlugin';
import { InstallControlsButton } from '../components/InstallControls';
@@ -14,8 +17,10 @@ interface Props {
}
export const PluginActions = ({ plugin }: Props) => {
+ const styles = useStyles2(getStyles);
const isRemotePluginsAvailable = useIsRemotePluginsAvailable();
const latestCompatibleVersion = getLatestCompatibleVersion(plugin?.details?.versions);
+ const [needReload, setNeedReload] = useState(false);
if (!plugin) {
return null;
@@ -32,21 +37,38 @@ export const PluginActions = ({ plugin }: Props) => {
plugin.isCore || plugin.isDisabled || !isInstallControlsEnabled() || hasInstallWarning;
return (
- <>
- {!isInstallControlsDisabled && (
- <>
- {isExternallyManaged ? (
-
- ) : (
-
- )}
- >
+
+
+ {!isInstallControlsDisabled && (
+ <>
+ {isExternallyManaged ? (
+
+ ) : (
+
+ )}
+ >
+ )}
+
+
+ {needReload && (
+
+
+ Refresh the page to see the changes
+
)}
-
- >
+
);
};
+
+const getStyles = (theme: GrafanaTheme2) => {
+ return {
+ message: css`
+ color: ${theme.colors.text.secondary};
+ `,
+ };
+};