mirror of https://github.com/grafana/grafana
Catalog: Display badges for Angular plugins and disable install if Angular is disabled (#69084)
* Angular deprecation: Add Angular badge in plugin catalog page * Angular deprecation: Add alert in plugin details page * Angular deprecation: Disable install button if for Angular plugins * removed extra console.log * Add tests for Angular badge * Add tests for PluginDetailsAngularDeprecation * Add tests for InstallControlsButton * Add tests for ExternallyManagedButton * Table tests * Catalog: Update angular deprecation message * PR review feedback * Update tests * Update copy for angular tooltip and alert * Update tests * Fix test warnings * Fix angularDetected not being set for remote catalog plugins * Dynamic alert text based on grafana config * Moved deprecation message to a separate function * Removed unused Props in PluginAngularBadgepull/70816/head
parent
ebe5e9c2e6
commit
dde4a03544
@ -0,0 +1,14 @@ |
||||
import React from 'react'; |
||||
|
||||
import { Badge } from '@grafana/ui'; |
||||
|
||||
export function PluginAngularBadge(): React.ReactElement { |
||||
return ( |
||||
<Badge |
||||
icon="exclamation-triangle" |
||||
text="Angular" |
||||
color="orange" |
||||
tooltip="This plugin uses deprecated functionality, support for which is being removed." |
||||
/> |
||||
); |
||||
} |
@ -0,0 +1,48 @@ |
||||
import { render, screen } from '@testing-library/react'; |
||||
import React from '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); |
||||
} |
||||
}); |
||||
} |
||||
); |
||||
}); |
@ -0,0 +1,72 @@ |
||||
import { render, screen } from '@testing-library/react'; |
||||
import React from 'react'; |
||||
import { TestProvider } from 'test/helpers/TestProvider'; |
||||
|
||||
import { PluginSignatureStatus } from '@grafana/data'; |
||||
import { config } from '@grafana/runtime'; |
||||
|
||||
import { CatalogPlugin, PluginStatus } from '../../types'; |
||||
|
||||
import { InstallControlsButton } from './InstallControlsButton'; |
||||
|
||||
const plugin: CatalogPlugin = { |
||||
description: 'The test plugin', |
||||
downloads: 5, |
||||
id: 'test-plugin', |
||||
info: { |
||||
logos: { small: '', large: '' }, |
||||
}, |
||||
name: 'Testing Plugin', |
||||
orgName: 'Test', |
||||
popularity: 0, |
||||
signature: PluginSignatureStatus.valid, |
||||
publishedAt: '2020-09-01', |
||||
updatedAt: '2021-06-28', |
||||
hasUpdate: false, |
||||
isInstalled: false, |
||||
isCore: false, |
||||
isDev: false, |
||||
isEnterprise: false, |
||||
isDisabled: false, |
||||
isPublished: true, |
||||
}; |
||||
|
||||
function setup(opts: { angularSupportEnabled: boolean; angularDetected: boolean }) { |
||||
config.angularSupportEnabled = opts.angularSupportEnabled; |
||||
render( |
||||
<TestProvider> |
||||
<InstallControlsButton |
||||
plugin={{ ...plugin, angularDetected: opts.angularDetected }} |
||||
pluginStatus={PluginStatus.INSTALL} |
||||
/> |
||||
</TestProvider> |
||||
); |
||||
} |
||||
|
||||
describe('InstallControlsButton', () => { |
||||
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('button'); |
||||
expect(el).toHaveTextContent(/install/i); |
||||
expect(el).toBeVisible(); |
||||
if (expectEnabled) { |
||||
expect(el).toBeEnabled(); |
||||
} else { |
||||
expect(el).toBeDisabled(); |
||||
} |
||||
}); |
||||
} |
||||
); |
||||
}); |
@ -0,0 +1,40 @@ |
||||
import React from 'react'; |
||||
|
||||
import { Alert } from '@grafana/ui'; |
||||
|
||||
type Props = { |
||||
className?: string; |
||||
angularSupportEnabled?: boolean; |
||||
}; |
||||
|
||||
function deprecationMessage(angularSupportEnabled?: boolean): string { |
||||
const msg = 'This plugin uses a deprecated, legacy platform based on AngularJS and '; |
||||
if (angularSupportEnabled === undefined) { |
||||
return msg + ' may be incompatible depending on your Grafana configuration.'; |
||||
} |
||||
if (angularSupportEnabled) { |
||||
return msg + ' will stop working in future releases of Grafana.'; |
||||
} |
||||
return msg + ' is incompatible with your current Grafana configuration.'; |
||||
} |
||||
|
||||
// An Alert showing information about Angular deprecation notice.
|
||||
// If the plugin does not use Angular (!plugin.angularDetected), it returns null.
|
||||
export function PluginDetailsAngularDeprecation({ |
||||
className, |
||||
angularSupportEnabled, |
||||
}: Props): React.ReactElement | null { |
||||
return ( |
||||
<Alert severity="warning" title="Angular plugin" className={className}> |
||||
<p>{deprecationMessage(angularSupportEnabled)}</p> |
||||
<a |
||||
href="https://grafana.com/docs/grafana/latest/developers/angular_deprecation/" |
||||
className="external-link" |
||||
target="_blank" |
||||
rel="noreferrer" |
||||
> |
||||
Read more about Angular support deprecation. |
||||
</a> |
||||
</Alert> |
||||
); |
||||
} |
@ -0,0 +1,64 @@ |
||||
import { render, screen, act } from '@testing-library/react'; |
||||
import React from 'react'; |
||||
import { TestProvider } from 'test/helpers/TestProvider'; |
||||
|
||||
import { PluginSignatureStatus } from '@grafana/data'; |
||||
|
||||
import { PluginDetailsPage } from './PluginDetailsPage'; |
||||
|
||||
jest.mock('../state/hooks', () => ({ |
||||
__esModule: true, |
||||
...jest.requireActual('../state/hooks'), |
||||
useGetSingle: jest.fn().mockImplementation((id: string) => { |
||||
return { |
||||
description: 'The test plugin', |
||||
downloads: 5, |
||||
id: 'test-plugin', |
||||
info: { |
||||
logos: { small: '', large: '' }, |
||||
}, |
||||
name: 'Testing Plugin', |
||||
orgName: 'Test', |
||||
popularity: 0, |
||||
signature: PluginSignatureStatus.valid, |
||||
publishedAt: '2020-09-01', |
||||
updatedAt: '2021-06-28', |
||||
hasUpdate: false, |
||||
isInstalled: false, |
||||
isCore: false, |
||||
isDev: false, |
||||
isEnterprise: false, |
||||
isDisabled: false, |
||||
isPublished: true, |
||||
angularDetected: id === 'angular', |
||||
}; |
||||
}), |
||||
})); |
||||
|
||||
describe('PluginDetailsAngularDeprecation', () => { |
||||
afterAll(() => { |
||||
jest.resetAllMocks(); |
||||
}); |
||||
|
||||
it('renders the component for angular plugins', async () => { |
||||
await act(async () => |
||||
render( |
||||
<TestProvider> |
||||
<PluginDetailsPage pluginId="angular" /> |
||||
</TestProvider> |
||||
) |
||||
); |
||||
expect(screen.getByText(/angular plugin/i)).toBeVisible(); |
||||
}); |
||||
|
||||
it('does not render the component for non-angular plugins', async () => { |
||||
await act(async () => |
||||
render( |
||||
<TestProvider> |
||||
<PluginDetailsPage pluginId="not-angular" /> |
||||
</TestProvider> |
||||
) |
||||
); |
||||
expect(screen.queryByText(/angular plugin/i)).toBeNull(); |
||||
}); |
||||
}); |
Loading…
Reference in new issue