UNPKG

@grafana/runtime

Version:
1,587 lines (1,547 loc) • 61.3 kB
'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 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 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.externalUserMngLinkUrl = ""; this.externalUserMngLinkName = ""; this.externalUserMngInfo = ""; this.externalUserMngAnalytics = false; this.externalUserMngAnalyticsParams = ""; this.allowOrgCreate = false; this.feedbackLinksEnabled = true; this.disableLoginForm = false; this.defaultDatasource = ""; // UID 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 = void 0; this.viewersCanEdit = false; this.disableSanitizeHtml = false; this.trustedTypesDefaultPolicyEnabled = false; this.cspReportOnlyEnabled = false; this.liveEnabled = true; this.liveMessageSizeLimit = 65536; this.featureToggles = {}; this.anonymousEnabled = false; this.anonymousDeviceLimit = void 0; this.licenseInfo = {}; this.rendererAvailable = false; this.rendererVersion = ""; this.rendererDefaultImageWidth = 1e3; this.rendererDefaultImageHeight = 500; this.rendererDefaultImageScale = 1; 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: void 0, alertStateHistoryPrimary: void 0, recordingRulesEnabled: false, defaultRecordingRulesTargetDatasourceUID: void 0 }; 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.panelSeriesLimit = 0; this.sqlConnectionLimits = { maxOpenConns: 100, maxIdleConns: 100, connMaxLifetime: 14400 }; this.defaultDatasourceManageAlertsUiToggle = true; this.defaultAllowRecordingRulesTargetAlertsUiToggle = true; this.enableFrontendSandboxForPlugins = []; this.cloudMigrationPollIntervalMs = 2e3; this.exploreDefaultTimeOffset = "1h"; this.bootData = options2.bootData; const defaults = { datasources: {}, windowTitlePrefix: "Grafana - ", panels: {}, playlist_timespan: "1m", unsaved_changes_warning: true, appUrl: "", appSubUrl: "", buildInfo: { version: "1.0", commit: "1", env: "production" }, viewersCanEdit: 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); this.theme2 = data.getThemeById(this.bootData.user.theme); this.bootData.user.lightTheme = this.theme2.isLight; this.theme = this.theme2.v1; this.regionalFormat = options2.bootData.user.regionalFormat; } } 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.`); } } } }); } let bootData = window.grafanaBootData; if (!bootData) { if (process.env.NODE_ENV !== "test") { console.error("window.grafanaBootData was not set by the time config was initialized"); } bootData = { 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] === void 0) { 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 ? void 0 : _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(void 0); 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; } 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); } function getObservablePluginLinks(options) { { throw new Error("getObservablePluginLinks() can only be used after the Grafana instance has started."); } } function getObservablePluginComponents(options) { { throw new Error("getObservablePluginComponents() can only be used after the Grafana instance has started."); } } 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; } function getLimitedComponentsToRender({ props, components, limit, pluginId }) { if (!components.length) { return null; } const renderedComponents = []; for (const Component of components) { const { meta } = Component; if (pluginId && typeof pluginId === "string" && pluginId !== meta.pluginId) { continue; } if (pluginId && Array.isArray(pluginId) && !pluginId.includes(meta.pluginId)) { continue; } if (pluginId instanceof RegExp && !pluginId.test(meta.pluginId)) { continue; } if (limit === void 0) { renderedComponents.push(Component); continue; } if (React__default.default.createElement(Component, props) !== null) { renderedComponents.push(Component); } if (renderedComponents.length >= limit) { break; } } return renderedComponents; } function renderLimitedComponents({ props, components, limit, pluginId }) { const limitedComponents = getLimitedComponentsToRender({ props, components, limit, pluginId }); if (!(limitedComponents == null ? void 0 : limitedComponents.length)) { return null; } return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: limitedComponents.map((Component) => /* @__PURE__ */ jsxRuntime.jsx(Component, { ...props }, Component.meta.id)) }); } 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(void 0); function useScopes() { var _a; const context = React.useContext(ScopesContext); reactUse.useObservable((_a = context == null ? void 0 : context.stateObservable) != null ? _a : new rxjs.Observable(), context == null ? void 0 : context.state); return React.useMemo(() => { return context ? { state: context.state, stateObservable: context.stateObservable, changeScopes: context.changeScopes, setReadOnly: context.setReadOnly, setEnabled: context.setEnabled } : void 0; }, [context, context == null ? void 0 : context.state]); } 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 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 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 ? void 0 : _a.message) !== "Query data error") { message = error.data.message; } else if (((_b = error == null ? void 0 : error.data) == null ? void 0 : _b.message) === "Query data error" && ((_c = error == null ? void 0 : error.data) == null ? void 0 : _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 : void 0; if (traceId != null) { rsp.traceIds = [traceId]; } const fetchResponse = res; if ((_a = fetchResponse.data) == null ? void 0 : _a.results) { const results = fetchResponse.data.results; const refIDs = (queries == null ? void 0 : 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 ? void 0 : _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 ? void 0 : _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 ? void 0 : _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 ? void 0 : 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 ? void 0 : _a.fields) != null ? _b : []], meta: { ...(_c = frame.schema) == null ? void 0 : _c.meta, notices: [...(_f = (_e = (_d = frame.schema) == null ? void 0 : _d.meta) == null ? void 0 : _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 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, showErrorAlert: false }) ); 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.bootData.user.isSignedIn; } async init() { if (this.storageSpec !== void 0) { return; } const userStorage = await apiRequest({ url: `/${this.resourceName}`, method: "GET", manageError: (error) => { if (lodash.get(error, "status") === 404) { this.storageSpec = null; return { error: null }; } return { error }; } }); if ("error" in userStorage) { return userStorage.error; } this.storageSpec = userStorage.data.spec; return; } async getItem(key) { if (!this.canUseUserStorage) { return localStorage.getItem(`${this.resourceName}:${key}`); } await this.init(); if (!this.storageSpec) { return localStorage.getItem(`${this.resourceName}:${key}`); } return this.storageSpec.data[key]; } async setItem(key, value) { if (!this.canUseUserStorage) { localStorage.setItem(`${this.resourceName}:${key}`, value); return; } const newData = { data: { [key]: value } }; const error = await this.init(); if (error) { localStorage.setItem(`${this.resourceName}:${key}`, value); return; } if (!this.storageSpec) { await apiRequest({ url: `/`, method: "POST", body: { metadata: { name: this.resourceName, labels: { user: this.userUID, service: this.service } }, spec: newData }, manageError: (error2) => { localStorage.setItem(`${this.resourceName}:${key}`, value); return { error: error2 }; } }); 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 }, manageError: (error2) => { localStorage.setItem(`${this.resourceName}:${key}`, value); return { error: error2 }; } }); } } 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 ? void 0 : context.meta.id); } 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; this.userStorage = new UserStorage(instanceSettings.type); } /** * 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 ? void 0 : _b.length) { pluginIDs.add(datasource.type); } if ((_c = datasource.uid) == null ? void 0 : _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 ? void 0 : range.from.valueOf().toString(), to: range == null ? void 0 : range.to.valueOf().toString() }; 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.queryServiceFromExplore && request.app === data.CoreApp.Explore) { const isQueryServiceEnabled = config.featureToggles.queryService; const isExperimentalAPIsEnabled = config.featureToggles.grafanaAPIServerWithExperimentalAPIs; if (!isQueryServiceEnabled && !isExperimentalAPIsEnabled) { console.warn("feature toggle queryServiceFromExplore also requires the queryService to be running"); } else { url = `/apis/query.grafana.app/v0alpha1/namespaces/${config.namespace}/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 { 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.dashboardTitle) { headers["X-Dashboard-Title" /* DashboardTitle */] = request.dashboardTitle; } if (request.panelId) { headers["X-Panel-Id" /* PanelID */] = `${request.panelId}`; } if (request.panelName) { headers["X-Panel-Title" /* PanelTitle */] = request.panelName; } } 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 ? void 0 : _a2.length) && rsp.data.find((f) => { var _a3; return (_a3 = f.meta) == null ? void 0 : _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 ? void 0 : options.headers) ? { ...options.headers, ...headers } : headers, params: params != null ? params : options == null ? void 0 : 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 ? void 0 : 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 ? void 0 : _a.id) || "", plugin_version: ((_c = (_b = this.meta) == null ? void 0 : _b.info) == null ? void 0 : _c.version) || "", datasource_healthcheck_status: ((_d = err == null ? void 0 : err.data) == null ? void 0 : _d.status) || "error", datasource_healthcheck_message: ((_e = err == null ? void 0 : err.data) == null ? void 0 : _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 ? void 0 : _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 ? void 0 : _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: void 0 }); } }; } 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 : void 0, 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: [