alerting/exposed-component-test
Gilles De Mey 8 months ago
parent 4807d964b0
commit d5dadd074c
No known key found for this signature in database
  1. 4
      Makefile
  2. 30
      public/app/features/alerting/plugin/plugin.tsx
  3. 56
      public/app/features/alerting/unified/components/contact-points/ContactPoint.tsx
  4. 4
      public/app/features/alerting/unified/components/contact-points/useContactPointsSearch.tsx
  5. 2
      public/app/features/alerting/unified/components/contact-points/utils.ts
  6. 4
      public/app/features/alerting/unified/components/notification-policies/ContactPointSelector.tsx
  7. 4
      public/app/features/alerting/unified/initAlerting.tsx
  8. 7
      public/app/features/plugins/extensions/registry/AddedLinksRegistry.ts
  9. 7
      public/app/features/plugins/extensions/registry/ExposedComponentsRegistry.ts
  10. 0
      public/app/features/plugins/extensions/registry/isCorePluginIdentifier.ts
  11. 16
      public/app/features/plugins/extensions/registry/setup.ts
  12. 3
      public/app/features/plugins/extensions/usePluginComponent.tsx

@ -234,8 +234,8 @@ run: $(BRA) ## Build and run web server on filesystem changes. See /.bra.toml fo
.PHONY: run-go
run-go: ## Build and run web server immediately.
$(GO) run -race $(if $(GO_BUILD_TAGS),-build-tags=$(GO_BUILD_TAGS)) \
./pkg/cmd/grafana -- server -profile -profile-addr=127.0.0.1 -profile-port=6000 -packaging=dev cfg:app_mode=development
$(GO) run $(if $(GO_BUILD_TAGS),-build-tags=$(GO_BUILD_TAGS)) \
./pkg/cmd/grafana -- server -packaging=dev cfg:app_mode=development
.PHONY: run-frontend
run-frontend: deps-js ## Fetch js dependencies and watch frontend for rebuild

@ -1,21 +1,31 @@
import { ReactNode } from 'react';
import { AppPlugin } from '@grafana/data';
import { PluginExtensionExposedComponentConfig } from '@grafana/data';
import { ContactPoint } from '../unified/components/contact-points/ContactPoint';
import { useContactPointsWithStatus } from '../unified/components/contact-points/useContactPoints';
import { AlertmanagerProvider } from '../unified/state/AlertmanagerContext';
import { GRAFANA_RULES_SOURCE_NAME } from '../unified/utils/datasource';
export const ALERTING_PLUGIN_PREFIX = 'com.grafana.alerting';
export function initAlertingPlugin() {
new AppPlugin().exposeComponent({
id: `${ALERTING_PLUGIN_PREFIX}/listContactPoints/v0`,
const ExposedAlertingComponents = [
{
id: 'grafana/listContactPoints/v0',
title: 'List Contact Points',
description:
'This components will use renderProps to return all contact points for the built-in Grafana Alertmanager',
component: ListContactPointsV1Component,
});
}
},
{
id: 'grafana/ContactPoint/v0',
title: 'Visual representation of a single Contact Point',
component: ContactPoint,
},
{
id: 'grafana/AlertmanagerProvider/v0',
title: 'Use this component to wrap your code that wants to use the AlertmanagerContext',
component: AlertmanagerProvider,
},
] as PluginExtensionExposedComponentConfig[];
type ListContactPointsV1ComponentProps = {
children: (result: ReturnType<typeof useContactPointsWithStatus>) => ReactNode;
@ -29,3 +39,7 @@ function ListContactPointsV1Component({ children }: ListContactPointsV1Component
});
return children(result);
}
export function getCoreAlertingConfigurations(): PluginExtensionExposedComponentConfig[] {
return ExposedAlertingComponents;
}

@ -33,7 +33,7 @@ export const ContactPoint = ({ contactPoint }: ContactPointProps) => {
const [DeleteModal, showDeleteModal] = useDeleteContactPointModal(deleteTrigger.execute);
// TODO probably not the best way to figure out if we want to show either only the summary or full metadata for the receivers?
const showFullMetadata = receivers.some((receiver) => Boolean(receiver[RECEIVER_META_KEY]));
const showFullMetadata = (receivers ?? []).some((receiver) => Boolean(receiver[RECEIVER_META_KEY]));
return (
<div className={styles.contactPointWrapper} data-testid="contact-point">
@ -47,34 +47,34 @@ export const ContactPoint = ({ contactPoint }: ContactPointProps) => {
})
}
/>
{receivers &&
(showFullMetadata ? (
<div>
{receivers.map((receiver, index) => {
const diagnostics = receiver[RECEIVER_STATUS_KEY];
const metadata = receiver[RECEIVER_META_KEY];
const sendingResolved = !Boolean(receiver.disableResolveMessage);
const pluginMetadata = receiver[RECEIVER_PLUGIN_META_KEY];
const key = metadata.name + index;
{showFullMetadata ? (
<div>
{receivers.map((receiver, index) => {
const diagnostics = receiver[RECEIVER_STATUS_KEY];
const metadata = receiver[RECEIVER_META_KEY];
const sendingResolved = !Boolean(receiver.disableResolveMessage);
const pluginMetadata = receiver[RECEIVER_PLUGIN_META_KEY];
const key = metadata.name + index;
return (
<ContactPointReceiver
key={key}
name={metadata.name}
type={receiver.type}
description={getReceiverDescription(receiver)}
diagnostics={diagnostics}
pluginMetadata={pluginMetadata}
sendingResolved={sendingResolved}
/>
);
})}
</div>
) : (
<div className={styles.integrationWrapper}>
<ContactPointReceiverSummary receivers={receivers} />
</div>
)}
return (
<ContactPointReceiver
key={key}
name={metadata.name}
type={receiver.type}
description={getReceiverDescription(receiver)}
diagnostics={diagnostics}
pluginMetadata={pluginMetadata}
sendingResolved={sendingResolved}
/>
);
})}
</div>
) : (
<div className={styles.integrationWrapper}>
<ContactPointReceiverSummary receivers={receivers} />
</div>
))}
</Stack>
{DeleteModal}
</div>

@ -25,7 +25,9 @@ export const useContactPointsSearch = (
const typeHaystack = useMemo(() => {
return contactPoints.map((contactPoint) =>
// we're using the resolved metadata key here instead of the "type" property – ex. we alias "teams" to "microsoft teams"
contactPoint.grafana_managed_receiver_configs.map((receiver) => receiver[RECEIVER_META_KEY].name).join(' ')
(contactPoint.grafana_managed_receiver_configs ?? [])
.map((receiver) => receiver[RECEIVER_META_KEY].name)
.join(' ')
);
}, [contactPoints]);

@ -94,7 +94,7 @@ export interface ReceiverConfigWithMetadata extends GrafanaManagedReceiverConfig
export interface ContactPointWithMetadata extends GrafanaManagedContactPoint {
id: string;
policies?: RouteReference[]; // now is optional as we don't have the data from the read-only endpoint
grafana_managed_receiver_configs: ReceiverConfigWithMetadata[];
grafana_managed_receiver_configs: ReceiverConfigWithMetadata[] | null; // can be empty for contact points with no integrations
}
type EnhanceContactPointsArgs = {

@ -2,7 +2,7 @@ import { css, cx, keyframes } from '@emotion/css';
import { useMemo, useState } from 'react';
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
import { Select, SelectCommonProps, Stack, Alert, IconButton, Text, useStyles2 } from '@grafana/ui';
import { Alert, IconButton, Select, SelectCommonProps, Stack, Text, useStyles2 } from '@grafana/ui';
import { ContactPointReceiverSummary } from 'app/features/alerting/unified/components/contact-points/ContactPoint';
import { useAlertmanager } from 'app/features/alerting/unified/state/AlertmanagerContext';
@ -40,7 +40,7 @@ export const ContactPointSelector = ({
value: contactPoint,
component: () => (
<Text variant="bodySmall" color="secondary">
<ContactPointReceiverSummary receivers={contactPoint.grafana_managed_receiver_configs} limit={2} />
<ContactPointReceiverSummary receivers={contactPoint.grafana_managed_receiver_configs ?? []} limit={2} />
</Text>
),
};

@ -4,7 +4,6 @@ import { config } from '@grafana/runtime';
import { contextSrv } from 'app/core/services/context_srv';
import { addCustomRightAction } from '../../dashboard/components/DashNav/DashNav';
import { initAlertingPlugin } from '../plugin/plugin';
import { getRulesPermissions } from './utils/access-control';
import { GRAFANA_RULES_SOURCE_NAME } from './utils/datasource';
@ -29,7 +28,4 @@ export function initAlerting() {
index: -2,
});
}
// init Alerting pseudo-plugin
initAlertingPlugin();
}

@ -8,6 +8,7 @@ import { isGrafanaDevMode } from '../utils';
import { isAddedLinkMetaInfoMissing, isConfigureFnValid, isLinkPathValid } from '../validators';
import { PluginExtensionConfigs, Registry, RegistryType } from './Registry';
import { isCorePluginIdentifier } from './setup';
const logPrefix = 'Could not register link extension. Reason:';
@ -69,7 +70,11 @@ export class AddedLinksRegistry extends Registry<AddedLinkRegistryItem[], Plugin
continue;
}
if (pluginId !== 'grafana' && isGrafanaDevMode() && isAddedLinkMetaInfoMissing(pluginId, config, configLog)) {
if (
!isCorePluginIdentifier(pluginId) &&
isGrafanaDevMode() &&
isAddedLinkMetaInfoMissing(pluginId, config, configLog)
) {
continue;
}

@ -6,7 +6,8 @@ import * as errors from '../errors';
import { isGrafanaDevMode } from '../utils';
import { isExposedComponentMetaInfoMissing } from '../validators';
import { Registry, RegistryType, PluginExtensionConfigs } from './Registry';
import { PluginExtensionConfigs, Registry, RegistryType } from './Registry';
import { isCorePluginIdentifier } from './setup';
const logPrefix = 'Could not register exposed component. Reason:';
@ -47,7 +48,7 @@ export class ExposedComponentsRegistry extends Registry<
pluginId,
});
if (!id.startsWith(pluginId)) {
if (!id.startsWith(pluginId) && !isCorePluginIdentifier(pluginId)) {
pointIdLog.error(`${logPrefix} ${errors.INVALID_EXPOSED_COMPONENT_ID}`);
continue;
}
@ -63,7 +64,7 @@ export class ExposedComponentsRegistry extends Registry<
}
if (
pluginId !== 'grafana' &&
!isCorePluginIdentifier(pluginId) &&
isGrafanaDevMode() &&
isExposedComponentMetaInfoMissing(pluginId, config, pointIdLog)
) {

@ -1,3 +1,5 @@
import { getCoreAlertingConfigurations } from 'app/features/alerting/plugin/plugin';
import { getCoreExtensionConfigurations } from '../getCoreExtensionConfigurations';
import { AddedComponentsRegistry } from './AddedComponentsRegistry';
@ -5,6 +7,8 @@ import { AddedLinksRegistry } from './AddedLinksRegistry';
import { ExposedComponentsRegistry } from './ExposedComponentsRegistry';
import { PluginExtensionRegistries } from './types';
export const GRAFANA_CORE_PLUGIN_ID = 'grafana';
export function setupPluginExtensionRegistries(): PluginExtensionRegistries {
const pluginExtensionsRegistries = {
addedComponentsRegistry: new AddedComponentsRegistry(),
@ -13,9 +17,19 @@ export function setupPluginExtensionRegistries(): PluginExtensionRegistries {
};
pluginExtensionsRegistries.addedLinksRegistry.register({
pluginId: 'grafana',
pluginId: GRAFANA_CORE_PLUGIN_ID,
configs: getCoreExtensionConfigurations(),
});
pluginExtensionsRegistries.exposedComponentsRegistry.register({
pluginId: GRAFANA_CORE_PLUGIN_ID,
configs: getCoreAlertingConfigurations(),
});
return pluginExtensionsRegistries;
}
export const isCorePluginIdentifier = (id: string): boolean => [GRAFANA_CORE_PLUGIN_ID].includes(id);
export const hasCorePluginIdentifier = (id: string): boolean =>
[GRAFANA_CORE_PLUGIN_ID].findIndex((coreId) => id.startsWith(coreId)) > -1;

@ -7,6 +7,7 @@ import { UsePluginComponentResult } from '@grafana/runtime';
import { useExposedComponentsRegistry } from './ExtensionRegistriesContext';
import * as errors from './errors';
import { log } from './logs/log';
import { hasCorePluginIdentifier } from './registry/setup';
import { isGrafanaDevMode, wrapWithPluginContext } from './utils';
import { isExposedComponentDependencyMissing } from './validators';
@ -35,7 +36,7 @@ export function usePluginComponent<Props extends object = {}>(id: string): UsePl
pluginId: registryItem.pluginId,
});
if (enableRestrictions && isExposedComponentDependencyMissing(id, pluginContext)) {
if (enableRestrictions && isExposedComponentDependencyMissing(id, pluginContext) && !hasCorePluginIdentifier(id)) {
componentLog.error(errors.EXPOSED_COMPONENT_DEPENDENCY_MISSING);
return {
isLoading: false,

Loading…
Cancel
Save