UNPKG

@grafana/runtime

Version:
2,170 lines • 71.6 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 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