Datasources: Filter plugin errors to only show datasource plugins (#74339)
* feat(plugins): allow filtering of plugin errors by plugin type * refactor(plugins): migrate PluginsErrorsInfo component to use Alert component * chore(plugins): remove redundant d3 import * feat(datasources): filter plugin errors by plugin type * refactor(plugins): pass plugin.type from selector rather than guess from pluginId * refactor(plugins): move filtering to selector
This commit is contained in:
@@ -49,6 +49,7 @@ export enum PluginErrorCode {
|
||||
export interface PluginError {
|
||||
errorCode: PluginErrorCode;
|
||||
pluginId: string;
|
||||
pluginType?: PluginType;
|
||||
}
|
||||
|
||||
export interface PluginMeta<T extends KeyValue = {}> {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import { AnyAction } from 'redux';
|
||||
|
||||
import { DataSourcePluginMeta } from '@grafana/data';
|
||||
import { DataSourcePluginMeta, PluginType } from '@grafana/data';
|
||||
import { LinkButton, FilterInput } from '@grafana/ui';
|
||||
import PageLoader from 'app/core/components/PageLoader/PageLoader';
|
||||
import { PluginsErrorsInfo } from 'app/features/plugins/components/PluginsErrorsInfo';
|
||||
@@ -74,8 +74,8 @@ export function NewDataSourceView({
|
||||
</LinkButton>
|
||||
</div>
|
||||
|
||||
{/* Show any plugin errors while not searching for anything specific */}
|
||||
{!searchQuery && <PluginsErrorsInfo />}
|
||||
{/* Show datasource plugin errors while not searching for anything specific */}
|
||||
{!searchQuery && <PluginsErrorsInfo filterByPluginType={PluginType.datasource} />}
|
||||
|
||||
{/* Search results */}
|
||||
<div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useEffect, useMemo } from 'react';
|
||||
|
||||
import { PluginError } from '@grafana/data';
|
||||
import { PluginError, PluginType } from '@grafana/data';
|
||||
import { useDispatch, useSelector } from 'app/types';
|
||||
|
||||
import { sortPlugins, Sorters } from '../helpers';
|
||||
@@ -48,10 +48,10 @@ export const useGetSingleLocalWithoutDetails = (id: string): CatalogPlugin | und
|
||||
return useSelector((state) => selectById(state, id));
|
||||
};
|
||||
|
||||
export const useGetErrors = (): PluginError[] => {
|
||||
export const useGetErrors = (filterByPluginType?: PluginType): PluginError[] => {
|
||||
useFetchAll();
|
||||
|
||||
return useSelector(selectPluginErrors);
|
||||
return useSelector(selectPluginErrors(filterByPluginType));
|
||||
};
|
||||
|
||||
export const useInstall = () => {
|
||||
|
||||
@@ -63,19 +63,20 @@ export const selectPlugins = (filters: PluginFilters) =>
|
||||
});
|
||||
});
|
||||
|
||||
export const selectPluginErrors = createSelector(selectAll, (plugins) => {
|
||||
const pluginErrors: PluginError[] = [];
|
||||
for (const plugin of plugins) {
|
||||
if (plugin.error) {
|
||||
pluginErrors.push({
|
||||
pluginId: plugin.id,
|
||||
errorCode: plugin.error,
|
||||
});
|
||||
export const selectPluginErrors = (filterByPluginType?: PluginType) =>
|
||||
createSelector(selectAll, (plugins) => {
|
||||
const pluginErrors: PluginError[] = [];
|
||||
for (const plugin of plugins) {
|
||||
if (plugin.error && (!filterByPluginType || plugin.type === filterByPluginType)) {
|
||||
pluginErrors.push({
|
||||
pluginId: plugin.id,
|
||||
errorCode: plugin.error,
|
||||
pluginType: plugin.type,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pluginErrors;
|
||||
});
|
||||
return pluginErrors;
|
||||
});
|
||||
|
||||
// The following selectors are used to get information about the outstanding or completed plugins-related network requests.
|
||||
export const selectRequest = (actionType: string) =>
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
import { css } from '@emotion/css';
|
||||
import React from 'react';
|
||||
|
||||
import { GrafanaTheme2, PluginErrorCode, PluginSignatureStatus } from '@grafana/data';
|
||||
import { GrafanaTheme2, PluginErrorCode, PluginSignatureStatus, PluginType } from '@grafana/data';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
import { HorizontalGroup, InfoBox, List, PluginSignatureBadge, useStyles2 } from '@grafana/ui';
|
||||
import { Alert, HorizontalGroup, Icon, List, PluginSignatureBadge, useStyles2 } from '@grafana/ui';
|
||||
|
||||
import { useGetErrors, useFetchStatus } from '../admin/state/hooks';
|
||||
|
||||
export function PluginsErrorsInfo() {
|
||||
const errors = useGetErrors();
|
||||
type PluginsErrorInfoProps = {
|
||||
filterByPluginType?: PluginType;
|
||||
};
|
||||
|
||||
export function PluginsErrorsInfo({ filterByPluginType }: PluginsErrorInfoProps) {
|
||||
let errors = useGetErrors(filterByPluginType);
|
||||
const { isLoading } = useFetchStatus();
|
||||
const styles = useStyles2(getStyles);
|
||||
|
||||
@@ -17,35 +21,36 @@ export function PluginsErrorsInfo() {
|
||||
}
|
||||
|
||||
return (
|
||||
<InfoBox
|
||||
<Alert
|
||||
title="Unsigned plugins were found during plugin initialization. Grafana Labs cannot guarantee the integrity of these plugins. We recommend only using signed plugins."
|
||||
aria-label={selectors.pages.PluginsList.signatureErrorNotice}
|
||||
severity="warning"
|
||||
urlTitle="Read more about plugin signing"
|
||||
url="https://grafana.com/docs/grafana/latest/plugins/plugin-signatures/"
|
||||
>
|
||||
<div>
|
||||
<p>
|
||||
Unsigned plugins were found during plugin initialization. Grafana Labs cannot guarantee the integrity of these
|
||||
plugins. We recommend only using signed plugins.
|
||||
</p>
|
||||
The following plugins are disabled and not shown in the list below:
|
||||
<List
|
||||
items={errors}
|
||||
className={styles.list}
|
||||
renderItem={(error) => (
|
||||
<div className={styles.wrapper}>
|
||||
<HorizontalGroup spacing="sm" justify="flex-start" align="center">
|
||||
<strong>{error.pluginId}</strong>
|
||||
<PluginSignatureBadge
|
||||
status={mapPluginErrorCodeToSignatureStatus(error.errorCode)}
|
||||
className={styles.badge}
|
||||
/>
|
||||
</HorizontalGroup>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</InfoBox>
|
||||
<p>The following plugins are disabled and not shown in the list below:</p>
|
||||
<List
|
||||
items={errors}
|
||||
className={styles.list}
|
||||
renderItem={(error) => (
|
||||
<div className={styles.wrapper}>
|
||||
<HorizontalGroup spacing="sm" justify="flex-start" align="center">
|
||||
<strong>{error.pluginId}</strong>
|
||||
<PluginSignatureBadge
|
||||
status={mapPluginErrorCodeToSignatureStatus(error.errorCode)}
|
||||
className={styles.badge}
|
||||
/>
|
||||
</HorizontalGroup>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
<a
|
||||
href="https://grafana.com/docs/grafana/latest/plugins/plugin-signatures/"
|
||||
className={styles.docsLink}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
<Icon name="book" /> Read more about plugin signing
|
||||
</a>
|
||||
</Alert>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -73,5 +78,10 @@ function getStyles(theme: GrafanaTheme2) {
|
||||
badge: css({
|
||||
marginTop: 0,
|
||||
}),
|
||||
docsLink: css({
|
||||
display: 'inline-block',
|
||||
color: theme.colors.text.link,
|
||||
marginTop: theme.spacing(2),
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user