Plugins: Disable update button when cloud install is not completed (#81716)

This commit is contained in:
Hugo Kiyodi Oshiro 2024-02-19 09:38:06 +01:00 committed by GitHub
parent 1aff748e8f
commit dcc977005c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 98 additions and 7 deletions

View File

@ -4,7 +4,9 @@ import { TestProvider } from 'test/helpers/TestProvider';
import { PluginSignatureStatus } from '@grafana/data';
import { config } from '@grafana/runtime';
import { configureStore } from 'app/store/configureStore';
import { getPluginsStateMock } from '../../__mocks__';
import { CatalogPlugin, PluginStatus } from '../../types';
import { InstallControlsButton } from './InstallControlsButton';
@ -91,4 +93,79 @@ describe('InstallControlsButton', () => {
);
expect(screen.queryByRole('button')).not.toBeInTheDocument();
});
describe('update button on prem', () => {
const store = configureStore({
plugins: getPluginsStateMock([]),
});
it('should be disabled when is Installing', () => {
store.dispatch({ type: 'plugins/install/pending' });
render(
<TestProvider store={store}>
<InstallControlsButton plugin={{ ...plugin }} pluginStatus={PluginStatus.UPDATE} />
</TestProvider>
);
const button = screen.getByText('Updating').closest('button');
expect(button).toBeDisabled();
});
it('should be enabled when it is not Installing', () => {
store.dispatch({ type: 'plugins/install/fulfilled', payload: { id: '', changes: {} } });
render(
<TestProvider store={store}>
<InstallControlsButton plugin={{ ...plugin }} pluginStatus={PluginStatus.UPDATE} />
</TestProvider>
);
const button = screen.getByText('Update').closest('button');
expect(button).toBeEnabled();
});
});
describe('update button on managed instance', () => {
const oldFeatureTogglesManagedPluginsInstall = config.featureToggles.managedPluginsInstall;
const oldPluginAdminExternalManageEnabled = config.pluginAdminExternalManageEnabled;
beforeAll(() => {
config.featureToggles.managedPluginsInstall = true;
config.pluginAdminExternalManageEnabled = true;
});
afterAll(() => {
config.featureToggles.managedPluginsInstall = oldFeatureTogglesManagedPluginsInstall;
config.pluginAdminExternalManageEnabled = oldPluginAdminExternalManageEnabled;
});
const store = configureStore({
plugins: getPluginsStateMock([]),
});
it('should be disabled when isInstalling=false but isUpdatingFromInstance=true', () => {
store.dispatch({ type: 'plugins/install/fulfilled', payload: { id: '', changes: {} } });
render(
<TestProvider store={store}>
<InstallControlsButton
plugin={{ ...plugin, isUpdatingFromInstance: true }}
pluginStatus={PluginStatus.UPDATE}
/>
</TestProvider>
);
const button = screen.getByText('Update').closest('button');
expect(button).toBeDisabled();
});
it('should be enabled when isInstalling=false and isUpdatingFromInstance=false', () => {
store.dispatch({ type: 'plugins/install/fulfilled', payload: { id: '', changes: {} } });
render(
<TestProvider store={store}>
<InstallControlsButton
plugin={{ ...plugin, isUpdatingFromInstance: false }}
pluginStatus={PluginStatus.UPDATE}
/>
</TestProvider>
);
const button = screen.getByText('Update').closest('button');
expect(button).toBeEnabled();
});
});
});

View File

@ -140,9 +140,14 @@ export function InstallControlsButton({
}
if (pluginStatus === PluginStatus.UPDATE) {
const disableUpdate =
config.pluginAdminExternalManageEnabled && configCore.featureToggles.managedPluginsInstall
? plugin.isUpdatingFromInstance
: isInstalling;
return (
<HorizontalGroup align="flex-start" width="auto" height="auto">
<Button disabled={isInstalling} onClick={onUpdate}>
<Button disabled={disableUpdate} onClick={onUpdate}>
{isInstalling ? 'Updating' : 'Update'}
</Button>
<Button variant="destructive" disabled={isUninstalling} onClick={onUninstall}>

View File

@ -23,10 +23,10 @@ export function mergeLocalsAndRemotes({
const catalogPlugins: CatalogPlugin[] = [];
const errorByPluginId = groupErrorsByPluginId(errors);
const instancesSet = instance.reduce((set, instancePlugin) => {
set.add(instancePlugin.pluginSlug);
return set;
}, new Set<string>());
const instancesMap = instance.reduce((map, instancePlugin) => {
map.set(instancePlugin.pluginSlug, instancePlugin);
return map;
}, new Map<string, InstancePlugin>());
// add locals
local.forEach((localPlugin) => {
@ -51,8 +51,15 @@ export function mergeLocalsAndRemotes({
if (configCore.featureToggles.managedPluginsInstall && config.pluginAdminExternalManageEnabled) {
catalogPlugin.isFullyInstalled = catalogPlugin.isCore
? true
: instancesSet.has(remotePlugin.slug) && catalogPlugin.isInstalled;
catalogPlugin.isInstalled = instancesSet.has(remotePlugin.slug) || catalogPlugin.isInstalled;
: instancesMap.has(remotePlugin.slug) && catalogPlugin.isInstalled;
catalogPlugin.isInstalled = instancesMap.has(remotePlugin.slug) || catalogPlugin.isInstalled;
const instancePlugin = instancesMap.get(remotePlugin.slug);
catalogPlugin.isUpdatingFromInstance =
instancesMap.has(remotePlugin.slug) &&
catalogPlugin.hasUpdate &&
catalogPlugin.installedVersion !== instancePlugin?.version;
}
catalogPlugins.push(catalogPlugin);

View File

@ -62,6 +62,7 @@ export interface CatalogPlugin extends WithAccessControlMetadata {
// instance plugins may not be fully installed, which means a new instance
// running the plugin didn't started yet
isFullyInstalled?: boolean;
isUpdatingFromInstance?: boolean;
iam?: IdentityAccessManagement;
}
@ -318,4 +319,5 @@ export type PluginVersion = {
export type InstancePlugin = {
pluginSlug: string;
version: string;
};