The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
grafana/public/app/features/plugins/extensions/validators.ts

106 lines
3.7 KiB

Plugin extensions: Introduce new registry for added links (#92343) * add added component registry * fix broken test * add tests for usePluginComponents hook * readd expose components * add type assertion exceptions to betterer results * use new addedComponent registry in legacy endpoints * remove unused code * cleanup * revert test code * remove commented code * initial commit * refactor sync method and hook * fix tests * subscribe to the correct registry * remove old registry * cleanup types * add use usePluginLinks hook * add more tests * fix import order * fix typo * fix and temporarly skip failing tests * wip * add hook tests * add more tests * remove old hook * fix versioning * add version to all extension point ids * remove cleanup * remove unused imports * revert touched file * fix test * test: remove hook creation * catch init error * send error to faro * fix broken hook * comment out call hook initialization * use the right import ofr isString * remove unused import * remove registryState type * pr feedback * Update public/app/features/plugins/extensions/validators.test.tsx Co-authored-by: Levente Balogh <balogh.levente.hu@gmail.com> * Update public/app/features/plugins/extensions/validators.test.tsx Co-authored-by: Levente Balogh <balogh.levente.hu@gmail.com> * remove no longer relevant comment * fix broken tests * Fixed test to verify that the memotization works properly. * simplify hooks --------- Co-authored-by: Levente Balogh <balogh.levente.hu@gmail.com> Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com>
1 year ago
import type { PluginExtensionAddedLinkConfig, PluginExtension, PluginExtensionLink } from '@grafana/data';
import { PluginAddedLinksConfigureFunc, PluginExtensionPoints } from '@grafana/data/src/types/pluginExtensions';
import { isPluginExtensionLink } from '@grafana/runtime';
export function assertPluginExtensionLink(
extension: PluginExtension | undefined,
errorMessage = 'extension is not a link extension'
): asserts extension is PluginExtensionLink {
if (!isPluginExtensionLink(extension)) {
throw new Error(errorMessage);
}
}
export function assertLinkPathIsValid(pluginId: string, path: string) {
if (!isLinkPathValid(pluginId, path)) {
throw new Error(
`Invalid link extension. The "path" is required and should start with "/a/${pluginId}/" (currently: "${path}"). Skipping the extension.`
);
}
}
export function assertIsReactComponent(component: React.ComponentType) {
if (!isReactComponent(component)) {
throw new Error(`Invalid component extension, the "component" property needs to be a valid React component.`);
}
}
Plugin extensions: Introduce new registry for added links (#92343) * add added component registry * fix broken test * add tests for usePluginComponents hook * readd expose components * add type assertion exceptions to betterer results * use new addedComponent registry in legacy endpoints * remove unused code * cleanup * revert test code * remove commented code * initial commit * refactor sync method and hook * fix tests * subscribe to the correct registry * remove old registry * cleanup types * add use usePluginLinks hook * add more tests * fix import order * fix typo * fix and temporarly skip failing tests * wip * add hook tests * add more tests * remove old hook * fix versioning * add version to all extension point ids * remove cleanup * remove unused imports * revert touched file * fix test * test: remove hook creation * catch init error * send error to faro * fix broken hook * comment out call hook initialization * use the right import ofr isString * remove unused import * remove registryState type * pr feedback * Update public/app/features/plugins/extensions/validators.test.tsx Co-authored-by: Levente Balogh <balogh.levente.hu@gmail.com> * Update public/app/features/plugins/extensions/validators.test.tsx Co-authored-by: Levente Balogh <balogh.levente.hu@gmail.com> * remove no longer relevant comment * fix broken tests * Fixed test to verify that the memotization works properly. * simplify hooks --------- Co-authored-by: Levente Balogh <balogh.levente.hu@gmail.com> Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com>
1 year ago
export function assertConfigureIsValid(config: PluginExtensionAddedLinkConfig) {
if (!isConfigureFnValid(config.configure)) {
throw new Error(
Plugin extensions: Introduce new registry for added links (#92343) * add added component registry * fix broken test * add tests for usePluginComponents hook * readd expose components * add type assertion exceptions to betterer results * use new addedComponent registry in legacy endpoints * remove unused code * cleanup * revert test code * remove commented code * initial commit * refactor sync method and hook * fix tests * subscribe to the correct registry * remove old registry * cleanup types * add use usePluginLinks hook * add more tests * fix import order * fix typo * fix and temporarly skip failing tests * wip * add hook tests * add more tests * remove old hook * fix versioning * add version to all extension point ids * remove cleanup * remove unused imports * revert touched file * fix test * test: remove hook creation * catch init error * send error to faro * fix broken hook * comment out call hook initialization * use the right import ofr isString * remove unused import * remove registryState type * pr feedback * Update public/app/features/plugins/extensions/validators.test.tsx Co-authored-by: Levente Balogh <balogh.levente.hu@gmail.com> * Update public/app/features/plugins/extensions/validators.test.tsx Co-authored-by: Levente Balogh <balogh.levente.hu@gmail.com> * remove no longer relevant comment * fix broken tests * Fixed test to verify that the memotization works properly. * simplify hooks --------- Co-authored-by: Levente Balogh <balogh.levente.hu@gmail.com> Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com>
1 year ago
`Invalid extension "${config.title}". The "configure" property must be a function. Skipping the extension.`
);
}
}
export function assertStringProps(extension: Record<string, unknown>, props: string[]) {
for (const prop of props) {
if (!isStringPropValid(extension[prop])) {
throw new Error(
`Invalid extension "${extension.title}". Property "${prop}" must be a string and cannot be empty. Skipping the extension.`
);
}
}
}
export function assertIsNotPromise(value: unknown, errorMessage = 'The provided value is a Promise.'): void {
if (isPromise(value)) {
throw new Error(errorMessage);
}
}
export function isLinkPathValid(pluginId: string, path: string) {
return Boolean(typeof path === 'string' && path.length > 0 && path.startsWith(`/a/${pluginId}/`));
}
Plugin Extensions: Require meta-data to be defined in `plugin.json` during development mode (#93429) * feat: add extensions to the backend plugin model * feat: update the frontend plugin types * feat(pluginContext): return a `null` if there is no context found This will be necessary to understand if a certain hook is running inside a plugin context or not. * feat: add utility functions for checking extension configs * tests: fix failing tests due to the type updates * feat(AddedComponentsRegistry): validate plugin meta-info * feat(AddedLinksRegistry): validate meta-info * feat(ExposedComponentsRegistry): validate meta-info * feat(usePluginComponent): add meta-info validation * feat(usePluginComponents): add meta-info validation * feat(usePluginLinks): add meta-info validation * fix: only validate meta-info in registries if dev mode is enabled * tests: add unit tests for the restrictions functionality * tests: fix Go tests * fix(tests): revert accidental changes * fix: run goimports * fix: api tests * add nested app so that meta data can bested e2e tested * refactor(types): extract the ExtensionInfo into a separate type * refactor(extensions/utils): use Array.prototype.some() instead of .find() * refactor(usePluginLinks): update warning message * feat(usePluginExtensions()): validate plugin meta-info * Wip * fix(e2e): E2E tests for extensions * fix(extensions): allow multiple "/" slashes in the extension point id * fix(extensions/validators): stop validating the plugin id pattern --------- Co-authored-by: Erik Sundell <erik.sundell87@gmail.com>
1 year ago
export function isExtensionPointIdValid({
extensionPointId,
pluginId,
}: {
extensionPointId: string;
pluginId: string;
}) {
if (extensionPointId.startsWith('grafana/')) {
return true;
}
return Boolean(extensionPointId.startsWith(`plugins/${pluginId}/`) || extensionPointId.startsWith(`${pluginId}/`));
}
export function extensionPointEndsWithVersion(extensionPointId: string) {
return extensionPointId.match(/.*\/v\d+$/);
}
Plugin extensions: Introduce new registry for added links (#92343) * add added component registry * fix broken test * add tests for usePluginComponents hook * readd expose components * add type assertion exceptions to betterer results * use new addedComponent registry in legacy endpoints * remove unused code * cleanup * revert test code * remove commented code * initial commit * refactor sync method and hook * fix tests * subscribe to the correct registry * remove old registry * cleanup types * add use usePluginLinks hook * add more tests * fix import order * fix typo * fix and temporarly skip failing tests * wip * add hook tests * add more tests * remove old hook * fix versioning * add version to all extension point ids * remove cleanup * remove unused imports * revert touched file * fix test * test: remove hook creation * catch init error * send error to faro * fix broken hook * comment out call hook initialization * use the right import ofr isString * remove unused import * remove registryState type * pr feedback * Update public/app/features/plugins/extensions/validators.test.tsx Co-authored-by: Levente Balogh <balogh.levente.hu@gmail.com> * Update public/app/features/plugins/extensions/validators.test.tsx Co-authored-by: Levente Balogh <balogh.levente.hu@gmail.com> * remove no longer relevant comment * fix broken tests * Fixed test to verify that the memotization works properly. * simplify hooks --------- Co-authored-by: Levente Balogh <balogh.levente.hu@gmail.com> Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com>
1 year ago
export function isGrafanaCoreExtensionPoint(extensionPointId: string) {
return Object.values(PluginExtensionPoints)
.map((v) => v.toString())
.includes(extensionPointId);
}
Plugin extensions: Introduce new registry for added links (#92343) * add added component registry * fix broken test * add tests for usePluginComponents hook * readd expose components * add type assertion exceptions to betterer results * use new addedComponent registry in legacy endpoints * remove unused code * cleanup * revert test code * remove commented code * initial commit * refactor sync method and hook * fix tests * subscribe to the correct registry * remove old registry * cleanup types * add use usePluginLinks hook * add more tests * fix import order * fix typo * fix and temporarly skip failing tests * wip * add hook tests * add more tests * remove old hook * fix versioning * add version to all extension point ids * remove cleanup * remove unused imports * revert touched file * fix test * test: remove hook creation * catch init error * send error to faro * fix broken hook * comment out call hook initialization * use the right import ofr isString * remove unused import * remove registryState type * pr feedback * Update public/app/features/plugins/extensions/validators.test.tsx Co-authored-by: Levente Balogh <balogh.levente.hu@gmail.com> * Update public/app/features/plugins/extensions/validators.test.tsx Co-authored-by: Levente Balogh <balogh.levente.hu@gmail.com> * remove no longer relevant comment * fix broken tests * Fixed test to verify that the memotization works properly. * simplify hooks --------- Co-authored-by: Levente Balogh <balogh.levente.hu@gmail.com> Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com>
1 year ago
export function isConfigureFnValid(configure?: PluginAddedLinksConfigureFunc<object> | undefined) {
return configure ? typeof configure === 'function' : true;
}
Plugin extensions: Introduce new registry for added links (#92343) * add added component registry * fix broken test * add tests for usePluginComponents hook * readd expose components * add type assertion exceptions to betterer results * use new addedComponent registry in legacy endpoints * remove unused code * cleanup * revert test code * remove commented code * initial commit * refactor sync method and hook * fix tests * subscribe to the correct registry * remove old registry * cleanup types * add use usePluginLinks hook * add more tests * fix import order * fix typo * fix and temporarly skip failing tests * wip * add hook tests * add more tests * remove old hook * fix versioning * add version to all extension point ids * remove cleanup * remove unused imports * revert touched file * fix test * test: remove hook creation * catch init error * send error to faro * fix broken hook * comment out call hook initialization * use the right import ofr isString * remove unused import * remove registryState type * pr feedback * Update public/app/features/plugins/extensions/validators.test.tsx Co-authored-by: Levente Balogh <balogh.levente.hu@gmail.com> * Update public/app/features/plugins/extensions/validators.test.tsx Co-authored-by: Levente Balogh <balogh.levente.hu@gmail.com> * remove no longer relevant comment * fix broken tests * Fixed test to verify that the memotization works properly. * simplify hooks --------- Co-authored-by: Levente Balogh <balogh.levente.hu@gmail.com> Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com>
1 year ago
export function isStringPropValid(prop: unknown) {
return typeof prop === 'string' && prop.length > 0;
}
export function isPromise(value: unknown): value is Promise<unknown> {
return (
value instanceof Promise || (typeof value === 'object' && value !== null && 'then' in value && 'catch' in value)
);
}
export function isReactComponent(component: unknown): component is React.ComponentType {
const hasReactTypeProp = (obj: unknown): obj is { $$typeof: Symbol } =>
typeof obj === 'object' && obj !== null && '$$typeof' in obj;
// The sandbox wraps the plugin components with React.memo.
const isReactMemoObject = (obj: unknown): boolean =>
hasReactTypeProp(obj) && obj.$$typeof === Symbol.for('react.memo');
// We currently don't have any strict runtime-checking for this.
// (The main reason is that we don't want to start depending on React implementation details.)
return typeof component === 'function' || isReactMemoObject(component);
}