2021-04-13 06:16:56 -05:00
|
|
|
import React from 'react';
|
2022-04-22 08:33:13 -05:00
|
|
|
|
2021-04-12 02:41:07 -05:00
|
|
|
import { AnnotationQuery, DataSourceApi } from '@grafana/data';
|
|
|
|
import { AngularComponent, getAngularLoader } from '@grafana/runtime';
|
|
|
|
|
|
|
|
export interface Props {
|
|
|
|
annotation: AnnotationQuery;
|
|
|
|
datasource: DataSourceApi;
|
|
|
|
onChange: (annotation: AnnotationQuery) => void;
|
|
|
|
}
|
|
|
|
|
2021-04-23 07:06:30 -05:00
|
|
|
interface ScopeProps {
|
|
|
|
ctrl: {
|
|
|
|
currentDatasource: DataSourceApi;
|
|
|
|
currentAnnotation: AnnotationQuery;
|
|
|
|
ignoreNextWatcherFiring: boolean;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2021-04-13 06:16:56 -05:00
|
|
|
export class AngularEditorLoader extends React.PureComponent<Props> {
|
|
|
|
ref: HTMLDivElement | null = null;
|
2021-04-15 07:21:06 -05:00
|
|
|
angularComponent?: AngularComponent;
|
2021-04-23 07:06:30 -05:00
|
|
|
scopeProps?: ScopeProps;
|
2021-04-12 02:41:07 -05:00
|
|
|
|
2021-04-13 06:16:56 -05:00
|
|
|
componentWillUnmount() {
|
|
|
|
if (this.angularComponent) {
|
|
|
|
this.angularComponent.destroy();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
componentDidMount() {
|
|
|
|
if (this.ref) {
|
|
|
|
this.loadAngular();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
componentDidUpdate(prevProps: Props) {
|
|
|
|
if (prevProps.datasource !== this.props.datasource) {
|
|
|
|
this.loadAngular();
|
|
|
|
}
|
2021-04-12 02:41:07 -05:00
|
|
|
|
2021-04-23 07:06:30 -05:00
|
|
|
if (this.scopeProps && this.scopeProps.ctrl.currentAnnotation !== this.props.annotation) {
|
|
|
|
this.scopeProps.ctrl.ignoreNextWatcherFiring = true;
|
|
|
|
this.scopeProps.ctrl.currentAnnotation = this.props.annotation;
|
|
|
|
this.angularComponent?.digest();
|
2021-04-12 02:41:07 -05:00
|
|
|
}
|
2021-04-13 06:16:56 -05:00
|
|
|
}
|
2021-04-12 02:41:07 -05:00
|
|
|
|
2021-04-13 06:16:56 -05:00
|
|
|
loadAngular() {
|
|
|
|
if (this.angularComponent) {
|
|
|
|
this.angularComponent.destroy();
|
2021-04-23 07:06:30 -05:00
|
|
|
this.scopeProps = undefined;
|
2021-04-13 06:16:56 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
const loader = getAngularLoader();
|
2021-11-02 10:30:20 -05:00
|
|
|
// NOTE: BE CAREFUL HERE
|
|
|
|
// If this template contains an ng-if, then it won't be removed correctly by AngularLoader.
|
|
|
|
// The compiledElem will only contain the single comment node (e.g. <!-- ngIf !ctrl.currentDatasource.annotations -->)
|
|
|
|
const template = `<plugin-component type="annotations-query-ctrl"> </plugin-component>`;
|
2021-04-13 06:16:56 -05:00
|
|
|
const scopeProps = {
|
|
|
|
ctrl: {
|
|
|
|
currentDatasource: this.props.datasource,
|
|
|
|
currentAnnotation: this.props.annotation,
|
2021-04-19 02:35:43 -05:00
|
|
|
ignoreNextWatcherFiring: false,
|
2021-04-13 06:16:56 -05:00
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
this.angularComponent = loader.load(this.ref, scopeProps, template);
|
|
|
|
this.angularComponent.digest();
|
|
|
|
this.angularComponent.getScope().$watch(() => {
|
2021-04-19 02:35:43 -05:00
|
|
|
// To avoid recursive loop when the annotation is updated from outside angular in componentDidUpdate
|
|
|
|
if (scopeProps.ctrl.ignoreNextWatcherFiring) {
|
|
|
|
scopeProps.ctrl.ignoreNextWatcherFiring = false;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-04-23 07:06:30 -05:00
|
|
|
this.props.onChange(scopeProps.ctrl.currentAnnotation);
|
2021-04-13 06:16:56 -05:00
|
|
|
});
|
2021-04-23 07:06:30 -05:00
|
|
|
|
|
|
|
this.scopeProps = scopeProps;
|
2021-04-13 06:16:56 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
render() {
|
|
|
|
return <div ref={(element) => (this.ref = element)} />;
|
|
|
|
}
|
|
|
|
}
|