@grafana/runtime
Version:
Grafana Runtime Library
2,170 lines • 71.6 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var data = require('@grafana/data');
var jsxRuntime = require('react/jsx-runtime');
var H = require('history');
var React = require('react');
var rxjs = require('rxjs');
var ui = require('@grafana/ui');
var lodash = require('lodash');
var reactUse = require('react-use');
var faroWebSdk = require('@grafana/faro-web-sdk');
var operators = require('rxjs/operators');
var e2eSelectors = require('@grafana/e2e-selectors');
var Skeleton = require('react-loading-skeleton');
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
function _interopNamespaceCompat(e) {
if (e && typeof e === 'object' && 'default' in e) return e;
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () { return e[k]; }
});
}
});
}
n.default = e;
return Object.freeze(n);
}
var H__namespace = /*#__PURE__*/_interopNamespaceCompat(H);
var React__default = /*#__PURE__*/_interopDefaultCompat(React);
var Skeleton__default = /*#__PURE__*/_interopDefaultCompat(Skeleton);
function isFetchError(e) {
return typeof e === "object" && e !== null && "status" in e && "data" in e;
}
let singletonInstance$8;
const setBackendSrv = (instance) => {
singletonInstance$8 = instance;
};
const getBackendSrv = () => singletonInstance$8;
let instance;
function setAngularLoader(v) {
instance = v;
}
function getAngularLoader() {
return instance;
}
let singletonInstance$7;
function setDataSourceSrv(instance) {
singletonInstance$7 = instance;
}
function getDataSourceSrv() {
return singletonInstance$7;
}
let singletonInstance$6;
function setLocationSrv(instance) {
singletonInstance$6 = instance;
}
function getLocationSrv() {
return singletonInstance$6;
}
var EchoEventType = /* @__PURE__ */ ((EchoEventType2) => {
EchoEventType2["Performance"] = "performance";
EchoEventType2["MetaAnalytics"] = "meta-analytics";
EchoEventType2["Pageview"] = "pageview";
EchoEventType2["Interaction"] = "interaction";
EchoEventType2["ExperimentView"] = "experimentview";
EchoEventType2["GrafanaJavascriptAgent"] = "grafana-javascript-agent";
return EchoEventType2;
})(EchoEventType || {});
let singletonInstance$5;
function setEchoSrv(instance) {
if (singletonInstance$5 instanceof FakeEchoSrv) {
for (const item of singletonInstance$5.buffer) {
instance.addEvent(item.event, item.meta);
}
}
singletonInstance$5 = instance;
}
function getEchoSrv() {
if (!singletonInstance$5) {
singletonInstance$5 = new FakeEchoSrv();
}
return singletonInstance$5;
}
const registerEchoBackend = (backend) => {
getEchoSrv().addBackend(backend);
};
class FakeEchoSrv {
constructor() {
this.buffer = [];
}
flush() {
this.buffer = [];
}
addBackend(backend) {
}
addEvent(event, meta) {
this.buffer.push({ event, meta });
}
}
let singletonInstance$4;
const setTemplateSrv = (instance) => {
singletonInstance$4 = instance;
};
const getTemplateSrv = () => singletonInstance$4;
let singleton$6;
const setLegacyAngularInjector = (instance) => {
singleton$6 = instance;
};
const getLegacyAngularInjector = () => singleton$6;
let singletonInstance$3;
const setGrafanaLiveSrv = (instance) => {
singletonInstance$3 = instance;
};
const getGrafanaLiveSrv = () => singletonInstance$3;
class GrafanaBootConfig {
constructor(options2) {
this.publicDashboardsEnabled = true;
this.snapshotEnabled = true;
this.datasources = {};
this.panels = {};
this.apps = {};
this.auth = {};
this.minRefreshInterval = "";
this.appUrl = "";
this.appSubUrl = "";
this.namespace = "default";
this.windowTitlePrefix = "";
this.newPanelTitle = "";
this.externalUserMngLinkUrl = "";
this.externalUserMngLinkName = "";
this.externalUserMngInfo = "";
this.externalUserMngAnalytics = false;
this.externalUserMngAnalyticsParams = "";
this.allowOrgCreate = false;
this.feedbackLinksEnabled = true;
this.disableLoginForm = false;
this.defaultDatasource = "";
// UID
this.angularSupportEnabled = false;
this.authProxyEnabled = false;
this.exploreEnabled = false;
this.queryHistoryEnabled = false;
this.helpEnabled = false;
this.profileEnabled = false;
this.newsFeedEnabled = true;
this.ldapEnabled = false;
this.jwtHeaderName = "";
this.jwtUrlLogin = false;
this.sigV4AuthEnabled = false;
this.azureAuthEnabled = false;
this.secureSocksDSProxyEnabled = false;
this.samlEnabled = false;
this.samlName = "";
this.autoAssignOrg = true;
this.verifyEmailEnabled = false;
this.oauth = {};
this.rbacEnabled = true;
this.disableUserSignUp = false;
this.loginHint = "";
this.passwordHint = "";
this.loginError = undefined;
this.viewersCanEdit = false;
this.editorsCanAdmin = false;
this.disableSanitizeHtml = false;
this.trustedTypesDefaultPolicyEnabled = false;
this.cspReportOnlyEnabled = false;
this.liveEnabled = true;
this.featureToggles = {};
this.anonymousEnabled = false;
this.anonymousDeviceLimit = undefined;
this.licenseInfo = {};
this.rendererAvailable = false;
this.rendererVersion = "";
this.rendererDefaultImageWidth = 1e3;
this.rendererDefaultImageHeight = 500;
this.rendererDefaultImageScale = 1;
this.secretsManagerPluginEnabled = false;
this.supportBundlesEnabled = false;
this.http2Enabled = false;
this.grafanaJavascriptAgent = {
enabled: false,
customEndpoint: "",
apiKey: "",
allInstrumentationsEnabled: false,
errorInstrumentalizationEnabled: true,
consoleInstrumentalizationEnabled: false,
webVitalsInstrumentalizationEnabled: false,
tracingInstrumentalizationEnabled: false
};
this.pluginCatalogURL = "https://grafana.com/grafana/plugins/";
this.pluginAdminEnabled = true;
this.pluginAdminExternalManageEnabled = false;
this.pluginCatalogHiddenPlugins = [];
this.pluginCatalogManagedPlugins = [];
this.pluginCatalogPreinstalledPlugins = [];
this.pluginsCDNBaseURL = "";
this.expressionsEnabled = false;
this.awsAllowedAuthProviders = [];
this.awsAssumeRoleEnabled = false;
this.azure = {
managedIdentityEnabled: false,
workloadIdentityEnabled: false,
userIdentityEnabled: false,
userIdentityFallbackCredentialsEnabled: false,
azureEntraPasswordCredentialsEnabled: false
};
this.caching = {
enabled: false
};
this.unifiedAlertingEnabled = false;
this.unifiedAlerting = {
minInterval: "",
alertStateHistoryBackend: undefined,
alertStateHistoryPrimary: undefined
};
this.recordedQueries = {
enabled: true
};
this.featureHighlights = {
enabled: false
};
this.reporting = {
enabled: true
};
this.analytics = {
enabled: true
};
this.googleAnalytics4SendManualPageViews = false;
this.analyticsConsoleReporting = false;
this.dashboardPerformanceMetrics = [];
this.sqlConnectionLimits = {
maxOpenConns: 100,
maxIdleConns: 100,
connMaxLifetime: 14400
};
this.defaultDatasourceManageAlertsUiToggle = true;
this.enableFrontendSandboxForPlugins = [];
this.cloudMigrationFeedbackURL = "";
this.cloudMigrationPollIntervalMs = 2e3;
this.exploreDefaultTimeOffset = "1h";
this.bootData = options2.bootData;
const defaults = {
datasources: {},
windowTitlePrefix: "Grafana - ",
panels: {},
newPanelTitle: "Panel Title",
playlist_timespan: "1m",
unsaved_changes_warning: true,
appUrl: "",
appSubUrl: "",
buildInfo: {
version: "1.0",
commit: "1",
env: "production"
},
viewersCanEdit: false,
editorsCanAdmin: false,
disableSanitizeHtml: false
};
lodash.merge(this, defaults, options2);
this.buildInfo = options2.buildInfo || defaults.buildInfo;
if (this.dateFormats) {
data.systemDateFormats.update(this.dateFormats);
}
overrideFeatureTogglesFromUrl(this);
overrideFeatureTogglesFromLocalStorage(this);
if (this.featureToggles.disableAngular) {
this.angularSupportEnabled = false;
}
this.theme2 = data.getThemeById(this.bootData.user.theme);
this.bootData.user.lightTheme = this.theme2.isLight;
this.theme = this.theme2.v1;
}
}
function overrideFeatureTogglesFromLocalStorage(config2) {
const featureToggles = config2.featureToggles;
const localStorageKey = "grafana.featureToggles";
const localStorageValue = window.localStorage.getItem(localStorageKey);
if (localStorageValue) {
const features = localStorageValue.split(",");
for (const feature of features) {
const [featureName, featureValue] = feature.split("=");
const toggleState = featureValue === "true" || featureValue === "1";
featureToggles[featureName] = toggleState;
console.log(`Setting feature toggle ${featureName} = ${toggleState} via localstorage`);
}
}
}
function overrideFeatureTogglesFromUrl(config2) {
if (window.location.href.indexOf("__feature") === -1) {
return;
}
const isDevelopment = config2.buildInfo.env === "development";
const safeRuntimeFeatureFlags = /* @__PURE__ */ new Set(["queryServiceFromUI", "dashboardSceneSolo"]);
const params = new URLSearchParams(window.location.search);
params.forEach((value, key) => {
if (key.startsWith("__feature.")) {
const featureToggles = config2.featureToggles;
const featureName = key.substring(10);
const toggleState = value === "true" || value === "";
if (toggleState !== featureToggles[key]) {
if (isDevelopment || safeRuntimeFeatureFlags.has(featureName)) {
featureToggles[featureName] = toggleState;
console.log(`Setting feature toggle ${featureName} = ${toggleState} via url`);
} else {
console.log(`Unable to change feature toggle ${featureName} via url in production.`);
}
}
}
});
}
const bootData = window.grafanaBootData || {
settings: {},
user: {},
navTree: []
};
const options = bootData.settings;
options.bootData = bootData;
const config = new GrafanaBootConfig(options);
class HistoryWrapper {
constructor(history) {
var _a;
this.history = history || (process.env.NODE_ENV === "test" ? H__namespace.createMemoryHistory({ initialEntries: ["/"] }) : H__namespace.createBrowserHistory({ basename: (_a = config.appSubUrl) != null ? _a : "/" }));
this.locationObservable = new rxjs.BehaviorSubject(this.history.location);
this.history.listen((location) => {
this.locationObservable.next(location);
});
this.partial = this.partial.bind(this);
this.push = this.push.bind(this);
this.replace = this.replace.bind(this);
this.getSearch = this.getSearch.bind(this);
this.getHistory = this.getHistory.bind(this);
this.getLocation = this.getLocation.bind(this);
}
getLocationObservable() {
return this.locationObservable.asObservable();
}
getHistory() {
return this.history;
}
getSearch() {
return new URLSearchParams(this.history.location.search);
}
partial(query, replace) {
const currentLocation = this.history.location;
const newQuery = this.getSearchObject();
for (const key in query) {
if (query[key] === null || query[key] === undefined) {
delete newQuery[key];
} else {
newQuery[key] = query[key];
}
}
const updatedUrl = data.urlUtil.renderUrl(currentLocation.pathname, newQuery);
if (replace) {
this.history.replace(updatedUrl, this.history.location.state);
} else {
this.history.push(updatedUrl, this.history.location.state);
}
}
push(location) {
this.history.push(location);
}
replace(location) {
this.history.replace(location);
}
reload() {
var _a;
const prevState = (_a = this.history.location.state) == null ? undefined : _a.routeReloadCounter;
this.history.replace({
...this.history.location,
state: { routeReloadCounter: prevState ? prevState + 1 : 1 }
});
}
getLocation() {
return this.history.location;
}
getSearchObject() {
return locationSearchToObject(this.history.location.search);
}
/** @deprecated use partial, push or replace instead */
update(options) {
data.deprecationWarning("LocationSrv", "update", "partial, push or replace");
if (options.partial && options.query) {
this.partial(options.query, options.partial);
} else {
const newLocation = {
pathname: options.path
};
if (options.query) {
newLocation.search = data.urlUtil.toUrlParams(options.query);
}
if (options.replace) {
this.replace(newLocation);
} else {
this.push(newLocation);
}
}
}
}
function locationSearchToObject(search) {
let queryString = typeof search === "number" ? String(search) : search;
if (queryString.length > 0) {
if (queryString.startsWith("?")) {
return data.urlUtil.parseKeyValue(queryString.substring(1));
}
return data.urlUtil.parseKeyValue(queryString);
}
return {};
}
exports.locationService = new HistoryWrapper();
const setLocationService = (location) => {
if (process.env.NODE_ENV !== "test") {
throw new Error("locationService can be only overriden in test environment");
}
exports.locationService = location;
};
const navigationLog = ui.createLogger("Router");
const navigationLogger = navigationLog.logger;
ui.attachDebugger("location", exports.locationService, navigationLog);
const LocationServiceContext = React__default.default.createContext(undefined);
function useLocationService() {
const service = React.useContext(LocationServiceContext);
if (!service) {
throw new Error("useLocationService must be used within a LocationServiceProvider");
}
return service;
}
const LocationServiceProvider = ({
service,
children
}) => {
return /* @__PURE__ */ jsxRuntime.jsx(LocationServiceContext.Provider, { value: service, children });
};
class RefreshEvent extends data.BusEventBase {
}
RefreshEvent.type = "refresh";
class ThemeChangedEvent extends data.BusEventWithPayload {
}
ThemeChangedEvent.type = "theme-changed";
class TimeRangeUpdatedEvent extends data.BusEventWithPayload {
}
TimeRangeUpdatedEvent.type = "time-range-updated";
class CopyPanelEvent extends data.BusEventWithPayload {
}
CopyPanelEvent.type = "copy-panel";
let singletonInstance$2;
function setAppEvents(instance) {
singletonInstance$2 = instance;
}
function getAppEvents() {
return singletonInstance$2;
}
const reportMetaAnalytics = (payload) => {
getEchoSrv().addEvent({
type: EchoEventType.MetaAnalytics,
payload
});
};
const reportPageview = () => {
var _a;
const location = exports.locationService.getLocation();
const page = `${(_a = config.appSubUrl) != null ? _a : ""}${location.pathname}${location.search}${location.hash}`;
getEchoSrv().addEvent({
type: EchoEventType.Pageview,
payload: {
page
}
});
};
const reportInteraction = (interactionName, properties) => {
if (config.reportingStaticContext && config.reportingStaticContext instanceof Object) {
properties = { ...properties, ...config.reportingStaticContext };
}
getEchoSrv().addEvent({
type: EchoEventType.Interaction,
payload: {
interactionName,
properties
}
});
};
const reportExperimentView = (id, group, variant) => {
getEchoSrv().addEvent({
type: EchoEventType.ExperimentView,
payload: {
experimentId: id,
experimentGroup: group,
experimentVariant: variant
}
});
};
const ALLOW_ROUTES = [
/(^\/d\/)/,
// dashboards
/^\/explore/,
// explore + explore metrics
/^\/a\/[^\/]+/,
// app plugins
/^\/alerting/
];
class SidecarService_EXPERIMENTAL {
constructor(mainLocationService2) {
// If true we don't close the sidecar when user navigates to another app or part of Grafana from where the sidecar
// was opened.
this.follow = false;
this.mainOnAllowedRoute = false;
this._initialContext = new rxjs.BehaviorSubject(undefined);
this.mainLocationService = mainLocationService2;
this.sidecarLocationService = new HistoryWrapper(
createLocationStorageHistory({ storageKey: "grafana.sidecar.history" })
);
this.handleMainLocationChanges();
}
assertFeatureEnabled() {
if (!config.featureToggles.appSidecar) {
console.warn("The `appSidecar` feature toggle is not enabled, doing nothing.");
return false;
}
return true;
}
updateMainLocationWhenOpened() {
var _a;
const pathname = this.mainLocationService.getLocation().pathname;
for (const route of ALLOW_ROUTES) {
const match = (_a = pathname.match(route)) == null ? undefined : _a[0];
if (match) {
this.mainLocationWhenOpened = match;
return;
}
}
}
/**
* Every time the main location changes we check if we should keep the sidecar open or close it based on list
* of allowed routes and also based on the follow flag when opening the app.
*/
handleMainLocationChanges() {
this.mainOnAllowedRoute = ALLOW_ROUTES.some(
(prefix) => this.mainLocationService.getLocation().pathname.match(prefix)
);
this.mainLocationService.getLocationObservable().subscribe((location) => {
this.mainOnAllowedRoute = ALLOW_ROUTES.some((prefix) => location.pathname.match(prefix));
if (!this.activePluginId) {
return;
}
if (!this.mainOnAllowedRoute) {
this.closeApp();
return;
}
const isTheSameLocation = Boolean(
this.mainLocationWhenOpened && location.pathname.startsWith(this.mainLocationWhenOpened)
);
if (!(isTheSameLocation || this.follow)) {
this.closeApp();
}
});
}
/**
* Get current app id of the app in sidecar. This is most probably provisional. In the future
* this should be driven by URL addressing so that routing for the apps don't change. Useful just internally
* to decide which app to render.
*
* @experimental
*/
get activePluginIdObservable() {
return this.sidecarLocationService.getLocationObservable().pipe(
rxjs.map((val) => {
return getPluginIdFromUrl((val == null ? undefined : val.pathname) || "");
})
);
}
/**
* Get initial context which is whatever data was passed when calling the 'openApp' function. This is meant as
* a way for the app to initialize it's state based on some context that is passed to it from the primary app.
*
* @experimental
*/
get initialContextObservable() {
return this._initialContext.asObservable();
}
// Get the current value of the subject, this is needed if we want the value immediately. For example if used in
// hook in react with useObservable first render would return undefined even if the behaviourSubject has some
// value which will be emitted in the next tick and thus next rerender.
get initialContext() {
return this._initialContext.getValue();
}
/**
* @experimental
*/
get activePluginId() {
return getPluginIdFromUrl(this.sidecarLocationService.getLocation().pathname);
}
getLocationService() {
return this.sidecarLocationService;
}
/**
* Opens an app in a sidecar. You can also pass some context object that will be then available to the app.
* @deprecated
* @experimental
*/
openApp(pluginId, context) {
if (!(this.assertFeatureEnabled() && this.mainOnAllowedRoute)) {
return;
}
this._initialContext.next(context);
this.openAppV3({ pluginId, follow: false });
}
/**
* Opens an app in a sidecar. You can also relative path inside the app to open.
* @deprecated
* @experimental
*/
openAppV2(pluginId, path) {
this.openAppV3({ pluginId, path, follow: false });
}
/**
* Opens an app in a sidecar. You can also relative path inside the app to open.
* @param options.pluginId Plugin ID of the app to open
* @param options.path Relative path inside the app to open
* @param options.follow If true, the sidecar will stay open even if the main location change to another app or
* Grafana section
*
* @experimental
*/
openAppV3(options) {
if (!(this.assertFeatureEnabled() && this.mainOnAllowedRoute)) {
return;
}
this.follow = options.follow || false;
this.updateMainLocationWhenOpened();
this.sidecarLocationService.push({ pathname: `/a/${options.pluginId}${options.path || ""}` });
reportInteraction("sidecar_service_open_app", { pluginId: options.pluginId, follow: options.follow });
}
/**
* @experimental
*/
closeApp() {
if (!this.assertFeatureEnabled()) {
return;
}
this.follow = false;
this.mainLocationWhenOpened = undefined;
this._initialContext.next(undefined);
this.sidecarLocationService.replace({ pathname: "/" });
reportInteraction("sidecar_service_close_app");
}
/**
* This is mainly useful inside an app extensions which are executed outside the main app context but can work
* differently depending on whether their app is currently rendered or not.
*
* This is also true only in case a sidecar is opened. In other cases, just to check if a single app is opened
* probably does not make sense.
*
* This means these are the states and the result of this function:
* Single app is opened: false (may seem strange from considering the function name, but the main point of
* this is to recognize when the app needs to do specific alteration in context of running next to second app)
* 2 apps are opened and pluginId is the one in the main window: true
* 2 apps are opened and pluginId is the one in the sidecar window: true
* 2 apps are opened and pluginId is not one of those: false
*
* @experimental
*/
isAppOpened(pluginId) {
if (!this.assertFeatureEnabled()) {
return false;
}
const result = !!(this.activePluginId && (this.activePluginId === pluginId || getMainAppPluginId() === pluginId));
reportInteraction("sidecar_service_is_app_opened", { pluginId, isOpened: result });
return result;
}
}
const pluginIdUrlRegex = /a\/([^\/]+)/;
function getPluginIdFromUrl(url) {
var _a;
return (_a = url.match(pluginIdUrlRegex)) == null ? undefined : _a[1];
}
function getMainAppPluginId() {
const { pathname } = exports.locationService.getLocation();
let mainApp = getPluginIdFromUrl(pathname);
if (!mainApp && pathname.match(/\/explore/)) {
mainApp = "explore";
}
if (!mainApp && pathname.match(/\/d\//)) {
mainApp = "dashboards";
}
return mainApp || "unknown";
}
function createLocationStorageHistory(options) {
const storedLocation = localStorage.getItem(options.storageKey);
const initialEntry = storedLocation ? JSON.parse(storedLocation) : "/";
const locationSubject = new rxjs.BehaviorSubject(initialEntry);
const memoryHistory = H__namespace.createMemoryHistory({ initialEntries: [initialEntry] });
let currentLocation = memoryHistory.location;
function maybeUpdateLocation() {
if (memoryHistory.location !== currentLocation) {
localStorage.setItem(
options.storageKey,
JSON.stringify(lodash.pick(memoryHistory.location, "pathname", "search", "hash"))
);
currentLocation = memoryHistory.location;
locationSubject.next(memoryHistory.location);
}
}
return {
...memoryHistory,
// Getter aren't destructured as getter but as values, so they have to be still here even though we are not
// modifying them.
get index() {
return memoryHistory.index;
},
get entries() {
return memoryHistory.entries;
},
get length() {
return memoryHistory.length;
},
get action() {
return memoryHistory.action;
},
get location() {
return memoryHistory.location;
},
push(location, state) {
memoryHistory.push(location, state);
maybeUpdateLocation();
},
replace(location, state) {
memoryHistory.replace(location, state);
maybeUpdateLocation();
},
go(n) {
memoryHistory.go(n);
maybeUpdateLocation();
},
goBack() {
memoryHistory.goBack();
maybeUpdateLocation();
},
goForward() {
memoryHistory.goForward();
maybeUpdateLocation();
},
getLocationObservable() {
return locationSubject.asObservable();
}
};
}
const sidecarServiceSingleton_EXPERIMENTAL = new SidecarService_EXPERIMENTAL(exports.locationService);
const SidecarContext_EXPERIMENTAL = React.createContext(
sidecarServiceSingleton_EXPERIMENTAL
);
function useSidecar_EXPERIMENTAL() {
const service = React.useContext(SidecarContext_EXPERIMENTAL);
if (!service) {
throw new Error("No SidecarContext found");
}
const initialContext = reactUse.useObservable(service.initialContextObservable, service.initialContext);
const activePluginId = reactUse.useObservable(service.activePluginIdObservable, service.activePluginId);
const locationService = service.getLocationService();
return {
activePluginId,
initialContext,
locationService,
// TODO: currently this allows anybody to open any app, in the future we should probably scope this to the
// current app but that means we will need to incorporate this better into the plugin platform APIs which
// we will do once the functionality is reasonably stable
openApp: (pluginId, context) => {
return service.openApp(pluginId, context);
},
openAppV2: (pluginId, path) => {
return service.openAppV2(pluginId, path);
},
openAppV3: (options) => {
return service.openAppV3(options);
},
closeApp: () => service.closeApp(),
isAppOpened: (pluginId) => {
return service.isAppOpened(pluginId);
}
};
}
function isPluginExtensionLink(extension) {
if (!extension) {
return false;
}
return extension.type === data.PluginExtensionTypes.link && ("path" in extension || "onClick" in extension);
}
function isPluginExtensionComponent(extension) {
if (!extension) {
return false;
}
return extension.type === data.PluginExtensionTypes.component && "component" in extension;
}
let singleton$5;
function setPluginExtensionGetter(instance) {
if (singleton$5 && process.env.NODE_ENV !== "test") {
throw new Error("setPluginExtensionGetter() function should only be called once, when Grafana is starting.");
}
singleton$5 = instance;
}
function getPluginExtensionGetter() {
if (!singleton$5) {
throw new Error("getPluginExtensionGetter() can only be used after the Grafana instance has started.");
}
return singleton$5;
}
const getPluginExtensions = (options) => getPluginExtensionGetter()(options);
const getPluginLinkExtensions = (options) => {
const { extensions } = getPluginExtensions(options);
return {
extensions: extensions.filter(isPluginExtensionLink)
};
};
const getPluginComponentExtensions = (options) => {
const { extensions } = getPluginExtensions(options);
const componentExtensions = extensions.filter(isPluginExtensionComponent);
return {
extensions: componentExtensions
};
};
let singleton$4;
function setPluginExtensionsHook(hook) {
if (singleton$4 && process.env.NODE_ENV !== "test") {
throw new Error("setPluginExtensionsHook() function should only be called once, when Grafana is starting.");
}
singleton$4 = hook;
}
function usePluginExtensions(options) {
if (!singleton$4) {
throw new Error("usePluginExtensions(options) can only be used after the Grafana instance has started.");
}
return singleton$4(options);
}
function usePluginLinkExtensions(options) {
const { extensions, isLoading } = usePluginExtensions(options);
return React.useMemo(() => {
return {
extensions: extensions.filter(isPluginExtensionLink),
isLoading
};
}, [extensions, isLoading]);
}
function usePluginComponentExtensions(options) {
const { extensions, isLoading } = usePluginExtensions(options);
return React.useMemo(
() => ({
extensions: extensions.filter(isPluginExtensionComponent),
isLoading
}),
[extensions, isLoading]
);
}
let singleton$3;
function setPluginComponentHook(hook) {
if (singleton$3 && process.env.NODE_ENV !== "test") {
throw new Error("setPluginComponentHook() function should only be called once, when Grafana is starting.");
}
singleton$3 = hook;
}
function usePluginComponent(componentId) {
if (!singleton$3) {
throw new Error("setPluginComponentHook(options) can only be used after the Grafana instance has started.");
}
return singleton$3(componentId);
}
let singleton$2;
function setPluginComponentsHook(hook) {
if (singleton$2 && process.env.NODE_ENV !== "test") {
throw new Error("setPluginComponentsHook() function should only be called once, when Grafana is starting.");
}
singleton$2 = hook;
}
function usePluginComponents(options) {
if (!singleton$2) {
throw new Error("setPluginComponentsHook(options) can only be used after the Grafana instance has started.");
}
return singleton$2(options);
}
let singleton$1;
function setPluginLinksHook(hook) {
if (singleton$1 && process.env.NODE_ENV !== "test") {
throw new Error("setPluginLinksHook() function should only be called once, when Grafana is starting.");
}
singleton$1 = hook;
}
function usePluginLinks(options) {
if (!singleton$1) {
throw new Error("setPluginLinksHook(options) can only be used after the Grafana instance has started.");
}
return singleton$1(options);
}
let singleton;
function setPluginFunctionsHook(hook) {
if (singleton && process.env.NODE_ENV !== "test") {
throw new Error("setUsePluginFunctionsHook() function should only be called once, when Grafana is starting.");
}
singleton = hook;
}
function usePluginFunctions(options) {
if (!singleton) {
throw new Error("usePluginFunctions(options) can only be used after the Grafana instance has started.");
}
return singleton(options);
}
let singletonInstance$1 = null;
function setCurrentUser(instance) {
if (singletonInstance$1) {
throw new Error("User should only be set once, when Grafana is starting.");
}
singletonInstance$1 = instance;
}
function getCurrentUser() {
if (!singletonInstance$1) {
throw new Error("User can only be used after Grafana instance has started.");
}
return singletonInstance$1;
}
class RuntimeDataSource extends data.DataSourceApi {
constructor(pluginId, uid) {
const instanceSettings = {
name: "RuntimeDataSource-" + pluginId,
uid,
type: pluginId,
id: 1,
readOnly: true,
jsonData: {},
access: "direct",
meta: {
id: pluginId,
name: "RuntimeDataSource-" + pluginId,
type: data.PluginType.datasource,
info: {
author: {
name: ""
},
description: "",
links: [],
logos: {
large: "",
small: ""
},
screenshots: [],
updated: "",
version: ""
},
module: "",
baseUrl: ""
}
};
super(instanceSettings);
this.instanceSettings = instanceSettings;
}
testDatasource() {
return Promise.resolve({
status: "success",
message: ""
});
}
}
const ScopesContext = React.createContext(undefined);
function useScopes() {
var _a;
const context = React.useContext(ScopesContext);
reactUse.useObservable((_a = context == null ? undefined : context.stateObservable) != null ? _a : new rxjs.Observable(), context == null ? undefined : context.state);
return context ? {
state: context.state,
stateObservable: context.stateObservable,
changeScopes: context.changeScopes,
setReadOnly: context.setReadOnly,
setEnabled: context.setEnabled
} : undefined;
}
var MetaAnalyticsEventName = /* @__PURE__ */ ((MetaAnalyticsEventName2) => {
MetaAnalyticsEventName2["DashboardView"] = "dashboard-view";
MetaAnalyticsEventName2["DataRequest"] = "data-request";
return MetaAnalyticsEventName2;
})(MetaAnalyticsEventName || {});
const isPageviewEvent = (event) => {
return Boolean(event.payload.page);
};
const isInteractionEvent = (event) => {
return Boolean(event.payload.interactionName);
};
const isExperimentViewEvent = (event) => {
return Boolean(event.payload.experimentId);
};
async function loadPluginCss(options) {
try {
const cssPath = config.bootData.user.theme === "light" ? options.light : options.dark;
return window.System.import(cssPath);
} catch (err) {
console.error(err);
}
}
let pluginImportUtils;
function setPluginImportUtils(utils) {
if (pluginImportUtils) {
throw new Error("pluginImportUtils should only be set once, when Grafana is starting.");
}
pluginImportUtils = utils;
}
function getPluginImportUtils() {
if (!pluginImportUtils) {
throw new Error("pluginImportUtils can only be used after Grafana instance has started.");
}
return pluginImportUtils;
}
const featureEnabled = (feature) => {
const { enabledFeatures } = config.licenseInfo;
return enabledFeatures && enabledFeatures[feature];
};
function logInfo(message, contexts) {
if (config.grafanaJavascriptAgent.enabled) {
faroWebSdk.faro.api.pushLog([message], {
level: faroWebSdk.LogLevel.INFO,
context: contexts
});
}
}
function logWarning(message, contexts) {
if (config.grafanaJavascriptAgent.enabled) {
faroWebSdk.faro.api.pushLog([message], {
level: faroWebSdk.LogLevel.WARN,
context: contexts
});
}
}
function logDebug(message, contexts) {
if (config.grafanaJavascriptAgent.enabled) {
faroWebSdk.faro.api.pushLog([message], {
level: faroWebSdk.LogLevel.DEBUG,
context: contexts
});
}
}
function logError(err, contexts) {
if (config.grafanaJavascriptAgent.enabled) {
faroWebSdk.faro.api.pushError(err, {
context: contexts
});
}
}
function logMeasurement(type, values, context) {
if (config.grafanaJavascriptAgent.enabled) {
faroWebSdk.faro.api.pushMeasurement(
{
type,
values
},
{ context }
);
}
}
function createMonitoringLogger(source, defaultContext) {
const createFullContext = (contexts) => ({
source,
...defaultContext,
...contexts
});
return {
/**
* Logs a debug message with optional additional context.
* @param {string} message - The debug message to be logged.
* @param {LogContext} [contexts] - Optional additional context to be included.
*/
logDebug: (message, contexts) => logDebug(message, createFullContext(contexts)),
/**
* Logs an informational message with optional additional context.
* @param {string} message - The informational message to be logged.
* @param {LogContext} [contexts] - Optional additional context to be included.
*/
logInfo: (message, contexts) => logInfo(message, createFullContext(contexts)),
/**
* Logs a warning message with optional additional context.
* @param {string} message - The warning message to be logged.
* @param {LogContext} [contexts] - Optional additional context to be included.
*/
logWarning: (message, contexts) => logWarning(message, createFullContext(contexts)),
/**
* Logs an error with optional additional context.
* @param {Error} error - The error object to be logged.
* @param {LogContext} [contexts] - Optional additional context to be included.
*/
logError: (error, contexts) => logError(error, createFullContext(contexts)),
/**
* Logs an measurement with optional additional context.
* @param {MeasurementEvent} measurement - The measurement object to be recorded.
* @param {LogContext} [contexts] - Optional additional context to be included.
*/
logMeasurement: (type, measurement, contexts) => logMeasurement(type, measurement, createFullContext(contexts))
};
}
function toDataQueryError(err) {
var _a, _b, _c;
const error = err || {};
if (!error.message) {
if (typeof err === "string") {
return { message: err };
}
let message = "Query error";
if (error.message) {
message = error.message;
} else if (error.data && error.data.message && ((_a = error.data) == null ? undefined : _a.message) !== "Query data error") {
message = error.data.message;
} else if (((_b = error == null ? undefined : error.data) == null ? undefined : _b.message) === "Query data error" && ((_c = error == null ? undefined : error.data) == null ? undefined : _c.error)) {
message = error.data.error;
} else if (error.data && error.data.error) {
message = error.data.error;
} else if (error.status) {
message = `Query error: ${error.status} ${error.statusText}`;
}
error.message = message;
}
return error;
}
const cachedResponseNotice = { severity: "info", text: "Cached response" };
function toDataQueryResponse(res, queries) {
var _a, _b, _c, _d;
const rsp = { data: [], state: data.LoadingState.Done };
const traceId = "traceId" in res ? res.traceId : undefined;
if (traceId != null) {
rsp.traceIds = [traceId];
}
const fetchResponse = res;
if ((_a = fetchResponse.data) == null ? undefined : _a.results) {
const results = fetchResponse.data.results;
const refIDs = (queries == null ? undefined : queries.length) ? queries.map((q) => q.refId) : Object.keys(results);
const cachedResponse = isCachedResponse(fetchResponse);
const data$1 = [];
for (const refId of refIDs) {
const dr = results[refId];
if (!dr) {
continue;
}
dr.refId = refId;
data$1.push(dr);
}
for (const dr of data$1) {
if (dr.error) {
const errorObj = {
refId: dr.refId,
message: dr.error,
status: dr.status
};
if (traceId != null) {
errorObj.traceId = traceId;
}
if (!rsp.error) {
rsp.error = { ...errorObj };
}
if (rsp.errors) {
rsp.errors.push({ ...errorObj });
} else {
rsp.errors = [{ ...errorObj }];
}
rsp.state = data.LoadingState.Error;
}
if ((_b = dr.frames) == null ? undefined : _b.length) {
for (let js of dr.frames) {
if (cachedResponse) {
js = addCacheNotice(js);
}
const df = data.dataFrameFromJSON(js);
if (!df.refId) {
df.refId = dr.refId;
}
rsp.data.push(df);
}
continue;
}
if ((_c = dr.series) == null ? undefined : _c.length) {
for (const s of dr.series) {
if (!s.refId) {
s.refId = dr.refId;
}
rsp.data.push(data.toDataFrame(s));
}
}
if ((_d = dr.tables) == null ? undefined : _d.length) {
for (const s of dr.tables) {
if (!s.refId) {
s.refId = dr.refId;
}
rsp.data.push(data.toDataFrame(s));
}
}
}
}
if (fetchResponse.status && fetchResponse.status !== 200) {
if (rsp.state !== data.LoadingState.Error) {
rsp.state = data.LoadingState.Error;
}
if (!rsp.error) {
rsp.error = toDataQueryError(res);
}
}
return rsp;
}
function isCachedResponse(res) {
const headers = res == null ? undefined : res.headers;
if (!headers || !headers.get) {
return false;
}
return headers.get("X-Cache") === "HIT";
}
function addCacheNotice(frame) {
var _a, _b, _c, _d, _e, _f;
return {
...frame,
schema: {
...frame.schema,
fields: [...(_b = (_a = frame.schema) == null ? undefined : _a.fields) != null ? _b : []],
meta: {
...(_c = frame.schema) == null ? undefined : _c.meta,
notices: [...(_f = (_e = (_d = frame.schema) == null ? undefined : _d.meta) == null ? undefined : _e.notices) != null ? _f : [], cachedResponseNotice],
isCachedResponse: true
}
}
};
}
function frameToMetricFindValue(frame) {
if (!frame || !frame.length) {
return [];
}
const values = [];
let field = frame.fields.find((f) => f.type === data.FieldType.string);
if (!field) {
field = frame.fields.find((f) => f.type !== data.FieldType.time);
}
if (field) {
for (let i = 0; i < field.values.length; i++) {
values.push({ text: "" + field.values[i] });
}
}
return values;
}
function publicDashboardQueryHandler(request) {
const {
intervalMs,
maxDataPoints,
requestId,
panelId,
queryCachingTTL,
range: { from: fromRange, to: toRange }
} = request;
if (!request.targets.length) {
return rxjs.of({ data: [] });
}
const body = {
intervalMs,
maxDataPoints,
queryCachingTTL,
timeRange: {
from: fromRange.valueOf().toString(),
to: toRange.valueOf().toString(),
timezone: request.timezone
}
};
return getBackendSrv().fetch({
url: `/api/public/dashboards/${config.publicDashboardAccessToken}/panels/${panelId}/query`,
method: "POST",
data: body,
requestId
}).pipe(
rxjs.switchMap((raw) => {
return rxjs.of(toDataQueryResponse(raw, request.targets));
}),
rxjs.catchError((err) => {
return rxjs.of(toDataQueryResponse(err));
})
);
}
const ExpressionDatasourceRef = Object.freeze({
type: "__expr__",
uid: "__expr__",
name: "Expression"
});
function isExpressionReference(ref) {
if (!ref) {
return false;
}
const v = typeof ref === "string" ? ref : ref.type;
return v === ExpressionDatasourceRef.type || v === ExpressionDatasourceRef.name || v === "-100";
}
class HealthCheckError extends Error {
constructor(message, details) {
super(message);
this.details = details;
this.name = "HealthCheckError";
}
}
var HealthStatus = /* @__PURE__ */ ((HealthStatus2) => {
HealthStatus2["Unknown"] = "UNKNOWN";
HealthStatus2["OK"] = "OK";
HealthStatus2["Error"] = "ERROR";
return HealthStatus2;
})(HealthStatus || {});
class DataSourceWithBackend extends data.DataSourceApi {
constructor(instanceSettings) {
super(instanceSettings);
/**
* Optionally override the streaming behavior
*/
this.streamOptionsProvider = standardStreamOptionsProvider;
}
/**
* Ideally final -- any other implementation may not work as expected
*/
query(request) {
var _a;
if (config.publicDashboardAccessToken) {
return publicDashboardQueryHandler(request);
}
const { intervalMs, maxDataPoints, queryCachingTTL, range, requestId, hideFromInspector = false } = request;
let targets = request.targets;
let hasExpr = false;
const pluginIDs = /* @__PURE__ */ new Set();
const dsUIDs = /* @__PURE__ */ new Set();
const queries = targets.map((q) => {
var _a2, _b, _c;
let datasource = this.getRef();
let datasourceId = this.id;
let shouldApplyTemplateVariables = true;
if (isExpressionReference(q.datasource)) {
hasExpr = true;
return {
...q,
datasource: ExpressionDatasourceRef
};
}
if (q.datasource) {
const ds = getDataSourceSrv().getInstanceSettings(q.datasource, request.scopedVars);
if (!ds) {
throw new Error(`Unknown Datasource: ${JSON.stringify(q.datasource)}`);
}
const dsRef = (_a2 = ds.rawRef) != null ? _a2 : data.getDataSourceRef(ds);
const dsId = ds.id;
if (dsRef.uid !== datasource.uid || datasourceId !== dsId) {
datasource = dsRef;
datasourceId = dsId;
shouldApplyTemplateVariables = false;
}
}
if ((_b = datasource.type) == null ? undefined : _b.length) {
pluginIDs.add(datasource.type);
}
if ((_c = datasource.uid) == null ? undefined : _c.length) {
dsUIDs.add(datasource.uid);
}
return {
...shouldApplyTemplateVariables ? this.applyTemplateVariables(q, request.scopedVars, request.filters) : q,
datasource,
datasourceId,
// deprecated!
intervalMs,
maxDataPoints,
queryCachingTTL
};
});
if (!queries.length) {
return rxjs.of({ data: [] });
}
const body = {
queries,
from: range == null ? undefined : range.from.valueOf().toString(),
to: range == null ? undefined : range.to.valueOf().toString()
};
if (config.featureToggles.queryOverLive) {
return getGrafanaLiveSrv().getQueryData({
request,
body
});
}
const headers = (_a = request.headers) != null ? _a : {};
headers["X-Plugin-Id" /* PluginID */] = Array.from(pluginIDs).join(", ");
headers["X-Datasource-Uid" /* DatasourceUID */] = Array.from(dsUIDs).join(", ");
let url = "/api/ds/query?ds_type=" + this.type;
if (config.featureToggles.queryServiceFromUI) {
if (!(config.featureToggles.queryService || config.featureToggles.grafanaAPIServerWithExperimentalAPIs)) {
console.warn("feature toggle queryServiceFromUI also requires the queryService to be running");
} else {
if (!hasExpr && dsUIDs.size === 1) ;
url = `/apis/query.grafana.app/v0alpha1/namespaces/${config.namespace}/query?ds_type=' + this.type`;
}
}
if (hasExpr) {
headers["X-Grafana-From-Expr" /* FromExpression */] = "true";
url += "&expression=true";
}
if (requestId) {
url += `&requestId=${requestId}`;
}
if (request.dashboardUID) {
headers["X-Dashboard-Uid" /* DashboardUID */] = request.dashboardUID;
if (request.panelId) {
headers["X-Panel-Id" /* PanelID */] = `${request.panelId}`;
}
}
if (request.panelPluginId) {
headers["X-Panel-Plugin-Id" /* PanelPluginId */] = `${request.panelPluginId}`;
}
if (request.queryGroupId) {
headers["X-Query-Group-Id" /* QueryGroupID */] = `${request.queryGroupId}`;
}
if (request.skipQueryCache) {
headers["X-Cache-Skip" /* SkipQueryCache */] = "true";
}
return getBackendSrv().fetch({
url,
method: "POST",
data: body,
requestId,
hideFromInspector,
headers
}).pipe(
operators.switchMap((raw) => {
var _a2;
const rsp = toDataQueryResponse(raw, queries);
if (((_a2 = rsp.data) == null ? undefined : _a2.length) && rsp.data.find((f) => {
var _a3;
return (_a3 = f.meta) == null ? undefined : _a3.channel;
})) {
return toStreamingDataResponse(rsp, request, this.streamOptionsProvider);
}
return rxjs.of(rsp);
}),
operators.catchError((err) => {
return rxjs.of(toDataQueryResponse(err));
})
);
}
/** Get request headers with plugin ID+UID set */
getRequestHeaders() {
const headers = {};
headers["X-Plugin-Id" /* PluginID */] = this.type;
headers["X-Datasource-Uid" /* DatasourceUID */] = this.uid;
return headers;
}
/**
* Apply template variables for explore
*/
interpolateVariablesInQueries(queries, scopedVars, filters) {
return queries.map((q) => this.applyTemplateVariables(q, scopedVars, filters));
}
/**
* Override to apply template variables and adhoc filters. The result is usually also `TQuery`, but sometimes this can
* be used to modify the query structure before sending to the backend.
*
* NOTE: if you do modify the structure or use template variables, alerting queries may not work
* as expected
*
* @virtual
*/
applyTemplateVariables(query, scopedVars, filters) {
return query;
}
/**
* Make a GET request to the datasource resource path
*/
async getResource(path, params, options) {
const headers = this.getRequestHeaders();
const result = await rxjs.lastValueFrom(
getBackendSrv().fetch({
...options,
method: "GET",
headers: (options == null ? undefined : options.headers) ? { ...options.headers, ...headers } : headers,
params: params != null ? params : options == null ? undefined : options.params,
url: `/api/datasources/uid/${this.uid}/resources/${path}`
})
);
return result.data;
}
/**
* Send a POST request to the datasource resource path
*/
async postResource(path, data, options) {
const headers = this.getRequestHeaders();
const result = await rxjs.lastValueFrom(
getBackendSrv().fetch({
...options,
method: "POST",
headers: (options == null ? undefined : options.headers) ? { ...options.headers, ...headers } : headers,
data: data != null ? data : { ...data },
url: `/api/datasources/uid/${this.uid}/resources/${path}`
})
);
return result.data;
}
/**
* Run the datasource healthcheck
*/
async callHealthCheck() {
return rxjs.lastValueFrom(
getBackendSrv().fetch({
method: "GET",
url: `/api/datasources/uid/${this.uid}/health`,
showErrorAlert: false,
headers: this.getRequestHeaders()
})
).then((v) => v.data).catch((err) => {
var _a, _b, _c, _d, _e;
let properties = {
plugin_id: ((_a = this.meta) == null ? undefined : _a.id) || "",
plugin_version: ((_c = (_b = this.meta) == null ? undefined : _b.info) == null ? undefined : _c.version) || "",
datasource_healthcheck_status: ((_d = err == null ? undefined : err.data) == null ? undefined : _d.status) || "error",
datasource_healthcheck_message: ((_e = err == null ? undefined : err.data) == null ? undefined : _e.message) || ""
};
reportInteraction("datasource_health_check_completed", properties);
return err.data;
});
}
/**
* Checks the plugin health
* see public/app/features/datasources/state/actions.ts for what needs to be returned here
*/
async testDatasource() {
return this.callHealthCheck().then((res) => {
if (res.status === "OK" /* OK */) {
return {
status: "success",
message: res.message
};
}
return Promise.reject({
status: "error",
message: res.message,
error: new HealthCheckError(res.message, res.details)
});
});
}
}
function toStreamingDataResponse(rsp, req, getter) {
var _a;
const live = getGrafanaLiveSrv();
if (!live) {
return rxjs.of(rsp);
}
const staticdata = [];
const streams = [];
for (const f of rsp.data) {
const addr = data.parseLiveChannelAddress((_a = f.meta) == null ? undefined : _a.channel);
if (addr) {
const frame = f;
streams.push(
live.getDataStream({
addr,
buffer: getter(req, frame),
frame: data.dataFrameToJSON(f)
})
);
} else {
staticdata.push(f);
}
}
if (staticdata.length) {
streams.push(rxjs.of({ ...rsp, data: staticdata }));
}
if (streams.length === 1) {
return streams[0];
}
return rxjs.merge(...streams);
}
const standardStreamOptionsProvider = (request, frame) => {
var _a, _b;
const opts = {
maxLength: (_a = request.maxDataPoints) != null ? _a : 500,
action: data.StreamingFrameAction.Append
};
if (((_b = request.rangeRaw) == null ? undefined : _b.to) === "now") {
opts.maxDelta = request.range.to.valueOf() - request.range.from.valueOf();
}
return opts;
};
DataSourceWithBackend = data.makeClassES5Compatible(DataSourceWithBackend);
let PanelRenderer = () => {
return /* @__PURE__ */ jsxRuntime.jsx("div", { children: "PanelRenderer can only be used after Grafana instance has been started." });
};
let PanelDataErrorView = ({ message }) => {
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
"Unable to render data: ",
message,
"."
] });
};
let factory;
const setQueryRunnerFactory = (instance) => {
if (factory) {
throw new Error("Runner should only be set when Grafana is starting.");
}
factory = instance;
};
const createQueryRunner = () => {
if (!factory) {
throw new Error("`createQueryRunner` can only be used after Grafana instance has started.");
}
return factory();
};
let runRequest;
function setRunRequest(fn) {
if (runRequest && process.env.NODE_ENV !== "test") {
throw new Error("runRequest function should only be set once, when Grafana is starting.");
}
runRequest = fn;
}
function getRunRequest() {
if (!runRequest) {
throw new Error("getRunRequest can only be used after Grafana instance has started.");
}
return runRequest;
}
let PluginPage = ({ children }) => {
return /* @__PURE__ */ jsxRuntime.jsx("div", { children });
};
class DataSourcePicker extends React.PureComponent {
constructor(props) {
super(props);
this.dataSourceSrv = getDataSourceSrv();
this.state = {};
this.onChange = (item, actionMeta) => {
if (actionMeta.action === "clear" && this.props.onClear) {
this.props.onClear();
return;
}
const dsSettings = this.dataSourceSrv.getInstanceSettings(item.value);
if (dsSettings) {
this.props.onChange(dsSettings);
this.setState({ error: undefined });
}
};
}
componentDidMount() {
const { current } = this.props;
const dsSettings = this.dataSourceSrv.getInstanceSettings(current);
if (!dsSettings) {
this.setState({ error: "Could not find data source " + current });
}
}
getCurrentValue() {
const { current, hideTextValue, noDefault } = this.props;
if (!current && noDefault) {
return;
}
const ds = this.dataSourceSrv.getInstanceSettings(current);
if (ds) {
return {
label: ds.name.slice(0, 37),
value: ds.uid,
imgUrl: ds.meta.info.logos.small,
hideText: hideTextValue,
meta: ds.meta
};
}
const uid = data.getDataSourceUID(current);
if (uid === ExpressionDatasourceRef.uid || uid === ExpressionDatasourceRef.name) {
return { label: uid, value: uid, hideText: hideTextValue };
}
return {
label: (uid != null ? uid : "no name") + " - not found",
value: uid != null ? uid : undefined,
imgUrl: "",
hideText: hideTextValue
};
}
getDataSourceOptions() {
const { alerting, tracing, metrics, mixed, dashboard, variables, annotations, pluginId, type, filter, logs } = this.props;
const options = this.dataSourceSrv.getList({
alerting,
tracing,
metrics,
logs,
dashboard,
mixed,
variables,
annotations,
pluginId,
filter,
type
}).map((ds) => ({
value: ds.name,
label: `${ds.name}${ds.isDefault ? " (default)" : ""}`,
imgUrl: ds.meta.info.logos.small,
meta: ds.meta
}));
return options;
}
render() {
const {
autoFocus,
onBlur,
onClear,
openMenuOnFocus,
placeholder,
width,
inputId,
disabled = false,
isLoading = false
} = this.props;
const { error } = this.state;
const options = this.getDataSourceOptions();
const value = this.getCurrentValue();
const isClearable = typeof onClear === "function";
return /* @__PURE__ */ jsxRuntime.jsx(
"div",
{
"aria-label": "Data source picker select container",
"data-testid": e2eSelectors.selectors.components.DataSourcePicker.container,
children: /* @__PURE__ */ jsxRuntime.jsx(
ui.Select,
{
isLoading,
disabled,
"aria-label": "Select a data source",
"data-testid": e2eSelectors.selectors.components.DataSourcePicker.inputV2,
inputId: inputId || "data-source-picker",
className: "ds-picker select-container",
isMulti: false,
isClearable,
backspaceRemovesValue: false,
onChange: this.onChange,
options,
autoFocus,
onBlur,
width,
openMenuOnFocus,
maxMenuHeight: 500,
placeholder,
noOptionsMessage: "No datasources found",
value: value != null ? value : null,
invalid: Boolean(error) || Boolean(this.props.invalid),
getOptionLabel: (o) => {
if (o.meta && data.isUnsignedPluginSignature(o.meta.signature) && o !== value) {
return /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { alignItems: "center", justifyContent: "space-between", children: [
/* @__PURE__ */ jsxRuntime.jsx("span", { children: o.label }),
" ",
/* @__PURE__ */ jsxRuntime.jsx(ui.PluginSignatureBadge, { status: o.meta.signature })
] });
}
return o.label || "";
}
}
)
}
);
}
}
DataSourcePicker.defaultProps = {
autoFocus: false,
openMenuOnFocus: false,
placeholder: "Select data source"
};
function createPluginEventProperties(meta) {
return {
grafana_version: config.buildInfo.version,
plugin_type: String(meta.type),
plugin_version: meta.info.version,
plugin_id: meta.id,
plugin_name: meta.name
};
}
function createDataSourcePluginEventProperties(instanceSettings) {
return {
...createPluginEventProperties(instanceSettings.meta),
datasource_uid: instanceSettings.uid
};
}
const namePrefix = "grafana_plugin_";
function usePluginInteractionReporter() {
const context = data.usePluginContext();
return React.useMemo(() => {
if (!context) {
throw new Error(
`No PluginContext found. The usePluginInteractionReporter() hook can only be used from a plugin.`
);
}
const info = data.isDataSourcePluginContext(context) ? createDataSourcePluginEventProperties(context.instanceSettings) : createPluginEventProperties(context.meta);
return (interactionName, properties) => {
if (!validInteractionName(interactionName)) {
throw new Error(`Interactions reported in plugins should start with: "${namePrefix}".`);
}
return reportInteraction(interactionName, { ...properties, ...info });
};
}, [context]);
}
function validInteractionName(interactionName) {
return interactionName.startsWith(namePrefix) && interactionName.length > namePrefix.length;
}
let rtpHook = undefined;
const setReturnToPreviousHook = (hook) => {
rtpHook = hook;
};
const useReturnToPrevious = () => {
if (!rtpHook) {
if (process.env.NODE_ENV !== "production") {
throw new Error("useReturnToPrevious hook not found in @grafana/runtime");
}
return () => console.error("ReturnToPrevious hook not found");
}
return rtpHook();
};
let chromeHeaderHeightHook = undefined;
const setChromeHeaderHeightHook = (hook) => {
chromeHeaderHeightHook = hook;
};
const useChromeHeaderHeight = () => {
if (!chromeHeaderHeightHook) {
if (process.env.NODE_ENV !== "production") {
throw new Error("useChromeHeaderHeight hook not found in @grafana/runtime");
}
console.error("useChromeHeaderHeight hook not found");
}
return chromeHeaderHeightHook == null ? undefined : chromeHeaderHeightHook();
};
exports.EmbeddedDashboard = () => {
throw new Error("EmbeddedDashboard requires runtime initialization");
};
function setEmbeddedDashboard(component) {
exports.EmbeddedDashboard = component;
}
const hasPermission = (action) => data.userHasPermission(action, getCurrentUser());
const hasPermissionInMetadata = (action, object) => data.userHasPermissionInMetadata(action, object);
const hasAllPermissions = (actions) => data.userHasAllPermissions(actions, getCurrentUser());
const hasAnyPermission = (actions) => data.userHasAnyPermission(actions, getCurrentUser());
function isMigrationHandler(object) {
return object instanceof DataSourceWithBackend && "hasBackendMigration" in object && "shouldMigrate" in object;
}
async function postMigrateRequest(queries) {
var _a, _b;
if (!(config.featureToggles.grafanaAPIServerWithExperimentalAPIs || config.featureToggles.datasourceAPIServers)) {
console.warn("migrateQuery is only available with the experimental API server");
return queries;
}
const dsnameURL = (_b = (_a = queries[0].datasource) == null ? undefined : _a.type) == null ? undefined : _b.replace(/^(grafana-)?(.*?)(-datasource)?$/, "$2");
const groupName = `${dsnameURL}.datasource.grafana.app`;
const apiVersion = "v0alpha1";
const url = `/apis/${groupName}/${apiVersion}/namespaces/${config.namespace}/queryconvert`;
const request = {
queries: queries.map((query) => {
return {
...query,
JSON: query
// JSON is not part of the type but it should be what holds the query
};
})
};
const res = await getBackendSrv().post(url, request);
return res.queries.map((query) => query.JSON);
}
async function migrateQuery(datasource, query) {
if (!datasource.hasBackendMigration || !datasource.shouldMigrate(query)) {
return query;
}
const res = await postMigrateRequest([query]);
return res[0];
}
async function migrateRequest(datasource, request) {
if (!datasource.hasBackendMigration || !request.targets.some((query) => datasource.shouldMigrate(query))) {
return request;
}
const res = await postMigrateRequest(request.targets);
return { ...request, targets: res };
}
function QueryEditorWithMigration(QueryEditor) {
const WithExtra = (props) => {
const [migrated, setMigrated] = React.useState(false);
const [query, setQuery] = React.useState(props.query);
React.useEffect(() => {
if (props.query && isMigrationHandler(props.datasource)) {
migrateQuery(props.datasource, props.query).then((migrated2) => {
props.onChange(migrated2);
setQuery(migrated2);
setMigrated(true);
});
} else {
setMigrated(true);
}
}, []);
React.useEffect(() => {
setQuery(props.query);
}, [props.query]);
if (!migrated) {
return /* @__PURE__ */ jsxRuntime.jsx(Skeleton__default.default, { containerTestId: "react-loading-skeleton-testid", height: 75 });
}
return /* @__PURE__ */ jsxRuntime.jsx(QueryEditor, { ...props, query });
};
return WithExtra;
}
const baseURL = `/apis/userstorage.grafana.app/v0alpha1/namespaces/${config.namespace}/user-storage`;
async function apiRequest(requestOptions) {
try {
const { data: responseData, ...meta } = await rxjs.lastValueFrom(
getBackendSrv().fetch({
...requestOptions,
url: baseURL + requestOptions.url,
data: requestOptions.body
})
);
return { data: responseData, meta };
} catch (error) {
return requestOptions.manageError ? requestOptions.manageError(error) : { error };
}
}
class UserStorage {
constructor(service) {
this.service = service;
this.userUID = config.bootData.user.uid === "" ? config.bootData.user.id.toString() : config.bootData.user.uid;
this.resourceName = `${service}:${this.userUID}`;
this.canUseUserStorage = config.featureToggles.userStorageAPI === true && config.bootData.user.isSignedIn;
}
async init() {
if (this.storageSpec !== undefined) {
return;
}
const userStorage = await apiRequest({
url: `/${this.resourceName}`,
method: "GET",
showErrorAlert: false
});
if ("error" in userStorage) {
if (lodash.get(userStorage, "error.status") !== 404) {
console.error("Failed to get user storage", userStorage.error);
}
this.storageSpec = null;
} else {
this.storageSpec = userStorage.data.spec;
}
}
async getItem(key) {
if (!this.canUseUserStorage) {
return localStorage.getItem(this.resourceName);
}
await this.init();
if (!this.storageSpec) {
return localStorage.getItem(this.resourceName);
}
return this.storageSpec.data[key];
}
async setItem(key, value) {
if (!this.canUseUserStorage) {
localStorage.setItem(key, value);
return;
}
const newData = { data: { [key]: value } };
await this.init();
if (!this.storageSpec) {
await apiRequest({
url: `/`,
method: "POST",
body: {
metadata: { name: this.resourceName, labels: { user: this.userUID, service: this.service } },
spec: newData
}
});
this.storageSpec = newData;
return;
}
this.storageSpec.data[key] = value;
await apiRequest({
headers: { "Content-Type": "application/merge-patch+json" },
url: `/${this.resourceName}`,
method: "PATCH",
body: { spec: newData }
});
}
}
function usePluginUserStorage() {
const context = data.usePluginContext();
if (!context) {
throw new Error(`No PluginContext found. The usePluginUserStorage() hook can only be used from a plugin.`);
}
return new UserStorage(context == null ? undefined : context.meta.id);
}
let FolderPickerComponent;
function setFolderPicker(component) {
FolderPickerComponent = component;
}
function FolderPicker(props) {
if (FolderPickerComponent) {
return /* @__PURE__ */ jsxRuntime.jsx(FolderPickerComponent, { ...props });
}
if (process.env.NODE_ENV !== "production") {
return /* @__PURE__ */ jsxRuntime.jsx("div", { children: "@grafana/runtime FolderPicker is not set" });
}
return null;
}
let singletonInstance;
function setCorrelationsService(instance) {
singletonInstance = instance;
}
function getCorrelationsService() {
return singletonInstance;
}
Object.defineProperty(exports, "StreamingFrameAction", {
enumerable: true,
get: function () { return data.StreamingFrameAction; }
});
exports.CopyPanelEvent = CopyPanelEvent;
exports.DataSourcePicker = DataSourcePicker;
exports.DataSourceWithBackend = DataSourceWithBackend;
exports.EchoEventType = EchoEventType;
exports.FakeEchoSrv = FakeEchoSrv;
exports.FolderPicker = FolderPicker;
exports.GrafanaBootConfig = GrafanaBootConfig;
exports.HealthCheckError = HealthCheckError;
exports.HealthStatus = HealthStatus;
exports.HistoryWrapper = HistoryWrapper;
exports.LocationServiceProvider = LocationServiceProvider;
exports.MetaAnalyticsEventName = MetaAnalyticsEventName;
exports.PanelDataErrorView = PanelDataErrorView;
exports.PanelRenderer = PanelRenderer;
exports.PluginPage = PluginPage;
exports.QueryEditorWithMigration = QueryEditorWithMigration;
exports.RefreshEvent = RefreshEvent;
exports.RuntimeDataSource = RuntimeDataSource;
exports.ScopesContext = ScopesContext;
exports.SidecarContext_EXPERIMENTAL = SidecarContext_EXPERIMENTAL;
exports.SidecarService_EXPERIMENTAL = SidecarService_EXPERIMENTAL;
exports.ThemeChangedEvent = ThemeChangedEvent;
exports.TimeRangeUpdatedEvent = TimeRangeUpdatedEvent;
exports.config = config;
exports.createDataSourcePluginEventProperties = createDataSourcePluginEventProperties;
exports.createMonitoringLogger = createMonitoringLogger;
exports.createPluginEventProperties = createPluginEventProperties;
exports.createQueryRunner = createQueryRunner;
exports.featureEnabled = featureEnabled;
exports.frameToMetricFindValue = frameToMetricFindValue;
exports.getAngularLoader = getAngularLoader;
exports.getAppEvents = getAppEvents;
exports.getBackendSrv = getBackendSrv;
exports.getCorrelationsService = getCorrelationsService;
exports.getDataSourceSrv = getDataSourceSrv;
exports.getEchoSrv = getEchoSrv;
exports.getGrafanaLiveSrv = getGrafanaLiveSrv;
exports.getLegacyAngularInjector = getLegacyAngularInjector;
exports.getLocationSrv = getLocationSrv;
exports.getPluginComponentExtensions = getPluginComponentExtensions;
exports.getPluginExtensions = getPluginExtensions;
exports.getPluginImportUtils = getPluginImportUtils;
exports.getPluginLinkExtensions = getPluginLinkExtensions;
exports.getRunRequest = getRunRequest;
exports.getTemplateSrv = getTemplateSrv;
exports.hasAllPermissions = hasAllPermissions;
exports.hasAnyPermission = hasAnyPermission;
exports.hasPermission = hasPermission;
exports.hasPermissionInMetadata = hasPermissionInMetadata;
exports.isExperimentViewEvent = isExperimentViewEvent;
exports.isExpressionReference = isExpressionReference;
exports.isFetchError = isFetchError;
exports.isInteractionEvent = isInteractionEvent;
exports.isMigrationHandler = isMigrationHandler;
exports.isPageviewEvent = isPageviewEvent;
exports.isPluginExtensionComponent = isPluginExtensionComponent;
exports.isPluginExtensionLink = isPluginExtensionLink;
exports.loadPluginCss = loadPluginCss;
exports.locationSearchToObject = locationSearchToObject;
exports.logDebug = logDebug;
exports.logError = logError;
exports.logInfo = logInfo;
exports.logMeasurement = logMeasurement;
exports.logWarning = logWarning;
exports.migrateQuery = migrateQuery;
exports.migrateRequest = migrateRequest;
exports.navigationLogger = navigationLogger;
exports.registerEchoBackend = registerEchoBackend;
exports.reportExperimentView = reportExperimentView;
exports.reportInteraction = reportInteraction;
exports.reportMetaAnalytics = reportMetaAnalytics;
exports.reportPageview = reportPageview;
exports.setAngularLoader = setAngularLoader;
exports.setAppEvents = setAppEvents;
exports.setBackendSrv = setBackendSrv;
exports.setChromeHeaderHeightHook = setChromeHeaderHeightHook;
exports.setCorrelationsService = setCorrelationsService;
exports.setCurrentUser = setCurrentUser;
exports.setDataSourceSrv = setDataSourceSrv;
exports.setEchoSrv = setEchoSrv;
exports.setEmbeddedDashboard = setEmbeddedDashboard;
exports.setFolderPicker = setFolderPicker;
exports.setGrafanaLiveSrv = setGrafanaLiveSrv;
exports.setLegacyAngularInjector = setLegacyAngularInjector;
exports.setLocationService = setLocationService;
exports.setLocationSrv = setLocationSrv;
exports.setPluginComponentHook = setPluginComponentHook;
exports.setPluginComponentsHook = setPluginComponentsHook;
exports.setPluginExtensionGetter = setPluginExtensionGetter;
exports.setPluginExtensionsHook = setPluginExtensionsHook;
exports.setPluginFunctionsHook = setPluginFunctionsHook;
exports.setPluginImportUtils = setPluginImportUtils;
exports.setPluginLinksHook = setPluginLinksHook;
exports.setQueryRunnerFactory = setQueryRunnerFactory;
exports.setReturnToPreviousHook = setReturnToPreviousHook;
exports.setRunRequest = setRunRequest;
exports.setTemplateSrv = setTemplateSrv;
exports.sidecarServiceSingleton_EXPERIMENTAL = sidecarServiceSingleton_EXPERIMENTAL;
exports.toDataQueryError = toDataQueryError;
exports.toDataQueryResponse = toDataQueryResponse;
exports.useChromeHeaderHeight = useChromeHeaderHeight;
exports.useLocationService = useLocationService;
exports.usePluginComponent = usePluginComponent;
exports.usePluginComponentExtensions = usePluginComponentExtensions;
exports.usePluginComponents = usePluginComponents;
exports.usePluginExtensions = usePluginExtensions;
exports.usePluginFunctions = usePluginFunctions;
exports.usePluginInteractionReporter = usePluginInteractionReporter;
exports.usePluginLinkExtensions = usePluginLinkExtensions;
exports.usePluginLinks = usePluginLinks;
exports.usePluginUserStorage = usePluginUserStorage;
exports.useReturnToPrevious = useReturnToPrevious;
exports.useScopes = useScopes;
exports.useSidecar_EXPERIMENTAL = useSidecar_EXPERIMENTAL;
//# sourceMappingURL=index.cjs.map