Plugins: Remove managedPluginsInstall feature toggle (#100416)
* Plugins: Remove managedPluginsInstall feature toggle Co-authored-by: Will Browne <wbrowne@users.noreply.github.com>
This commit is contained in:
co-authored by
Will Browne
parent
39b424b8a7
commit
29afe7d2cc
@@ -49,7 +49,6 @@ Most [generally available](https://grafana.com/docs/release-life-cycle/#general-
|
||||
| `kubernetesPlaylists` | Use the kubernetes API in the frontend for playlists, and route /api/playlist requests to k8s | Yes |
|
||||
| `recoveryThreshold` | Enables feature recovery threshold (aka hysteresis) for threshold server-side expression | Yes |
|
||||
| `lokiStructuredMetadata` | Enables the loki data source to request structured metadata from the Loki server | Yes |
|
||||
| `managedPluginsInstall` | Install managed plugins directly from plugins catalog | Yes |
|
||||
| `addFieldFromCalculationStatFunctions` | Add cumulative and window functions to the add field from calculation transformation | Yes |
|
||||
| `annotationPermissionUpdate` | Change the way annotation permissions work by scoping them to folders and dashboards. | Yes |
|
||||
| `dashboardSceneForViewers` | Enables dashboard rendering using Scenes for viewer roles | Yes |
|
||||
|
||||
@@ -120,7 +120,6 @@ export interface FeatureToggles {
|
||||
lokiStructuredMetadata?: boolean;
|
||||
teamHttpHeaders?: boolean;
|
||||
cachingOptimizeSerializationMemoryUsage?: boolean;
|
||||
managedPluginsInstall?: boolean;
|
||||
prometheusPromQAIL?: boolean;
|
||||
prometheusCodeModeMetricNamesSearch?: boolean;
|
||||
addFieldFromCalculationStatFunctions?: boolean;
|
||||
|
||||
+1
-1
@@ -424,7 +424,7 @@ func (hs *HTTPServer) registerRoutes() {
|
||||
apiRoute.Any("/plugin-proxy/:pluginId/*", requestmeta.SetSLOGroup(requestmeta.SLOGroupHighSlow), authorize(ac.EvalPermission(pluginaccesscontrol.ActionAppAccess, pluginIDScope)), checkAppEnabled(hs.pluginStore, hs.PluginSettings), hs.ProxyPluginRequest)
|
||||
apiRoute.Any("/plugin-proxy/:pluginId", requestmeta.SetSLOGroup(requestmeta.SLOGroupHighSlow), authorize(ac.EvalPermission(pluginaccesscontrol.ActionAppAccess, pluginIDScope)), checkAppEnabled(hs.pluginStore, hs.PluginSettings), hs.ProxyPluginRequest)
|
||||
|
||||
if hs.Cfg.PluginAdminEnabled && (hs.Features.IsEnabledGlobally(featuremgmt.FlagManagedPluginsInstall) || !hs.Cfg.PluginAdminExternalManageEnabled) {
|
||||
if hs.Cfg.PluginAdminEnabled {
|
||||
apiRoute.Group("/plugins", func(pluginRoute routing.RouteRegister) {
|
||||
pluginRoute.Post("/:pluginId/install", authorizeInOrg(ac.UseGlobalOrSingleOrg(hs.Cfg), ac.EvalPermission(pluginaccesscontrol.ActionInstall)), routing.Wrap(hs.InstallPlugin))
|
||||
pluginRoute.Post("/:pluginId/uninstall", authorizeInOrg(ac.UseGlobalOrSingleOrg(hs.Cfg), ac.EvalPermission(pluginaccesscontrol.ActionInstall)), routing.Wrap(hs.UninstallPlugin))
|
||||
|
||||
@@ -73,7 +73,7 @@ func Test_PluginsInstallAndUninstall(t *testing.T) {
|
||||
preInstalledPlugin bool
|
||||
}
|
||||
tcs := []testCase{
|
||||
{expectedCode: http.StatusNotFound, permissionOrg: globalOrg, permissions: canInstall, pluginAdminEnabled: true, pluginAdminExternalManageEnabled: true},
|
||||
{expectedCode: http.StatusOK, permissionOrg: globalOrg, permissions: canInstall, pluginAdminEnabled: true, pluginAdminExternalManageEnabled: true},
|
||||
{expectedCode: http.StatusNotFound, permissionOrg: globalOrg, permissions: canInstall, pluginAdminEnabled: false, pluginAdminExternalManageEnabled: true},
|
||||
{expectedCode: http.StatusNotFound, permissionOrg: globalOrg, permissions: canInstall, pluginAdminEnabled: false, pluginAdminExternalManageEnabled: false},
|
||||
{expectedCode: http.StatusForbidden, permissionOrg: globalOrg, permissions: cannotInstall, pluginAdminEnabled: true, pluginAdminExternalManageEnabled: false},
|
||||
|
||||
@@ -765,14 +765,6 @@ var (
|
||||
Owner: grafanaOperatorExperienceSquad,
|
||||
FrontendOnly: false,
|
||||
},
|
||||
{
|
||||
Name: "managedPluginsInstall",
|
||||
Description: "Install managed plugins directly from plugins catalog",
|
||||
Stage: FeatureStageGeneralAvailability,
|
||||
RequiresDevMode: false,
|
||||
Owner: grafanaPluginsPlatformSquad,
|
||||
Expression: "true", // enabled by default
|
||||
},
|
||||
{
|
||||
Name: "prometheusPromQAIL",
|
||||
Description: "Prometheus and AI/ML to assist users in creating a query",
|
||||
|
||||
@@ -101,7 +101,6 @@ recoveryThreshold,GA,@grafana/alerting-squad,false,true,false
|
||||
lokiStructuredMetadata,GA,@grafana/observability-logs,false,false,false
|
||||
teamHttpHeaders,preview,@grafana/identity-access-team,false,false,false
|
||||
cachingOptimizeSerializationMemoryUsage,experimental,@grafana/grafana-operator-experience-squad,false,false,false
|
||||
managedPluginsInstall,GA,@grafana/plugins-platform-backend,false,false,false
|
||||
prometheusPromQAIL,experimental,@grafana/oss-big-tent,false,false,true
|
||||
prometheusCodeModeMetricNamesSearch,experimental,@grafana/oss-big-tent,false,false,true
|
||||
addFieldFromCalculationStatFunctions,GA,@grafana/dataviz-squad,false,false,true
|
||||
|
||||
|
@@ -415,10 +415,6 @@ const (
|
||||
// If enabled, the caching backend gradually serializes query responses for the cache, comparing against the configured `[caching]max_value_mb` value as it goes. This can can help prevent Grafana from running out of memory while attempting to cache very large query responses.
|
||||
FlagCachingOptimizeSerializationMemoryUsage = "cachingOptimizeSerializationMemoryUsage"
|
||||
|
||||
// FlagManagedPluginsInstall
|
||||
// Install managed plugins directly from plugins catalog
|
||||
FlagManagedPluginsInstall = "managedPluginsInstall"
|
||||
|
||||
// FlagPrometheusPromQAIL
|
||||
// Prometheus and AI/ML to assist users in creating a query
|
||||
FlagPrometheusPromQAIL = "prometheusPromQAIL"
|
||||
|
||||
@@ -2651,6 +2651,7 @@
|
||||
"name": "managedPluginsInstall",
|
||||
"resourceVersion": "1720021873452",
|
||||
"creationTimestamp": "2023-10-18T13:17:03Z",
|
||||
"deletionTimestamp": "2025-02-11T11:13:57Z",
|
||||
"annotations": {
|
||||
"grafana.app/updatedTimestamp": "2024-07-03 15:51:13.452477 +0000 UTC"
|
||||
}
|
||||
|
||||
@@ -82,8 +82,7 @@ func DeclareRBACRoles(service ac.Service, cfg *setting.Cfg, features featuremgmt
|
||||
Grants: []string{ac.RoleGrafanaAdmin},
|
||||
}
|
||||
|
||||
if !cfg.PluginAdminEnabled ||
|
||||
(cfg.PluginAdminExternalManageEnabled && !features.IsEnabledGlobally(featuremgmt.FlagManagedPluginsInstall)) {
|
||||
if !cfg.PluginAdminEnabled {
|
||||
PluginsMaintainer.Grants = []string{}
|
||||
}
|
||||
|
||||
|
||||
+2
-5
@@ -37,10 +37,8 @@ const plugin: CatalogPlugin = {
|
||||
};
|
||||
|
||||
describe('GetStartedWithDataSource', () => {
|
||||
const oldFeatureTogglesManagedPluginsInstall = config.featureToggles.managedPluginsInstall;
|
||||
const oldPluginAdminExternalManageEnabled = config.pluginAdminExternalManageEnabled;
|
||||
|
||||
config.featureToggles.managedPluginsInstall = true;
|
||||
config.pluginAdminExternalManageEnabled = true;
|
||||
|
||||
const contextSrv = new ContextSrv();
|
||||
@@ -51,11 +49,10 @@ describe('GetStartedWithDataSource', () => {
|
||||
setContextSrv(contextSrv);
|
||||
|
||||
afterAll(() => {
|
||||
config.featureToggles.managedPluginsInstall = oldFeatureTogglesManagedPluginsInstall;
|
||||
config.pluginAdminExternalManageEnabled = oldPluginAdminExternalManageEnabled;
|
||||
});
|
||||
|
||||
it('should disable button when managedPluginsInstall and pluginAdminExternalManaged are enabled, but plugin.isFullyInstalled is false', () => {
|
||||
it('should disable button when pluginAdminExternalManaged is enabled, but plugin.isFullyInstalled is false', () => {
|
||||
render(
|
||||
<TestProvider>
|
||||
<GetStartedWithDataSource plugin={{ ...plugin, isFullyInstalled: false }} />
|
||||
@@ -67,7 +64,7 @@ describe('GetStartedWithDataSource', () => {
|
||||
expect(el).toBeDisabled();
|
||||
});
|
||||
|
||||
it('should disable button when managedPluginsInstall and pluginAdminExternalManaged are enabled, but plugin.isFullyInstalled is true', () => {
|
||||
it('should disable button when pluginAdminExternalManaged enabled, but plugin.isFullyInstalled is true', () => {
|
||||
render(
|
||||
<TestProvider>
|
||||
<GetStartedWithDataSource plugin={{ ...plugin, isFullyInstalled: true }} />
|
||||
|
||||
+1
-2
@@ -30,8 +30,7 @@ export function GetStartedWithDataSource({ plugin }: Props): React.ReactElement
|
||||
return null;
|
||||
}
|
||||
|
||||
const disabledButton =
|
||||
config.featureToggles.managedPluginsInstall && config.pluginAdminExternalManageEnabled && !plugin.isFullyInstalled;
|
||||
const disabledButton = config.pluginAdminExternalManageEnabled && !plugin.isFullyInstalled;
|
||||
|
||||
return (
|
||||
<Button
|
||||
|
||||
+1
-4
@@ -13,10 +13,7 @@ type Props = {
|
||||
};
|
||||
|
||||
export function GetStartedWithPlugin({ plugin }: Props): ReactElement | null {
|
||||
const isInstalled =
|
||||
config.featureToggles.managedPluginsInstall && config.pluginAdminExternalManageEnabled
|
||||
? plugin.isFullyInstalled
|
||||
: plugin.isInstalled;
|
||||
const isInstalled = config.pluginAdminExternalManageEnabled ? plugin.isFullyInstalled : plugin.isInstalled;
|
||||
|
||||
if (!isInstalled || plugin.isDisabled) {
|
||||
return null;
|
||||
|
||||
-47
@@ -1,47 +0,0 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
|
||||
import { config } from '@grafana/runtime';
|
||||
|
||||
import { PluginStatus } from '../../types';
|
||||
|
||||
import { ExternallyManagedButton } from './ExternallyManagedButton';
|
||||
|
||||
function setup(opts: { angularSupportEnabled: boolean; angularDetected: boolean }) {
|
||||
config.angularSupportEnabled = opts.angularSupportEnabled;
|
||||
render(
|
||||
<ExternallyManagedButton
|
||||
pluginId={'some-plugin-id'}
|
||||
angularDetected={opts.angularDetected}
|
||||
pluginStatus={PluginStatus.INSTALL}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
describe('ExternallyManagedButton', () => {
|
||||
let oldAngularSupportEnabled = config.angularSupportEnabled;
|
||||
afterAll(() => {
|
||||
config.angularSupportEnabled = oldAngularSupportEnabled;
|
||||
});
|
||||
|
||||
describe.each([{ angularSupportEnabled: true }, { angularSupportEnabled: false }])(
|
||||
'angular support is $angularSupportEnabled',
|
||||
({ angularSupportEnabled }) => {
|
||||
it.each([
|
||||
{ angularDetected: true, expectEnabled: angularSupportEnabled },
|
||||
{ angularDetected: false, expectEnabled: true },
|
||||
])('angular detected is $angularDetected', ({ angularDetected, expectEnabled }) => {
|
||||
setup({ angularSupportEnabled, angularDetected });
|
||||
|
||||
const el = screen.getByRole('link');
|
||||
expect(el).toHaveTextContent(/install/i);
|
||||
expect(el).toBeVisible();
|
||||
const linkDisabledStyle = 'pointer-events: none';
|
||||
if (expectEnabled) {
|
||||
expect(el).not.toHaveStyle(linkDisabledStyle);
|
||||
} else {
|
||||
expect(el).toHaveStyle(linkDisabledStyle);
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
-47
@@ -1,47 +0,0 @@
|
||||
import { config } from '@grafana/runtime';
|
||||
import { LinkButton, Stack } from '@grafana/ui';
|
||||
|
||||
import { getExternalManageLink } from '../../helpers';
|
||||
import { PluginStatus } from '../../types';
|
||||
|
||||
type ExternallyManagedButtonProps = {
|
||||
pluginId: string;
|
||||
pluginStatus: PluginStatus;
|
||||
angularDetected?: boolean;
|
||||
};
|
||||
|
||||
export function ExternallyManagedButton({ pluginId, pluginStatus, angularDetected }: ExternallyManagedButtonProps) {
|
||||
const externalManageLink = `${getExternalManageLink(pluginId)}/?tab=installation`;
|
||||
|
||||
if (pluginStatus === PluginStatus.UPDATE) {
|
||||
return (
|
||||
<Stack height="auto">
|
||||
<LinkButton href={externalManageLink} target="_blank" rel="noopener noreferrer">
|
||||
Update via grafana.com
|
||||
</LinkButton>
|
||||
<LinkButton variant="destructive" href={externalManageLink} target="_blank" rel="noopener noreferrer">
|
||||
Uninstall via grafana.com
|
||||
</LinkButton>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
if (pluginStatus === PluginStatus.UNINSTALL) {
|
||||
return (
|
||||
<LinkButton variant="destructive" href={externalManageLink} target="_blank" rel="noopener noreferrer">
|
||||
Uninstall via grafana.com
|
||||
</LinkButton>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<LinkButton
|
||||
disabled={!config.angularSupportEnabled && angularDetected}
|
||||
href={externalManageLink}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Install via grafana.com
|
||||
</LinkButton>
|
||||
);
|
||||
}
|
||||
-6
@@ -124,16 +124,13 @@ describe('InstallControlsButton', () => {
|
||||
});
|
||||
|
||||
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;
|
||||
});
|
||||
|
||||
@@ -199,16 +196,13 @@ describe('InstallControlsButton', () => {
|
||||
});
|
||||
|
||||
describe('uninstall 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;
|
||||
});
|
||||
|
||||
|
||||
+4
-8
@@ -5,7 +5,6 @@ import { AppEvents } from '@grafana/data';
|
||||
import { config, locationService, reportInteraction } from '@grafana/runtime';
|
||||
import { Button, ConfirmModal, Stack } from '@grafana/ui';
|
||||
import appEvents from 'app/core/app_events';
|
||||
import configCore from 'app/core/config';
|
||||
import { useQueryParams } from 'app/core/hooks/useQueryParams';
|
||||
import { removePluginFromNavTree } from 'app/core/reducers/navBarTree';
|
||||
import { useDispatch } from 'app/types';
|
||||
@@ -72,7 +71,7 @@ export function InstallControlsButton({
|
||||
const result = await install(plugin.id, latestCompatibleVersion?.version);
|
||||
if (!errorInstalling && !('error' in result)) {
|
||||
let successMessage = `Installed ${plugin.name}`;
|
||||
if (config.pluginAdminExternalManageEnabled && configCore.featureToggles.managedPluginsInstall) {
|
||||
if (config.pluginAdminExternalManageEnabled) {
|
||||
successMessage = 'Install requested, this may take a few minutes.';
|
||||
}
|
||||
|
||||
@@ -98,7 +97,7 @@ export function InstallControlsButton({
|
||||
}
|
||||
|
||||
let successMessage = `Uninstalled ${plugin.name}`;
|
||||
if (config.pluginAdminExternalManageEnabled && configCore.featureToggles.managedPluginsInstall) {
|
||||
if (config.pluginAdminExternalManageEnabled) {
|
||||
successMessage = 'Uninstall requested, this may take a few minutes.';
|
||||
}
|
||||
|
||||
@@ -154,10 +153,7 @@ export function InstallControlsButton({
|
||||
}
|
||||
|
||||
if (pluginStatus === PluginStatus.UPDATE) {
|
||||
const disableUpdate =
|
||||
config.pluginAdminExternalManageEnabled && configCore.featureToggles.managedPluginsInstall
|
||||
? plugin.isUpdatingFromInstance
|
||||
: isInstalling;
|
||||
const disableUpdate = config.pluginAdminExternalManageEnabled ? plugin.isUpdatingFromInstance : isInstalling;
|
||||
|
||||
return (
|
||||
<Stack alignItems="flex-start" width="auto" height="auto">
|
||||
@@ -181,7 +177,7 @@ export function InstallControlsButton({
|
||||
}
|
||||
|
||||
function shouldDisableUninstall(isUninstalling: boolean, plugin: CatalogPlugin) {
|
||||
if (config.pluginAdminExternalManageEnabled && config.featureToggles.managedPluginsInstall) {
|
||||
if (config.pluginAdminExternalManageEnabled) {
|
||||
return plugin.isUninstallingFromInstance || !plugin.isFullyInstalled || plugin.isUpdatingFromInstance;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,13 +2,10 @@ import { css } from '@emotion/css';
|
||||
import { useState } from 'react';
|
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { config } from '@grafana/runtime';
|
||||
import { Icon, Stack, useStyles2 } from '@grafana/ui';
|
||||
import configCore from 'app/core/config';
|
||||
|
||||
import { GetStartedWithPlugin } from '../components/GetStartedWithPlugin';
|
||||
import { InstallControlsButton } from '../components/InstallControls';
|
||||
import { ExternallyManagedButton } from '../components/InstallControls/ExternallyManagedButton';
|
||||
import { getLatestCompatibleVersion, hasInstallControlWarning, isInstallControlsEnabled } from '../helpers';
|
||||
import { useIsRemotePluginsAvailable } from '../state/hooks';
|
||||
import { CatalogPlugin, PluginStatus } from '../types';
|
||||
@@ -28,7 +25,6 @@ export const PluginActions = ({ plugin }: Props) => {
|
||||
}
|
||||
|
||||
const hasInstallWarning = hasInstallControlWarning(plugin, isRemotePluginsAvailable, latestCompatibleVersion);
|
||||
const isExternallyManaged = config.pluginAdminExternalManageEnabled;
|
||||
const pluginStatus = plugin.isInstalled
|
||||
? plugin.hasUpdate
|
||||
? PluginStatus.UPDATE
|
||||
@@ -41,23 +37,13 @@ export const PluginActions = ({ plugin }: Props) => {
|
||||
<Stack direction="column">
|
||||
<Stack alignItems="center">
|
||||
{!isInstallControlsDisabled && (
|
||||
<>
|
||||
{isExternallyManaged && !hasInstallWarning && !configCore.featureToggles.managedPluginsInstall ? (
|
||||
<ExternallyManagedButton
|
||||
pluginId={plugin.id}
|
||||
pluginStatus={pluginStatus}
|
||||
angularDetected={plugin.angularDetected}
|
||||
/>
|
||||
) : (
|
||||
<InstallControlsButton
|
||||
plugin={plugin}
|
||||
latestCompatibleVersion={latestCompatibleVersion}
|
||||
pluginStatus={pluginStatus}
|
||||
setNeedReload={setNeedReload}
|
||||
hasInstallWarning={hasInstallWarning}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
<InstallControlsButton
|
||||
plugin={plugin}
|
||||
latestCompatibleVersion={latestCompatibleVersion}
|
||||
pluginStatus={pluginStatus}
|
||||
setNeedReload={setNeedReload}
|
||||
hasInstallWarning={hasInstallWarning}
|
||||
/>
|
||||
)}
|
||||
<GetStartedWithPlugin plugin={plugin} />
|
||||
</Stack>
|
||||
|
||||
@@ -97,7 +97,7 @@ export const UpdateAllModal = ({ isOpen, onDismiss, isLoading, plugins }: Props)
|
||||
setInProgress(true);
|
||||
|
||||
// in cloud the requests need to be sync
|
||||
if (config.pluginAdminExternalManageEnabled && config.featureToggles.managedPluginsInstall) {
|
||||
if (config.pluginAdminExternalManageEnabled) {
|
||||
for (let plugin of plugins) {
|
||||
if (selectedPlugins?.has(plugin.id)) {
|
||||
await install(plugin.id, plugin.latestVersion, true);
|
||||
|
||||
@@ -194,7 +194,7 @@ export const UpdateModalBody = ({
|
||||
{`${errorMap.size} ${t('plugins.catalog.update-all.error-status-text', 'failed - see error messages')}`}
|
||||
</div>
|
||||
)}
|
||||
{config.pluginAdminExternalManageEnabled && config.featureToggles.managedPluginsInstall && (
|
||||
{config.pluginAdminExternalManageEnabled && (
|
||||
<footer className={styles.footer}>
|
||||
<Trans i18nKey="plugins.catalog.update-all.cloud-update-message">
|
||||
* It may take a few minutes for the plugins to be available for usage.
|
||||
|
||||
@@ -92,10 +92,8 @@ describe('Plugins/Helpers', () => {
|
||||
test('core plugins should be fullyInstalled in cloud', () => {
|
||||
const corePluginId = 'plugin-core';
|
||||
|
||||
const oldFeatureTogglesManagedPluginsInstall = config.featureToggles.managedPluginsInstall;
|
||||
const oldPluginAdminExternalManageEnabled = config.pluginAdminExternalManageEnabled;
|
||||
|
||||
config.featureToggles.managedPluginsInstall = true;
|
||||
config.pluginAdminExternalManageEnabled = true;
|
||||
|
||||
const merged = mergeLocalsAndRemotes({
|
||||
@@ -109,17 +107,14 @@ describe('Plugins/Helpers', () => {
|
||||
expect(findMerged(corePluginId)?.isCore).toBe(true);
|
||||
expect(findMerged(corePluginId)?.isFullyInstalled).toBe(true);
|
||||
|
||||
config.featureToggles.managedPluginsInstall = oldFeatureTogglesManagedPluginsInstall;
|
||||
config.pluginAdminExternalManageEnabled = oldPluginAdminExternalManageEnabled;
|
||||
});
|
||||
|
||||
test('plugins should be fully installed if they are installed and it is provisioned', () => {
|
||||
const pluginId = 'plugin-1';
|
||||
|
||||
const oldFeatureTogglesManagedPluginsInstall = config.featureToggles.managedPluginsInstall;
|
||||
const oldPluginAdminExternalManageEnabled = config.pluginAdminExternalManageEnabled;
|
||||
|
||||
config.featureToggles.managedPluginsInstall = true;
|
||||
config.pluginAdminExternalManageEnabled = true;
|
||||
|
||||
const merged = mergeLocalsAndRemotes({
|
||||
@@ -133,15 +128,12 @@ describe('Plugins/Helpers', () => {
|
||||
expect(findMerged(pluginId)).not.toBeUndefined();
|
||||
expect(findMerged(pluginId)?.isFullyInstalled).toBe(true);
|
||||
|
||||
config.featureToggles.managedPluginsInstall = oldFeatureTogglesManagedPluginsInstall;
|
||||
config.pluginAdminExternalManageEnabled = oldPluginAdminExternalManageEnabled;
|
||||
});
|
||||
|
||||
test('plugins should have update when instance version is different from remote version', () => {
|
||||
const oldFeatureTogglesManagedPluginsInstall = config.featureToggles.managedPluginsInstall;
|
||||
const oldPluginAdminExternalManageEnabled = config.pluginAdminExternalManageEnabled;
|
||||
|
||||
config.featureToggles.managedPluginsInstall = true;
|
||||
config.pluginAdminExternalManageEnabled = true;
|
||||
|
||||
const pluginId = 'plugin-1';
|
||||
@@ -162,7 +154,6 @@ describe('Plugins/Helpers', () => {
|
||||
expect(findMerged(pluginId)).not.toBeUndefined();
|
||||
expect(findMerged(pluginId)?.hasUpdate).toBe(true);
|
||||
|
||||
config.featureToggles.managedPluginsInstall = oldFeatureTogglesManagedPluginsInstall;
|
||||
config.pluginAdminExternalManageEnabled = oldPluginAdminExternalManageEnabled;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,7 +2,7 @@ import uFuzzy from '@leeoniya/ufuzzy';
|
||||
|
||||
import { PluginSignatureStatus, dateTimeParse, PluginError, PluginType, PluginErrorCode } from '@grafana/data';
|
||||
import { config, featureEnabled } from '@grafana/runtime';
|
||||
import configCore, { Settings } from 'app/core/config';
|
||||
import { Settings } from 'app/core/config';
|
||||
import { contextSrv } from 'app/core/core';
|
||||
import { getBackendSrv } from 'app/core/services/backend_srv';
|
||||
import { AccessControlAction } from 'app/types';
|
||||
@@ -63,7 +63,7 @@ export function mergeLocalsAndRemotes({
|
||||
const catalogPlugin = mergeLocalAndRemote(localCounterpart, remotePlugin, error);
|
||||
|
||||
// for managed instances, check if plugin is installed, but not yet present in the current instance
|
||||
if (configCore.featureToggles.managedPluginsInstall && config.pluginAdminExternalManageEnabled) {
|
||||
if (config.pluginAdminExternalManageEnabled) {
|
||||
catalogPlugin.isFullyInstalled = catalogPlugin.isCore
|
||||
? true
|
||||
: (instancesMap.has(remotePlugin.slug) || provisionedSet.has(remotePlugin.slug)) && catalogPlugin.isInstalled;
|
||||
|
||||
@@ -11,10 +11,8 @@ export const usePluginConfig = (plugin?: CatalogPlugin) => {
|
||||
return null;
|
||||
}
|
||||
|
||||
const isPluginInstalled =
|
||||
config.pluginAdminExternalManageEnabled && config.featureToggles.managedPluginsInstall
|
||||
? plugin.isFullyInstalled
|
||||
: plugin.isInstalled;
|
||||
const isPluginInstalled = config.pluginAdminExternalManageEnabled ? plugin.isFullyInstalled : plugin.isInstalled;
|
||||
|
||||
if (isPluginInstalled && !plugin.isDisabled) {
|
||||
return loadPlugin(plugin.id);
|
||||
}
|
||||
|
||||
@@ -391,31 +391,6 @@ describe('Plugin details page', () => {
|
||||
expect(await queryByRole('button', { name: /(un)?install/i })).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should display install link with `config.pluginAdminExternalManageEnabled` set to true', async () => {
|
||||
config.pluginAdminExternalManageEnabled = true;
|
||||
|
||||
const { queryByRole } = renderPluginDetails({ id, isInstalled: false });
|
||||
|
||||
expect(await queryByRole('link', { name: /install via grafana.com/i })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should display uninstall link for an installed plugin with `config.pluginAdminExternalManageEnabled` set to true', async () => {
|
||||
config.pluginAdminExternalManageEnabled = true;
|
||||
|
||||
const { queryByRole } = renderPluginDetails({ id, isInstalled: true });
|
||||
|
||||
expect(await queryByRole('link', { name: /uninstall via grafana.com/i })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should display update and uninstall links for a plugin with an available update and `config.pluginAdminExternalManageEnabled` set to true', async () => {
|
||||
config.pluginAdminExternalManageEnabled = true;
|
||||
|
||||
const { queryByRole } = renderPluginDetails({ id, isInstalled: true, hasUpdate: true });
|
||||
|
||||
expect(await queryByRole('link', { name: /update via grafana.com/i })).toBeInTheDocument();
|
||||
expect(queryByRole('link', { name: /uninstall via grafana.com/i })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should display alert with information about why the plugin is disabled', async () => {
|
||||
const { queryByTestId } = renderPluginDetails({
|
||||
id,
|
||||
|
||||
@@ -3,7 +3,6 @@ import { from, forkJoin, timeout, lastValueFrom, catchError, of } from 'rxjs';
|
||||
|
||||
import { PanelPlugin, PluginError } from '@grafana/data';
|
||||
import { config, getBackendSrv, isFetchError } from '@grafana/runtime';
|
||||
import configCore from 'app/core/config';
|
||||
import { importPanelPlugin } from 'app/features/plugins/importPanelPlugin';
|
||||
import { StoreState, ThunkResult } from 'app/types';
|
||||
|
||||
@@ -28,14 +27,8 @@ export const fetchAll = createAsyncThunk(`${STATE_PREFIX}/fetchAll`, async (_, t
|
||||
thunkApi.dispatch({ type: `${STATE_PREFIX}/fetchLocal/pending` });
|
||||
thunkApi.dispatch({ type: `${STATE_PREFIX}/fetchRemote/pending` });
|
||||
|
||||
const instance$ =
|
||||
config.pluginAdminExternalManageEnabled && configCore.featureToggles.managedPluginsInstall
|
||||
? from(getInstancePlugins())
|
||||
: of(undefined);
|
||||
const provisioned$ =
|
||||
config.pluginAdminExternalManageEnabled && configCore.featureToggles.managedPluginsInstall
|
||||
? from(getProvisionedPlugins())
|
||||
: of(undefined);
|
||||
const instance$ = config.pluginAdminExternalManageEnabled ? from(getInstancePlugins()) : of(undefined);
|
||||
const provisioned$ = config.pluginAdminExternalManageEnabled ? from(getProvisionedPlugins()) : of(undefined);
|
||||
const TIMEOUT = 500;
|
||||
const pluginErrors$ = from(getPluginErrors());
|
||||
const local$ = from(getLocalPlugins());
|
||||
|
||||
Reference in New Issue
Block a user