import "./register.css";
import { reactive, shallowRef, defineComponent, computed, openBlock, createBlock, unref, withCtx, renderSlot, createElementBlock, normalizeStyle, normalizeClass, createCommentVNode, useAttrs, mergeProps, ref, onMounted, watch, onBeforeUnmount, withDirectives, createElementVNode, vShow, createTextVNode, toDisplayString, Fragment, renderList, createVNode, withModifiers, vModelText, vModelCheckbox, vModelRadio, vModelSelect, nextTick, createStaticVNode, onUnmounted, withKeys, Teleport } from "vue";
import { Button, Select, Form, Input, Switch, Tooltip, InputNumber } from "ant-design-vue";
import Map$1 from "ol/Map";
import View from "ol/View";
import Tile from "ol/layer/Tile";
import Vector from "ol/layer/Vector";
import Heatmap from "ol/layer/Heatmap";
import OSM from "ol/source/OSM";
import XYZ from "ol/source/XYZ";
import Vector$1 from "ol/source/Vector";
import Feature from "ol/Feature";
import Point from "ol/geom/Point";
import LineString from "ol/geom/LineString";
import Polygon from "ol/geom/Polygon";
import { fromLonLat, toLonLat } from "ol/proj";
import { getArea, getLength } from "ol/sphere";
import { Circle, Fill, Stroke, Style, Text } from "ol/style";
import { defaults } from "ol/control";
import Zoom from "ol/control/Zoom";
import ScaleLine from "ol/control/ScaleLine";
import Attribution from "ol/control/Attribution";
import Draw from "ol/interaction/Draw";
import GeoJSON from "ol/format/GeoJSON";
import "ol/ol.css";
import { parser } from "@prometheus-io/lezer-promql";
import axios from "axios";
const panels = /* @__PURE__ */ new Map();
const datasources = /* @__PURE__ */ new Map();
function registerPanelPlugin(plugin2, opts = {}) {
  if (panels.has(plugin2.meta.id) && !opts.overwrite) {
    panels.set(plugin2.meta.id, plugin2);
    return;
  }
  panels.set(plugin2.meta.id, plugin2);
}
function registerDataSourcePlugin(plugin2, opts = {}) {
  if (datasources.has(plugin2.meta.id) && !opts.overwrite) {
    datasources.set(plugin2.meta.id, plugin2);
    return;
  }
  datasources.set(plugin2.meta.id, plugin2);
}
function getDataSourcePlugin(id) {
  return datasources.get(id);
}
function createEmptyEditorContext(partial = {}) {
  return {
    data: partial.data ?? [],
    annotations: partial.annotations ?? [],
    replaceVariables: partial.replaceVariables,
    eventBus: partial.eventBus,
    getSuggestions: partial.getSuggestions,
    options: partial.options,
    instanceState: partial.instanceState,
    isOverride: partial.isOverride ?? false
  };
}
function assignPathDefault$1(target, path, value) {
  const parts = path.split(".");
  let cur = target;
  for (let i = 0; i < parts.length - 1; i++) {
    const key = parts[i];
    const next = cur[key];
    if (!next || typeof next !== "object") {
      cur[key] = {};
    }
    cur = cur[key];
  }
  cur[parts[parts.length - 1]] = value;
}
class OptionsUIBuilder {
  descriptors = [];
  defaults = {};
  orderSeq = 0;
  getItems() {
    return this.descriptors;
  }
  add(d, defaultValue) {
    const order = d.order ?? this.orderSeq++;
    const editorKey = d.editorKey ?? d.editor;
    const desc = {
      ...d,
      category: d.category ?? [],
      editorKey,
      order,
      defaultValue: defaultValue !== void 0 ? defaultValue : d.defaultValue,
      id: d.id || d.path
    };
    this.descriptors.push(desc);
    const dv = defaultValue !== void 0 ? defaultValue : d.defaultValue;
    if (dv !== void 0) {
      assignPathDefault$1(this.defaults, d.path, dv);
    }
    return this;
  }
  addBoolean(d, defaultValue) {
    return this.add({ ...d, editor: "boolean" }, defaultValue);
  }
  addRadio(d, defaultValue) {
    return this.add({ ...d, editor: "radio" }, defaultValue);
  }
  addSelect(d, defaultValue) {
    return this.add({ ...d, editor: "select" }, defaultValue);
  }
  addMultiSelect(d, defaultValue) {
    return this.add({ ...d, editor: "multi-select" }, defaultValue);
  }
  addNumber(d, defaultValue) {
    return this.add({ ...d, editor: "number" }, defaultValue);
  }
  addSlider(d, defaultValue) {
    return this.add({ ...d, editor: "slider" }, defaultValue);
  }
  addText(d, defaultValue) {
    return this.add({ ...d, editor: "text" }, defaultValue);
  }
  addTextArea(d, defaultValue) {
    return this.add({ ...d, editor: "textarea" }, defaultValue);
  }
  addStrings(d, defaultValue) {
    return this.add({ ...d, editor: "strings" }, defaultValue);
  }
  addColor(d, defaultValue) {
    return this.add({ ...d, editor: "color" }, defaultValue);
  }
  addUnit(d, defaultValue) {
    return this.add({ ...d, editor: "unit" }, defaultValue);
  }
  addFieldColor(d, defaultValue) {
    return this.add({ ...d, editor: "fieldColor" }, defaultValue);
  }
  addThresholds(d, defaultValue) {
    return this.add({ ...d, editor: "thresholds" }, defaultValue);
  }
  addMappings(d, defaultValue) {
    return this.add({ ...d, editor: "mappings" }, defaultValue);
  }
  addLinks(d, defaultValue) {
    return this.add({ ...d, editor: "links" }, defaultValue);
  }
  addActions(d, defaultValue) {
    return this.add({ ...d, editor: "actions" }, defaultValue);
  }
  addStatsPicker(d, defaultValue) {
    return this.add({ ...d, editor: "stats-picker" }, defaultValue);
  }
  addTimezone(d, defaultValue) {
    return this.add({ ...d, editor: "timezone" }, defaultValue);
  }
  addFieldName(d, defaultValue) {
    return this.add({ ...d, editor: "field-name" }, defaultValue);
  }
  addDashboardUid(d, defaultValue) {
    return this.add({ ...d, editor: "dashboard-uid" }, defaultValue);
  }
  addCustomEditor(d, defaultValue) {
    return this.add(
      {
        ...d,
        editor: d.editor ?? "custom",
        editorKey: d.editorKey ?? "custom",
        customEditor: d.customEditor
      },
      defaultValue
    );
  }
  /**
   * Back-compat: full descriptor with explicit editor (used by commonBuilders / panels).
   */
  addCustom(d, defaultValue) {
    const editor = d.editor ?? "custom";
    return this.add(
      {
        ...d,
        editor,
        editorKey: d.editorKey ?? editor
      },
      defaultValue !== void 0 ? defaultValue : d.defaultValue
    );
  }
  /**
   * Nested option group — stores nested descriptor; children resolved by consumer via nested.build.
   */
  addNestedOptions(cfg) {
    return this.add(
      {
        id: `nested.${cfg.path}`,
        path: cfg.path,
        name: cfg.category?.[0] ?? cfg.path,
        category: cfg.category ?? [],
        editor: "nested",
        editorKey: "nested",
        nested: cfg,
        defaultValue: cfg.defaultValue
      },
      cfg.defaultValue
    );
  }
  /** Filter visible descriptors for a live context */
  static filterVisible(items, options, context) {
    return items.filter((d) => {
      if (d.hideFromDefaults && !context.isOverride) return false;
      if (d.hideFromOverrides && context.isOverride) return false;
      if (d.showIf) {
        const show = d.showIf(options, context.data, context.annotations);
        if (show === false) return false;
      }
      return true;
    });
  }
  static isDisabled(d, options, context) {
    if (!d.disableIf) return false;
    return !!d.disableIf(options, context.data, context.annotations);
  }
}
const STANDARD_ITEMS = [
  {
    id: "unit",
    path: "unit",
    name: "单位",
    category: ["Standard options"],
    editor: "unit",
    editorKey: "unit",
    override: true
  },
  {
    id: "min",
    path: "min",
    name: "最小值",
    category: ["Standard options"],
    editor: "number",
    editorKey: "number",
    override: true
  },
  {
    id: "max",
    path: "max",
    name: "最大值",
    category: ["Standard options"],
    editor: "number",
    editorKey: "number",
    override: true
  },
  {
    id: "fieldMinMax",
    path: "fieldMinMax",
    name: "字段最小/最大",
    description: "根据数据计算最小/最大值",
    category: ["Standard options"],
    editor: "boolean",
    editorKey: "boolean",
    override: true
  },
  {
    id: "decimals",
    path: "decimals",
    name: "小数位",
    category: ["Standard options"],
    editor: "number",
    editorKey: "number",
    override: true
  },
  {
    id: "displayName",
    path: "displayName",
    name: "显示名称",
    category: ["Standard options"],
    editor: "text",
    editorKey: "text",
    override: true
  },
  {
    id: "noValue",
    path: "noValue",
    name: "空值显示",
    category: ["Standard options"],
    editor: "text",
    editorKey: "text",
    override: true
  },
  {
    id: "color",
    path: "color",
    name: "颜色方案",
    category: ["Standard options"],
    editor: "fieldColor",
    editorKey: "fieldColor",
    override: true
  },
  {
    id: "thresholds",
    path: "thresholds",
    name: "阈值",
    category: ["Thresholds"],
    editor: "thresholds",
    editorKey: "thresholds",
    override: true
  },
  {
    id: "mappings",
    path: "mappings",
    name: "值映射",
    category: ["Value mappings"],
    editor: "mappings",
    editorKey: "mappings",
    override: true
  },
  {
    id: "links",
    path: "links",
    name: "数据链接",
    category: ["Data links and actions"],
    editor: "links",
    editorKey: "links",
    override: true
  },
  {
    id: "actions",
    path: "actions",
    name: "动作",
    category: ["Data links and actions"],
    editor: "actions",
    editorKey: "actions",
    override: true
  },
  {
    id: "filterable",
    path: "filterable",
    name: "可过滤",
    category: ["Standard options"],
    editor: "boolean",
    editorKey: "boolean",
    override: true,
    hideFromDefaults: true
  }
];
function buildStandardFieldConfigDescriptors(opts = {}) {
  const disabled = new Set(opts.disableStandardOptions ?? []);
  const patches = opts.standardOptions ?? {};
  return STANDARD_ITEMS.filter((item) => !disabled.has(item.id)).map((item) => {
    const patch = patches[item.id] ?? {};
    return {
      id: item.id,
      path: item.path,
      name: patch.name ?? item.name,
      description: patch.description ?? item.description,
      category: patch.category ?? item.category,
      editor: item.editor,
      editorKey: item.editorKey,
      override: item.override ?? true,
      hideFromDefaults: item.hideFromDefaults,
      hideFromOverrides: item.hideFromOverrides,
      defaultValue: patch.defaultValue ?? item.defaultValue,
      settings: patch.settings
    };
  });
}
function createPanelPlugin(meta2, panel2, extras = {}) {
  const plugin2 = { meta: meta2, panel: panel2, ...extras };
  registerPanelPlugin(plugin2);
  return plugin2;
}
function createDataSourcePlugin(module) {
  registerDataSourcePlugin(module);
  return module;
}
const STANDARD_FIELD_CONFIG = buildStandardFieldConfigDescriptors();
function applyStandardFieldConfig(opts) {
  const fieldBuilder = new FieldConfigBuilder();
  opts.useCustomConfig?.(fieldBuilder);
  const disabled = new Set(opts.disableStandardOptions ?? []);
  let standard = [];
  if (opts.standard !== false) {
    for (const base of STANDARD_FIELD_CONFIG) {
      if (disabled.has(base.id)) continue;
      let item = { ...base };
      const patch = opts.standardOptions?.[base.id];
      if (patch) {
        if (patch.defaultValue !== void 0)
          item = { ...item, defaultValue: patch.defaultValue };
        if (patch.settings)
          item = {
            ...item,
            settings: { ...item.settings ?? {}, ...patch.settings }
          };
        if (patch.hideFromDefaults !== void 0)
          item = { ...item, hideFromDefaults: patch.hideFromDefaults };
      }
      standard.push(item);
    }
  }
  const custom = fieldBuilder.descriptors.map((d) => ({
    ...d,
    isCustom: true,
    path: d.path.startsWith("custom.") ? d.path : `custom.${d.path}`,
    id: d.id.startsWith("custom.") ? d.id : `custom.${d.id}`
  }));
  return {
    descriptors: [...standard, ...custom],
    customDefaults: fieldBuilder.customDefaults
  };
}
function assignPathDefault(target, path, value) {
  const parts = path.split(".");
  let cur = target;
  for (let i = 0; i < parts.length - 1; i++) {
    cur[parts[i]] = cur[parts[i]] ?? {};
    cur = cur[parts[i]];
  }
  cur[parts[parts.length - 1]] = value;
}
class FieldConfigBuilder {
  descriptors = [];
  customDefaults = {};
  addCustom(d) {
    this.descriptors.push({
      ...d,
      isCustom: true,
      override: d.override !== false
    });
    if (d.defaultValue !== void 0) {
      const p = d.path.startsWith("custom.") ? d.path.slice("custom.".length) : d.path;
      assignPathDefault(this.customDefaults, p, d.defaultValue);
    }
    return this;
  }
  addBoolean(d, defaultValue) {
    return this.addCustom({ ...d, editor: "boolean", defaultValue });
  }
  addRadio(d, defaultValue) {
    return this.addCustom({ ...d, editor: "radio", defaultValue });
  }
  addSelect(d, defaultValue) {
    return this.addCustom({ ...d, editor: "select", defaultValue });
  }
  addNumber(d, defaultValue) {
    return this.addCustom({ ...d, editor: "number", defaultValue });
  }
  addSlider(d, defaultValue) {
    return this.addCustom({ ...d, editor: "slider", defaultValue });
  }
  addText(d, defaultValue) {
    return this.addCustom({ ...d, editor: "text", defaultValue });
  }
}
class VuePanelPlugin {
  module;
  optionsSupplier;
  constructor(meta2, panel2) {
    this.module = {
      meta: meta2,
      panel: panel2,
      optionDescriptors: [],
      fieldConfigDescriptors: [],
      standardFieldConfig: true,
      noPadding: false
    };
  }
  setPanel(panel2) {
    this.module.panel = panel2;
    return this;
  }
  setNoPadding() {
    this.module.noPadding = true;
    return this;
  }
  setDataSupport(_support) {
    this.module.dataSupport = _support;
    return this;
  }
  useFieldConfig(opts = {}) {
    this.module.standardFieldConfig = opts.standard !== false;
    const applied = applyStandardFieldConfig(opts);
    this.module.fieldConfigDescriptors = applied.descriptors;
    this.module.defaultFieldConfigCustom = applied.customDefaults;
    return this;
  }
  /**
   * Grafana-compatible setPanelOptions(builder, context).
   * Supplier is stored; defaults/descriptors resolved once with empty context at register.
   */
  setPanelOptions(builderFn) {
    this.optionsSupplier = (builder2, context) => {
      builderFn(builder2, context);
    };
    const builder = new OptionsUIBuilder();
    this.optionsSupplier(builder, createEmptyEditorContext());
    this.module.optionDescriptors = builder.descriptors;
    this.module.defaultOptions = builder.defaults;
    this.module.optionsSupplier = this.optionsSupplier;
    return this;
  }
  /** Re-resolve descriptors with live StandardEditorContext (showIf/disableIf with data). */
  resolveOptionDescriptors(context = createEmptyEditorContext()) {
    if (!this.optionsSupplier) {
      return this.module.optionDescriptors ?? [];
    }
    const builder = new OptionsUIBuilder();
    this.optionsSupplier(builder, context);
    return builder.descriptors;
  }
  setMigrationHandler(fn) {
    this.module.migrateOptions = fn;
    return this;
  }
  setPanelMigrationHandler(fn) {
    this.module.migratePanel = fn;
    return this;
  }
  setPanelChangeHandler(fn) {
    this.module.panelChangeHandler = fn;
    return this;
  }
  setRuntimeConsumedPaths(paths) {
    this.module.runtimeConsumedPaths = paths;
    return this;
  }
  setOptionsEditor(editor) {
    this.module.optionsEditor = editor;
    return this;
  }
  setFieldConfigEditor(editor) {
    this.module.fieldConfigEditor = editor;
    return this;
  }
  register() {
    return createPanelPlugin(this.module.meta, this.module.panel, {
      defaultOptions: this.module.defaultOptions,
      optionsEditor: this.module.optionsEditor,
      fieldConfigEditor: this.module.fieldConfigEditor,
      migrateOptions: this.module.migrateOptions,
      migratePanel: this.module.migratePanel,
      panelChangeHandler: this.module.panelChangeHandler,
      optionDescriptors: this.module.optionDescriptors,
      fieldConfigDescriptors: this.module.fieldConfigDescriptors,
      standardFieldConfig: this.module.standardFieldConfig,
      runtimeConsumedPaths: this.module.runtimeConsumedPaths,
      defaultFieldConfigCustom: this.module.defaultFieldConfigCustom,
      dataSupport: this.module.dataSupport,
      noPadding: this.module.noPadding,
      optionsSupplier: this.module.optionsSupplier
    });
  }
  getModule() {
    return this.module;
  }
}
const runtimeDataSources = /* @__PURE__ */ new Map();
function getRuntimeDataSource(uid) {
  return runtimeDataSources.get(String(uid || "").trim());
}
function listRuntimeDataSources() {
  return [...runtimeDataSources.values()];
}
const index$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
  __proto__: null,
  FieldConfigBuilder,
  OptionsBuilder: OptionsUIBuilder,
  OptionsUIBuilder,
  STANDARD_FIELD_CONFIG,
  VuePanelPlugin,
  buildStandardFieldConfigDescriptors,
  createDataSourcePlugin,
  createEmptyEditorContext,
  createPanelPlugin,
  getDataSourcePlugin,
  getRuntimeDataSource,
  listRuntimeDataSources,
  registerDataSourcePlugin,
  registerPanelPlugin
}, Symbol.toStringTag, { value: "Module" }));
const _export_sfc = (sfc, props) => {
  const target = sfc.__vccOpts || sfc;
  for (const [key, val] of props) {
    target[key] = val;
  }
  return target;
};
const state$1 = reactive({ boot: null });
function setBootData(boot) {
  state$1.boot = boot;
}
function createDefaultBootData(partial) {
  return {
    user: {
      id: 1,
      isSignedIn: true,
      login: "admin",
      email: "admin@localhost",
      name: "Admin",
      orgId: 1,
      orgName: "Main Org.",
      orgRole: "Admin",
      isGrafanaAdmin: true,
      timezone: "browser",
      weekStart: "monday",
      language: "en-US",
      theme: "dark",
      permissions: {
        "dashboards:read": true,
        "dashboards:write": true,
        "datasources:read": true,
        "datasources:write": true,
        "datasources:create": true,
        "datasources:delete": true
      },
      ...{}
    },
    settings: {
      appSubUrl: "",
      buildInfo: { version: "13.2.0-pre-vue", commit: "local", env: "dev" },
      featureToggles: {},
      datasources: {},
      panels: {},
      minRefreshInterval: "5s",
      ...{}
    },
    navTree: []
  };
}
function ok(data, status = 200) {
  return {
    data,
    status,
    statusText: status === 200 ? "OK" : String(status),
    ok: status >= 200 && status < 300,
    headers: new Headers({ "content-type": "application/json" })
  };
}
function notFound(message) {
  const err = new Error(message);
  err.status = 404;
  err.data = { message };
  throw err;
}
const DASH_STORAGE_KEY = "grafana-vue-imported-dashboards";
const DS_STORAGE_KEY = "grafana-vue-offline-datasources";
function readJson(key, fallback) {
  if (typeof localStorage === "undefined") return fallback;
  try {
    const raw = localStorage.getItem(key);
    if (!raw) return fallback;
    return JSON.parse(raw);
  } catch {
    return fallback;
  }
}
function writeJson(key, value) {
  if (typeof localStorage === "undefined") return;
  localStorage.setItem(key, JSON.stringify(value));
}
function readDashMap() {
  return readJson(DASH_STORAGE_KEY, {});
}
function writeDashMap(map) {
  writeJson(DASH_STORAGE_KEY, map);
}
let builders = {};
function registerLiveDashboardBuilders(next) {
  builders = { ...next };
}
function getLiveDashboardBuilders() {
  return builders;
}
function loadPluginDashboard(_pluginId, _file, uid, title) {
  try {
    const embedded = {
      "zabbix-overview": {
        uid: "zabbix-overview",
        title: "Zabbix 概览",
        schemaVersion: 39,
        panels: [
          {
            id: 1,
            type: "timeseries",
            title: "CPU",
            gridPos: { x: 0, y: 0, w: 12, h: 8 },
            targets: [
              {
                refId: "A",
                queryType: "0",
                item: { filter: "system.cpu.util" }
              }
            ],
            datasource: {
              type: "alexanderzobnin-zabbix-datasource",
              uid: "zabbix"
            }
          },
          {
            id: 2,
            type: "alexanderzobnin-zabbix-triggers-panel",
            title: "问题",
            gridPos: { x: 12, y: 0, w: 12, h: 8 },
            schemaVersion: 8,
            targets: [{ refId: "A", queryType: 5 }],
            datasource: {
              type: "alexanderzobnin-zabbix-datasource",
              uid: "zabbix"
            }
          }
        ]
      },
      "zabbix-problems": {
        uid: "zabbix-problems",
        title: "Zabbix 问题",
        schemaVersion: 39,
        panels: [
          {
            id: 1,
            type: "alexanderzobnin-zabbix-triggers-panel",
            title: "当前问题",
            gridPos: { x: 0, y: 0, w: 24, h: 16 },
            schemaVersion: 8,
            targets: [{ refId: "A", queryType: 5 }],
            datasource: {
              type: "alexanderzobnin-zabbix-datasource",
              uid: "zabbix"
            }
          }
        ]
      },
      "zabbix-host": {
        uid: "zabbix-host",
        title: "Zabbix 主机",
        schemaVersion: 39,
        panels: [
          {
            id: 1,
            type: "timeseries",
            title: "主机指标",
            gridPos: { x: 0, y: 0, w: 24, h: 10 },
            targets: [{ refId: "A", queryType: "0" }],
            datasource: {
              type: "alexanderzobnin-zabbix-datasource",
              uid: "zabbix"
            }
          }
        ]
      },
      "signoz-metrics": {
        uid: "signoz-metrics",
        title: "SigNoz metrics",
        schemaVersion: 39,
        panels: [
          {
            id: 1,
            type: "timeseries",
            title: "metrics",
            gridPos: { x: 0, y: 0, w: 24, h: 12 },
            targets: [{ refId: "A", signal: "metrics" }],
            datasource: { type: "signoz", uid: "signoz" }
          }
        ]
      },
      "signoz-services": {
        uid: "signoz-services",
        title: "SigNoz services",
        schemaVersion: 39,
        panels: [
          {
            id: 1,
            type: "timeseries",
            title: "services",
            gridPos: { x: 0, y: 0, w: 24, h: 12 },
            targets: [{ refId: "A", signal: "metrics" }],
            datasource: { type: "signoz", uid: "signoz" }
          }
        ]
      },
      "signoz-logs": {
        uid: "signoz-logs",
        title: "SigNoz logs",
        schemaVersion: 39,
        panels: [
          {
            id: 1,
            type: "logs",
            title: "logs",
            gridPos: { x: 0, y: 0, w: 24, h: 12 },
            targets: [{ refId: "A", signal: "logs" }],
            datasource: { type: "signoz", uid: "signoz" }
          }
        ]
      },
      "signoz-traces": {
        uid: "signoz-traces",
        title: "SigNoz traces",
        schemaVersion: 39,
        panels: [
          {
            id: 1,
            type: "traces",
            title: "traces",
            gridPos: { x: 0, y: 0, w: 24, h: 12 },
            targets: [{ refId: "A", signal: "traces" }],
            datasource: { type: "signoz", uid: "signoz" }
          }
        ]
      },
      "signoz-issues": {
        uid: "signoz-issues",
        title: "SigNoz issues",
        schemaVersion: 39,
        panels: [
          {
            id: 1,
            type: "signoz-issues",
            title: "issues",
            gridPos: { x: 0, y: 0, w: 24, h: 12 },
            targets: [{ refId: "A", signal: "alerts" }],
            datasource: { type: "signoz", uid: "signoz" }
          }
        ]
      }
    };
    const doc = embedded[uid] || { uid, title, schemaVersion: 39, panels: [] };
    return { ...doc, uid, title };
  } catch {
    return { uid, title, schemaVersion: 39, panels: [] };
  }
}
function seedDemoDashboards() {
  const map = readDashMap();
  let dirty = false;
  const demos = [
    { uid: "vue-demo", title: "可视化全景演示（全部 Panel）" },
    { uid: "demo", title: "演示看板" },
    { uid: "v1-demo", title: "V1 演示看板" },
    { uid: "ds-catalog", title: "数据源测试中心", factory: dsCatalogDashboard },
    {
      uid: "ds-zabbix-full",
      title: "Zabbix Full（测试）",
      factory: (u, ti) => dsTypedDashboard(u, ti, "alexanderzobnin-zabbix-datasource", "zabbix")
    },
    {
      uid: "ds-zabbix-viz",
      title: "Zabbix 可视化矩阵",
      factory: (u, ti) => dsVizMatrixDashboard(
        u,
        ti,
        "alexanderzobnin-zabbix-datasource",
        "zabbix"
      )
    },
    {
      uid: "ds-signoz-full",
      title: "SigNoz Full（测试）",
      factory: (u, ti) => dsTypedDashboard(u, ti, "signoz", "signoz")
    },
    {
      uid: "ds-signoz-viz",
      title: "SigNoz 可视化矩阵",
      factory: (u, ti) => dsVizMatrixDashboard(u, ti, "signoz", "signoz")
    },
    {
      uid: "ds-signoz-native-full",
      title: "SigNoz Native Full（测试）",
      factory: (u, ti) => dsTypedDashboard(u, ti, "signoz", "signoz-native")
    },
    {
      uid: "test-panel-view-edit-live-signoz-native",
      title: "View/Edit × SigNoz Native",
      factory: (u, ti) => testViewEditDashboard(u, ti, "signoz-native", "signoz")
    },
    {
      uid: "ds-otel-full",
      title: "OpenTelemetry Full（测试）",
      factory: (u, ti) => dsTypedDashboard(u, ti, "opentelemetry", "opentelemetry")
    },
    {
      uid: "ds-prometheus",
      title: "Prometheus 测试",
      factory: (u, ti) => dsTypedDashboard(u, ti, "prometheus", "prometheus")
    },
    {
      uid: "ds-loki",
      title: "Loki 测试",
      factory: (u, ti) => dsTypedDashboard(u, ti, "loki", "loki")
    },
    {
      uid: "ds-tempo",
      title: "Tempo 测试",
      factory: (u, ti) => dsTypedDashboard(u, ti, "tempo", "tempo")
    },
    {
      uid: "ds-jaeger",
      title: "Jaeger 测试",
      factory: (u, ti) => dsTypedDashboard(u, ti, "jaeger", "jaeger")
    },
    {
      uid: "ds-testdata",
      title: "TestData 全 scenario",
      factory: dsTestdataDashboard
    },
    { uid: "ds-mixed", title: "Mixed 多数据源测试", factory: dsMixedDashboard },
    {
      uid: "test-panel-view-edit",
      title: "面板 View/Edit 联调",
      factory: testViewEditDashboard
    },
    {
      uid: "test-panel-view-edit-live-zabbix",
      title: "View/Edit × Zabbix live",
      factory: (u, ti) => testViewEditDashboard(
        u,
        ti,
        "zabbix",
        "alexanderzobnin-zabbix-datasource"
      )
    },
    {
      uid: "test-panel-view-edit-live-signoz",
      title: "View/Edit × SigNoz live",
      factory: (u, ti) => testViewEditDashboard(u, ti, "signoz", "signoz")
    },
    {
      uid: "test-time-variables",
      title: "时间与变量联调",
      factory: testTimeVariablesDashboard
    },
    {
      uid: "test-transforms-live",
      title: "Transform 联调",
      factory: testTransformsDashboard
    },
    {
      uid: "test-six-states",
      title: "面板六态",
      factory: testSixStatesDashboard
    },
    {
      uid: "test-solo-embed",
      title: "Solo Embed 测试",
      factory: (u, ti) => dsTypedDashboard(u, ti, "grafana-testdata-datasource", "testdata")
    },
    {
      uid: "test-inspect-query-body",
      title: "Inspect Query Body",
      factory: (u, ti) => testViewEditDashboard(
        u,
        ti,
        "zabbix",
        "alexanderzobnin-zabbix-datasource"
      )
    },
    {
      uid: "test-same-config-pixel",
      title: "同配置像素回归",
      factory: testSameConfigPixelDashboard
    },
    // Task 17 live observability pages (factory — no tokens)
    ...(() => {
      const builders2 = getLiveDashboardBuilders();
      return Object.keys(builders2).map((uid) => ({
        uid,
        title: String(builders2[uid]?.()?.title || uid),
        factory: (u) => builders2[u]?.() ?? { uid: u, title: u, panels: [] }
      }));
    })(),
    // Built-in plugin dashboards (Zabbix / SigNoz)
    {
      uid: "zabbix-overview",
      title: "Zabbix 概览",
      factory: (u, ti) => loadPluginDashboard(
        "alexanderzobnin-zabbix-datasource",
        "zabbix-overview.json",
        u,
        ti
      )
    },
    {
      uid: "zabbix-problems",
      title: "Zabbix 问题",
      factory: (u, ti) => loadPluginDashboard(
        "alexanderzobnin-zabbix-datasource",
        "zabbix-problems.json",
        u,
        ti
      )
    },
    {
      uid: "zabbix-host",
      title: "Zabbix 主机",
      factory: (u, ti) => loadPluginDashboard(
        "alexanderzobnin-zabbix-datasource",
        "zabbix-host.json",
        u,
        ti
      )
    },
    {
      uid: "signoz-metrics",
      title: "SigNoz metrics",
      factory: (u, ti) => loadPluginDashboard("signoz", "signoz-metrics.json", u, ti)
    },
    {
      uid: "signoz-services",
      title: "SigNoz services",
      factory: (u, ti) => loadPluginDashboard("signoz", "signoz-services.json", u, ti)
    },
    {
      uid: "signoz-logs",
      title: "SigNoz logs",
      factory: (u, ti) => loadPluginDashboard("signoz", "signoz-logs.json", u, ti)
    },
    {
      uid: "signoz-traces",
      title: "SigNoz traces",
      factory: (u, ti) => loadPluginDashboard("signoz", "signoz-traces.json", u, ti)
    },
    {
      uid: "signoz-issues",
      title: "SigNoz issues",
      factory: (u, ti) => loadPluginDashboard("signoz", "signoz-issues.json", u, ti)
    },
    {
      uid: "signoz-service-overview",
      title: "SigNoz Service Overview",
      factory: (u, ti) => loadPluginDashboard("signoz", "service-overview.json", u, ti)
    },
    {
      uid: "signoz-metrics-overview",
      title: "SigNoz Metrics Overview",
      factory: (u, ti) => loadPluginDashboard("signoz", "metrics-overview.json", u, ti)
    },
    {
      uid: "signoz-logs-errors",
      title: "SigNoz Logs and Errors",
      factory: (u, ti) => loadPluginDashboard("signoz", "logs-and-errors.json", u, ti)
    },
    {
      uid: "signoz-distributed-traces",
      title: "SigNoz Distributed Traces",
      factory: (u, ti) => loadPluginDashboard("signoz", "distributed-traces.json", u, ti)
    },
    {
      uid: "signoz-observability-issues",
      title: "SigNoz Observability Issues",
      factory: (u, ti) => loadPluginDashboard("signoz", "observability-issues.json", u, ti)
    }
  ];
  const liveBuilderUids = new Set(Object.keys(getLiveDashboardBuilders()));
  for (const d of demos) {
    const factory2 = d.factory ?? demoDashboard;
    const existing = map[d.uid];
    let needs = !existing;
    if (existing && d.factory) {
      const panels2 = Array.isArray(existing.raw?.panels) ? existing.raw.panels : [];
      const types = panels2.map((p) => p?.datasource?.type || p?.targets?.[0]?.datasource?.type).filter(Boolean);
      if (liveBuilderUids.has(d.uid)) {
        const fresh = factory2(d.uid, d.title);
        const fp = Array.isArray(fresh?.panels) ? fresh.panels : [];
        const a = JSON.stringify({
          time: existing.raw?.time ?? null,
          titles: panels2.map((x) => x?.title),
          draw: panels2.map(
            (x) => x?.fieldConfig?.defaults?.custom?.drawStyle ?? null
          ),
          trends: panels2.map(
            (x) => x?.targets?.[0]?.options?.useTrends ?? null
          )
        });
        const b = JSON.stringify({
          time: fresh?.time ?? null,
          titles: fp.map((x) => x?.title),
          draw: fp.map(
            (x) => x?.fieldConfig?.defaults?.custom?.drawStyle ?? null
          ),
          trends: fp.map(
            (x) => x?.targets?.[0]?.options?.useTrends ?? null
          )
        });
        needs = a !== b;
      } else if (d.uid.startsWith("ds-zabbix") || d.uid.includes("live-zabbix")) {
        needs = !types.some((t) => String(t).includes("zabbix"));
      } else if (d.uid.startsWith("ds-signoz") || d.uid.includes("live-signoz")) {
        needs = !types.some((t) => String(t) === "signoz");
      } else if (d.uid.startsWith("ds-") && panels2.length < 3) {
        needs = true;
      }
      if (d.uid === "ds-zabbix-full" && panels2.length < 6) needs = true;
      if (d.uid.startsWith("ds-") && String(existing.raw?.time?.from || "") === "now-1h")
        needs = true;
      if (d.uid === "ds-zabbix-full") {
        const tgt = JSON.stringify(
          existing.raw?.panels?.[0]?.targets || []
        );
        if (!tgt.includes("vfs.fs.size")) needs = true;
      }
    }
    if (!needs) continue;
    map[d.uid] = {
      uid: d.uid,
      title: d.title,
      savedAt: (/* @__PURE__ */ new Date()).toISOString(),
      version: (existing?.version ?? 0) + 1,
      raw: factory2(d.uid, d.title)
    };
    dirty = true;
  }
  if (dirty) writeDashMap(map);
}
const DEFAULT_OFFLINE_DATASOURCES = [
  {
    uid: "testdata",
    name: "TestData",
    type: "grafana-testdata-datasource",
    isDefault: false,
    access: "proxy",
    jsonData: {}
  },
  {
    uid: "prometheus",
    name: "Prometheus",
    type: "prometheus",
    access: "proxy",
    url: "http://localhost:9090",
    jsonData: {}
  },
  {
    uid: "loki",
    name: "Loki",
    type: "loki",
    access: "proxy",
    url: "http://localhost:3100",
    jsonData: {}
  },
  {
    uid: "tempo",
    name: "Tempo",
    type: "tempo",
    access: "proxy",
    url: "http://localhost:3200",
    jsonData: {}
  },
  {
    uid: "opentelemetry",
    name: "OpenTelemetry",
    type: "opentelemetry",
    access: "proxy",
    url: "http://localhost:4318",
    jsonData: {}
  },
  // Offline seed uses dataMode=fixture so demo/viz matrices render without live upstream.
  // Live App config / live UIDs override this when operator supplies real credentials.
  {
    uid: "signoz",
    name: "SigNoz SigNoz",
    type: "signoz",
    access: "proxy",
    url: "/signoz-api",
    jsonData: { apiProfile: "signoz-v5", dataMode: "fixture" }
  },
  {
    uid: "signoz-native",
    name: "SigNoz Native",
    type: "signoz",
    access: "proxy",
    url: "/signoz-api",
    jsonData: { apiProfile: "signoz-v3", dataMode: "fixture" }
  },
  {
    uid: "zabbix",
    name: "Zabbix",
    type: "alexanderzobnin-zabbix-datasource",
    access: "proxy",
    url: "/zabbix-api3",
    jsonData: { dataMode: "fixture" }
  },
  {
    uid: "zabbix-3",
    name: "Zabbix 50.3",
    type: "alexanderzobnin-zabbix-datasource",
    access: "proxy",
    url: "/zabbix-api3",
    jsonData: { dataMode: "fixture" }
  },
  {
    uid: "zabbix-14",
    name: "Zabbix 50.14",
    type: "alexanderzobnin-zabbix-datasource",
    access: "proxy",
    url: "/zabbix-api14",
    jsonData: { dataMode: "fixture" }
  },
  {
    uid: "postgres",
    name: "PostgreSQL",
    type: "grafana-postgresql-datasource",
    access: "proxy",
    url: "localhost:5432",
    jsonData: {}
  },
  {
    uid: "mysql",
    name: "MySQL",
    type: "mysql",
    access: "proxy",
    url: "localhost:3306",
    jsonData: {}
  },
  {
    uid: "mssql",
    name: "MSSQL",
    type: "mssql",
    access: "proxy",
    url: "localhost:1433",
    jsonData: {}
  },
  {
    uid: "influxdb",
    name: "InfluxDB",
    type: "influxdb",
    access: "proxy",
    url: "http://localhost:8086",
    jsonData: {}
  },
  {
    uid: "graphite",
    name: "Graphite",
    type: "graphite",
    access: "proxy",
    url: "http://localhost:8080",
    jsonData: {}
  },
  {
    uid: "elasticsearch",
    name: "Elasticsearch",
    type: "elasticsearch",
    access: "proxy",
    url: "http://localhost:9200",
    jsonData: {}
  },
  {
    uid: "jaeger",
    name: "Jaeger",
    type: "jaeger",
    access: "proxy",
    url: "http://localhost:16686",
    jsonData: {}
  },
  {
    uid: "pyroscope",
    name: "Pyroscope",
    type: "grafana-pyroscope-datasource",
    access: "proxy",
    url: "http://localhost:4040",
    jsonData: {}
  },
  {
    uid: "cloudwatch",
    name: "CloudWatch",
    type: "cloudwatch",
    access: "proxy",
    jsonData: { defaultRegion: "us-east-1" }
  },
  {
    uid: "azure",
    name: "Azure Monitor",
    type: "grafana-azure-monitor-datasource",
    access: "proxy",
    jsonData: {}
  },
  {
    uid: "alertmanager",
    name: "Alertmanager",
    type: "alertmanager",
    access: "proxy",
    url: "http://localhost:9093",
    jsonData: {}
  },
  { uid: "mixed", name: "Mixed", type: "mixed", access: "proxy", jsonData: {} },
  {
    uid: "-- Grafana --",
    name: "Grafana",
    type: "grafana",
    access: "proxy",
    jsonData: {}
  },
  {
    uid: "dashboard",
    name: "Dashboard",
    type: "dashboard",
    access: "proxy",
    jsonData: {}
  }
];
function readDatasources() {
  const list = readJson(DS_STORAGE_KEY, []);
  if (!list.length) {
    writeJson(DS_STORAGE_KEY, DEFAULT_OFFLINE_DATASOURCES);
    return [...DEFAULT_OFFLINE_DATASOURCES];
  }
  const byUid2 = new Map(list.map((d) => [d.uid, d]));
  let dirty = false;
  for (const seed of DEFAULT_OFFLINE_DATASOURCES) {
    if (!byUid2.has(seed.uid)) {
      byUid2.set(seed.uid, seed);
      dirty = true;
      continue;
    }
    const existing = byUid2.get(seed.uid);
    const seedMode = seed.jsonData?.dataMode;
    const existMode = existing.jsonData?.dataMode;
    if (seedMode === "fixture" && existMode !== "live" && existMode !== "fixture") {
      byUid2.set(seed.uid, {
        ...existing,
        jsonData: { ...existing.jsonData || {}, ...seed.jsonData || {} }
      });
      dirty = true;
    }
  }
  const merged = [...byUid2.values()];
  if (dirty) writeJson(DS_STORAGE_KEY, merged);
  return merged;
}
function writeDatasources(list) {
  writeJson(DS_STORAGE_KEY, list);
}
function toPublicDatasource(ds2) {
  const anyDs = ds2;
  const secureJsonData = anyDs.secureJsonData;
  const fields = { ...anyDs.secureJsonFields ?? {} };
  if (secureJsonData && typeof secureJsonData === "object") {
    for (const [k, v] of Object.entries(secureJsonData)) {
      if (v != null && v !== "") fields[k] = true;
    }
  }
  const { secureJsonData: _drop, ...rest } = anyDs;
  return { ...rest, secureJsonFields: fields };
}
function pathOf(url) {
  try {
    if (url.startsWith("http")) {
      const u = new URL(url);
      return u.pathname + u.search;
    }
  } catch {
  }
  const q = url.indexOf("?");
  return q >= 0 ? url.slice(0, q) : url;
}
function queryParams(url, params) {
  const out = {};
  try {
    const full = url.startsWith("http") ? url : `http://local${url.startsWith("/") ? "" : "/"}${url}`;
    const u = new URL(full);
    u.searchParams.forEach((v, k) => {
      out[k] = v;
    });
  } catch {
  }
  if (params) {
    for (const [k, v] of Object.entries(params)) {
      if (v !== void 0) out[k] = String(v);
    }
  }
  return out;
}
function demoPanelOptions(type) {
  switch (type) {
    case "text":
      return {
        mode: "markdown",
        content: "## Grafana-Vue 全可视化演示\n每种 Panel 均有演示数据（TestData / 离线 fixture）。编辑 → 查询 / 转换 / 面板选项 / 字段。"
      };
    case "stat":
      return {
        reduceOptions: { calcs: ["lastNotNull"], fields: "", values: false },
        colorMode: "background",
        graphMode: "area",
        textMode: "auto",
        orientation: "auto"
      };
    case "gauge":
      return {
        showThresholdMarkers: true,
        showThresholdLabels: false,
        orientation: "auto",
        sizing: "auto"
      };
    case "bargauge":
      return {
        reduceOptions: { calcs: ["lastNotNull"], values: false },
        displayMode: "gradient",
        orientation: "horizontal",
        valueMode: "color",
        showUnfilled: true
      };
    case "piechart":
      return {
        reduceOptions: { calcs: ["lastNotNull"], values: true },
        pieType: "donut",
        legend: { showLegend: true, displayMode: "list", placement: "right" },
        tooltip: { mode: "single" }
      };
    case "timeseries":
    case "trend":
      return {
        legend: {
          showLegend: true,
          displayMode: "list",
          placement: "bottom",
          calcs: []
        },
        tooltip: { mode: "single", sort: "none" }
      };
    case "barchart":
      return {
        orientation: "auto",
        showValue: "auto",
        stacking: "none",
        barWidth: 0.9,
        groupWidth: 0.7,
        xTickLabelRotation: -30,
        legend: { showLegend: true, displayMode: "list", placement: "bottom" },
        tooltip: { mode: "single" }
      };
    case "histogram":
      return {
        bucketCount: 20,
        combine: false,
        fillOpacity: 80,
        gradientMode: "hue",
        stacking: "none"
      };
    case "heatmap":
      return {
        calculate: true,
        cellGap: 2,
        color: {
          mode: "scheme",
          scheme: "Spectral",
          reverse: false,
          steps: 64
        },
        legend: { show: true },
        tooltip: { mode: "single", yHistogram: true, showColorScale: true },
        yAxis: { axisPlacement: "left" }
      };
    case "candlestick":
      return {
        mode: "candles+volume",
        candleStyle: "candles",
        colorStrategy: "open-close",
        colors: { up: "green", down: "red", flat: "gray" },
        includeAllFields: false
      };
    case "state-timeline":
    case "status-history":
      return {
        showValue: "auto",
        rowHeight: 0.9,
        legend: { showLegend: true, displayMode: "list", placement: "bottom" }
      };
    case "logs":
      return {
        showTime: true,
        showLabels: false,
        showCommonLabels: false,
        wrapLogMessage: false,
        prettifyLogMessage: false,
        enableLogDetails: true,
        sortOrder: "Descending",
        dedupStrategy: "none",
        showLevel: true
      };
    case "logstable":
      return {
        enableLogDetails: true,
        showControls: true,
        showCopyLogLink: true,
        allowDownload: false
      };
    case "nodeGraph":
      return { layoutAlgorithm: "layered", zoomMode: "cooperative" };
    case "geomap":
      return {
        view: { lat: 0, lon: 0, zoom: 1 },
        controls: {
          showZoom: true,
          mouseWheelZoom: true,
          showAttribution: true
        },
        tooltip: { mode: "details" }
      };
    case "canvas":
      return {
        inlineEditing: false,
        showAdvancedTypes: true,
        tooltip: { mode: "single" },
        root: {
          type: "frame",
          elements: [
            {
              type: "metric-value",
              name: "Metric",
              config: { align: "center" },
              placement: { top: 20, left: 20, width: 120, height: 40 }
            }
          ]
        }
      };
    case "news":
      return { feedUrl: "https://grafana.com/blog/index.xml", showImage: true };
    case "dashlist":
      return {
        showStarred: true,
        showRecentlyViewed: true,
        showSearch: true,
        showHeadings: true,
        maxItems: 10
      };
    case "alertlist":
      return {
        maxItems: 10,
        viewMode: "list",
        groupMode: "default",
        sortOrder: 3
      };
    case "annolist":
      return {
        limit: 10,
        onlyInTimeRange: true,
        showTags: true,
        showTime: true,
        showUser: true
      };
    case "live":
      return { channel: "grafana/live/demo", display: "json" };
    case "debug":
      return { mode: "render" };
    case "traces":
      return {
        showServiceName: true,
        showDuration: true,
        spanFilters: { criticalPathOnly: false, matchesOnly: false }
      };
    case "flamegraph":
      return { showTable: true, collapsing: true, stickyHeader: true };
    case "table":
      return { showHeader: true, cellHeight: "sm", footer: { show: false } };
    case "xychart":
      return {
        series: [],
        mapping: "auto",
        legend: { showLegend: true },
        tooltip: { mode: "single" }
      };
    default:
      return {};
  }
}
function panelBase(id, type, title, gridPos, ds2, targets, options = {}) {
  return {
    id,
    type,
    title,
    gridPos,
    targets,
    datasource: ds2,
    options: { ...demoPanelOptions(type), ...options },
    fieldConfig: { defaults: {}, overrides: [] }
  };
}
function sampleTarget(type, uid) {
  const ds2 = { type, uid };
  switch (type) {
    case "alexanderzobnin-zabbix-datasource":
      return {
        refId: "A",
        datasource: ds2,
        queryType: "metrics",
        group: { filter: "/.*/" },
        host: { filter: "/.*/" },
        // Prefer a common Zabbix key so live demos return history points quickly.
        // Prefer keys that typically have history on busy Zabbix farms
        item: {
          filter: "/vfs.fs.size|cpu.util|system.uptime|system.cpu.load/"
        }
      };
    case "signoz":
      return {
        refId: "A",
        datasource: ds2,
        signal: "metrics",
        expr: "up",
        query: "up",
        queryType: "promql"
      };
    case "opentelemetry":
      return { refId: "A", datasource: ds2, signal: "metrics", expr: "up" };
    case "prometheus":
      return {
        refId: "A",
        datasource: ds2,
        expr: "up",
        legendFormat: "{{job}}"
      };
    case "loki":
      return {
        refId: "A",
        datasource: ds2,
        expr: '{job=~".+"}',
        queryType: "range"
      };
    case "tempo":
      return { refId: "A", datasource: ds2, queryType: "traceql", query: "{}" };
    case "jaeger":
      return { refId: "A", datasource: ds2, queryType: "search", service: "" };
    case "grafana-testdata-datasource":
    default:
      return { refId: "A", datasource: ds2, scenarioId: "random_walk" };
  }
}
function dsCatalogDashboard(uid, title) {
  const td = { type: "grafana-testdata-datasource", uid: "testdata" };
  const rows = [
    [
      "数据源测试中心",
      "打开下方链接进入各 DS 测试页；Zabbix/SigNoz 需 live 代理与 token。"
    ],
    ["ds-zabbix-full", "/d/ds-zabbix-full"],
    ["ds-signoz-full", "/d/ds-signoz-full"],
    ["ds-signoz-native-full", "/d/ds-signoz-native-full"],
    [
      "test-panel-view-edit-live-signoz-native",
      "/d/test-panel-view-edit-live-signoz-native"
    ],
    ["ds-otel-full", "/d/ds-otel-full"],
    ["ds-prometheus", "/d/ds-prometheus"],
    ["ds-testdata", "/d/ds-testdata"],
    ["test-panel-view-edit", "/d/test-panel-view-edit"],
    ["test-panel-view-edit-live-zabbix", "/d/test-panel-view-edit-live-zabbix"],
    ["test-panel-view-edit-live-signoz", "/d/test-panel-view-edit-live-signoz"]
  ];
  const content = rows.map((r, i) => i === 0 ? `## ${r[0]}\\n${r[1]}` : `- [${r[0]}](${r[1]})`).join("\\n");
  return {
    uid,
    title,
    tags: ["ds-test", "catalog"],
    schemaVersion: 39,
    timezone: "browser",
    version: 1,
    panels: [
      panelBase(
        1,
        "text",
        "数据源测试中心",
        { x: 0, y: 0, w: 24, h: 10 },
        td,
        [],
        {
          mode: "markdown",
          content
        }
      ),
      panelBase(2, "stat", "TestData 探活", { x: 0, y: 10, w: 6, h: 6 }, td, [
        { refId: "A", datasource: td, scenarioId: "random_walk" }
      ])
    ],
    time: { from: "now-1h", to: "now" },
    templating: { list: [] },
    annotations: { list: [] }
  };
}
function dsTypedDashboard(uid, title, type, dsUid) {
  const ds2 = { type, uid: dsUid };
  const target = sampleTarget(type, dsUid);
  const panels2 = [
    panelBase(
      1,
      "timeseries",
      `${title} · timeseries`,
      { x: 0, y: 0, w: 16, h: 10 },
      ds2,
      [target]
    ),
    panelBase(2, "stat", `${title} · stat`, { x: 16, y: 0, w: 8, h: 5 }, ds2, [
      target
    ]),
    panelBase(3, "gauge", `${title} · gauge`, { x: 16, y: 5, w: 8, h: 5 }, ds2, [
      target
    ]),
    panelBase(
      4,
      "table",
      `${title} · table`,
      { x: 0, y: 10, w: 12, h: 8 },
      ds2,
      [target]
    ),
    panelBase(
      5,
      "bargauge",
      `${title} · bargauge`,
      { x: 12, y: 10, w: 12, h: 8 },
      ds2,
      [target]
    )
  ];
  if (type === "alexanderzobnin-zabbix-datasource") {
    panels2.push(
      panelBase(
        6,
        "table",
        "Zabbix problems",
        { x: 0, y: 18, w: 24, h: 8 },
        ds2,
        [
          {
            refId: "A",
            datasource: ds2,
            queryType: "problems",
            group: { filter: "/.*/" },
            host: { filter: "/.*/" }
          }
        ]
      )
    );
    const ds14 = { type, uid: "zabbix-14" };
    panels2.push(
      panelBase(
        7,
        "timeseries",
        "Zabbix 50.14 · dual",
        { x: 0, y: 26, w: 24, h: 8 },
        ds14,
        [
          {
            refId: "A",
            datasource: ds14,
            queryType: "metrics",
            group: { filter: "/.*/" },
            host: { filter: "/.*/" },
            // Prefer keys that typically have history on busy Zabbix farms
            item: {
              filter: "/vfs.fs.size|cpu.util|system.uptime|system.cpu.load/"
            }
          }
        ]
      )
    );
  }
  if (type === "signoz") {
    panels2.push(
      panelBase(6, "logs", "SigNoz logs", { x: 0, y: 18, w: 12, h: 10 }, ds2, [
        { refId: "A", datasource: ds2, signal: "logs", expr: "", query: "" }
      ]),
      panelBase(
        7,
        "traces",
        "SigNoz traces",
        { x: 12, y: 18, w: 12, h: 10 },
        ds2,
        [{ refId: "A", datasource: ds2, signal: "traces", expr: "", query: "" }]
      )
    );
  }
  return {
    uid,
    title,
    tags: ["ds-test", type],
    schemaVersion: 39,
    timezone: "browser",
    version: 1,
    panels: panels2,
    // Prefer 6h so Zabbix history/trend has points for sparse items
    time: { from: "now-6h", to: "now" },
    templating: { list: [] },
    annotations: { list: [] }
  };
}
function dsVizMatrixDashboard(uid, title, type, dsUid) {
  const ds2 = { type, uid: dsUid };
  const target = sampleTarget(type, dsUid);
  const types = [
    "timeseries",
    "stat",
    "gauge",
    "bargauge",
    "table",
    "barchart",
    "piechart",
    "heatmap"
  ];
  const panels2 = types.map(
    (pt, i) => panelBase(
      i + 1,
      pt,
      pt,
      { x: i % 4 * 6, y: Math.floor(i / 4) * 8, w: 6, h: 8 },
      ds2,
      [target]
    )
  );
  return {
    uid,
    title,
    tags: ["ds-test", "viz-matrix", type],
    schemaVersion: 39,
    timezone: "browser",
    version: 1,
    panels: panels2,
    time: { from: "now-6h", to: "now" },
    templating: { list: [] },
    annotations: { list: [] }
  };
}
function dsTestdataDashboard(uid, title) {
  const td = { type: "grafana-testdata-datasource", uid: "testdata" };
  const scenarios = [
    "random_walk",
    "csv_metric_values",
    "random_walk_table",
    "logs",
    "trace",
    "node_graph",
    "flame_graph",
    "usa",
    "predictable_pulse",
    "predictable_csv_wave"
  ];
  const panels2 = scenarios.map(
    (s, i) => panelBase(
      i + 1,
      s === "logs" ? "logs" : s === "trace" ? "traces" : s === "node_graph" ? "nodeGraph" : s === "flame_graph" ? "flamegraph" : s === "random_walk_table" ? "table" : "timeseries",
      s,
      { x: i % 3 * 8, y: Math.floor(i / 3) * 8, w: 8, h: 8 },
      td,
      [{ refId: "A", datasource: td, scenarioId: s }]
    )
  );
  return {
    uid,
    title,
    tags: ["ds-test", "testdata"],
    schemaVersion: 39,
    timezone: "browser",
    version: 1,
    panels: panels2,
    time: { from: "now-1h", to: "now" },
    templating: { list: [] },
    annotations: { list: [] }
  };
}
function dsMixedDashboard(uid, title) {
  const mixed = { type: "mixed", uid: "mixed" };
  const td = { type: "grafana-testdata-datasource", uid: "testdata" };
  const prom = { type: "prometheus", uid: "prometheus" };
  return {
    uid,
    title,
    tags: ["ds-test", "mixed"],
    schemaVersion: 39,
    timezone: "browser",
    version: 1,
    panels: [
      panelBase(
        1,
        "timeseries",
        "Mixed A+B",
        { x: 0, y: 0, w: 24, h: 10 },
        mixed,
        [
          { refId: "A", datasource: td, scenarioId: "random_walk" },
          { refId: "B", datasource: prom, expr: "up" }
        ]
      )
    ],
    time: { from: "now-1h", to: "now" },
    templating: { list: [] },
    annotations: { list: [] }
  };
}
function testSameConfigPixelDashboard(uid, title) {
  const ds2 = { type: "grafana-testdata-datasource", uid: "testdata" };
  const target = {
    refId: "A",
    datasource: ds2,
    scenarioId: "csv_metric_values",
    stringInput: "1,20,90,30,5,0,40,70,15,55"
  };
  const fc = {
    defaults: {
      unit: "short",
      thresholds: {
        mode: "absolute",
        steps: [
          { color: "green", value: null },
          { color: "red", value: 80 }
        ]
      }
    },
    overrides: []
  };
  return {
    uid,
    title,
    tags: ["ds-test", "pixel", "same-config"],
    schemaVersion: 39,
    timezone: "utc",
    version: 1,
    panels: [
      {
        ...panelBase(
          1,
          "stat",
          "pixel-stat",
          { x: 0, y: 0, w: 6, h: 6 },
          ds2,
          [target],
          {
            colorMode: "background",
            graphMode: "area",
            reduceOptions: {
              calcs: ["lastNotNull"],
              fields: "",
              values: false
            }
          }
        ),
        fieldConfig: fc
      },
      {
        ...panelBase(
          2,
          "gauge",
          "pixel-gauge",
          { x: 6, y: 0, w: 6, h: 6 },
          ds2,
          [target],
          {
            showThresholdMarkers: true,
            orientation: "auto"
          }
        ),
        fieldConfig: fc
      },
      {
        ...panelBase(
          3,
          "timeseries",
          "pixel-timeseries",
          { x: 12, y: 0, w: 12, h: 8 },
          ds2,
          [target],
          {
            legend: {
              showLegend: true,
              displayMode: "list",
              placement: "bottom"
            }
          }
        ),
        fieldConfig: {
          defaults: {
            ...fc.defaults,
            custom: {
              drawStyle: "line",
              lineWidth: 1,
              fillOpacity: 20,
              showPoints: "never"
            }
          },
          overrides: []
        }
      },
      {
        ...panelBase(
          4,
          "table",
          "pixel-table",
          { x: 0, y: 6, w: 12, h: 8 },
          ds2,
          [{ refId: "A", datasource: ds2, scenarioId: "random_walk_table" }]
        ),
        fieldConfig: { defaults: {}, overrides: [] }
      },
      {
        ...panelBase(
          5,
          "bargauge",
          "pixel-bargauge",
          { x: 12, y: 8, w: 12, h: 6 },
          ds2,
          [target],
          {
            displayMode: "gradient",
            orientation: "horizontal",
            reduceOptions: { calcs: ["lastNotNull"], values: false }
          }
        ),
        fieldConfig: fc
      }
    ],
    time: { from: "now-15m", to: "now" },
    templating: { list: [] },
    annotations: { list: [] }
  };
}
function testViewEditDashboard(uid, title, dsUid = "testdata", type = "grafana-testdata-datasource") {
  const ds2 = { type, uid: dsUid };
  const target = sampleTarget(type, dsUid);
  return {
    uid,
    title,
    tags: ["ds-test", "view-edit"],
    schemaVersion: 39,
    timezone: "browser",
    version: 1,
    panels: [
      panelBase(
        1,
        "timeseries",
        "主面板（View/Edit）",
        { x: 0, y: 0, w: 16, h: 12 },
        ds2,
        [target]
      ),
      panelBase(2, "stat", "辅助 Stat", { x: 16, y: 0, w: 8, h: 6 }, ds2, [
        target
      ]),
      panelBase(3, "gauge", "辅助 Gauge", { x: 16, y: 6, w: 8, h: 6 }, ds2, [
        target
      ])
    ],
    time: { from: "now-15m", to: "now" },
    templating: { list: [] },
    annotations: { list: [] }
  };
}
function testTimeVariablesDashboard(uid, title) {
  const td = { type: "grafana-testdata-datasource", uid: "testdata" };
  return {
    uid,
    title,
    tags: ["ds-test", "variables"],
    schemaVersion: 39,
    timezone: "browser",
    version: 1,
    panels: [
      panelBase(1, "timeseries", "变量驱动", { x: 0, y: 0, w: 24, h: 10 }, td, [
        {
          refId: "A",
          datasource: td,
          scenarioId: "random_walk",
          alias: "$job"
        }
      ])
    ],
    time: { from: "now-1h", to: "now" },
    templating: {
      list: [
        {
          type: "custom",
          name: "job",
          label: "Job",
          query: "api,web,db",
          current: { text: "api", value: "api" },
          options: [
            { text: "api", value: "api", selected: true },
            { text: "web", value: "web", selected: false }
          ],
          multi: false,
          includeAll: false
        }
      ]
    },
    annotations: { list: [] }
  };
}
function testTransformsDashboard(uid, title) {
  const td = { type: "grafana-testdata-datasource", uid: "testdata" };
  return {
    uid,
    title,
    tags: ["ds-test", "transform"],
    schemaVersion: 39,
    timezone: "browser",
    version: 1,
    panels: [
      {
        ...panelBase(
          1,
          "table",
          "Reduce transform",
          { x: 0, y: 0, w: 24, h: 10 },
          td,
          [{ refId: "A", datasource: td, scenarioId: "random_walk" }]
        ),
        transformations: [
          { id: "reduce", options: { reducers: ["mean", "max"] } }
        ]
      }
    ],
    time: { from: "now-1h", to: "now" },
    templating: { list: [] },
    annotations: { list: [] }
  };
}
function testSixStatesDashboard(uid, title) {
  const td = { type: "grafana-testdata-datasource", uid: "testdata" };
  return {
    uid,
    title,
    tags: ["ds-test", "six-states"],
    schemaVersion: 39,
    timezone: "browser",
    version: 1,
    panels: [
      panelBase(1, "stat", "success", { x: 0, y: 0, w: 8, h: 6 }, td, [
        { refId: "A", datasource: td, scenarioId: "random_walk" }
      ]),
      panelBase(2, "stat", "empty-ish", { x: 8, y: 0, w: 8, h: 6 }, td, [
        { refId: "A", datasource: td, scenarioId: "no_data_points" }
      ]),
      panelBase(
        3,
        "timeseries",
        "loading-refresh",
        { x: 16, y: 0, w: 8, h: 6 },
        td,
        [
          {
            refId: "A",
            datasource: td,
            scenarioId: "random_walk",
            stringInput: "slow"
          }
        ]
      )
    ],
    time: { from: "now-15m", to: "now" },
    templating: { list: [] },
    annotations: { list: [] }
  };
}
function demoDashboard(uid, title) {
  const td = { type: "grafana-testdata-datasource", uid: "testdata" };
  const panelDefs = [
    { type: "text", title: "可视化全景演示", w: 24, h: 3 },
    { type: "stat", title: "Stat", scenario: "random_walk" },
    { type: "gauge", title: "Gauge", scenario: "random_walk" },
    { type: "bargauge", title: "Bar gauge", scenario: "csv_metric_values" },
    { type: "table", title: "Table", scenario: "random_walk_table" },
    {
      type: "piechart",
      title: "Pie chart",
      scenario: "csv_metric_values",
      stringInput: "10,25,40,15,30"
    },
    {
      type: "timeseries",
      title: "Time series",
      scenario: "random_walk",
      w: 12,
      h: 8
    },
    { type: "trend", title: "Trend", scenario: "linear_trend" },
    { type: "barchart", title: "Bar chart", scenario: "csv_metric_values" },
    { type: "histogram", title: "Histogram", scenario: "random_walk" },
    { type: "heatmap", title: "Heatmap", scenario: "random_walk" },
    {
      type: "candlestick",
      title: "Candlestick",
      scenario: "predictable_csv_wave"
    },
    {
      type: "state-timeline",
      title: "State timeline",
      scenario: "predictable_pulse",
      w: 12,
      h: 6
    },
    {
      type: "status-history",
      title: "Status history",
      scenario: "predictable_pulse",
      w: 12,
      h: 6
    },
    { type: "xychart", title: "XY chart", scenario: "random_walk" },
    { type: "geomap", title: "Geomap", scenario: "usa" },
    { type: "nodeGraph", title: "Node graph", scenario: "node_graph" },
    { type: "logs", title: "Logs", scenario: "logs", w: 12, h: 8 },
    { type: "logstable", title: "Logs table", scenario: "logs", w: 12, h: 8 },
    { type: "traces", title: "Traces", scenario: "trace", w: 12, h: 10 },
    {
      type: "flamegraph",
      title: "Flame graph",
      scenario: "flame_graph",
      w: 12,
      h: 10
    },
    { type: "canvas", title: "Canvas", scenario: "random_walk" },
    { type: "news", title: "News" },
    { type: "dashlist", title: "Dashboard list" },
    { type: "alertlist", title: "Alert list" },
    { type: "annolist", title: "Annotation list" },
    { type: "live", title: "Live" },
    { type: "debug", title: "Debug", scenario: "random_walk" },
    { type: "gettingstarted", title: "Getting started" },
    { type: "welcome", title: "Welcome" }
  ];
  let x = 0;
  let y = 0;
  let rowH = 0;
  const panels2 = panelDefs.map((d, idx) => {
    const w = d.w ?? 6;
    const h = d.h ?? 8;
    if (x + w > 24) {
      x = 0;
      y += rowH || 8;
      rowH = 0;
    }
    const gridPos = { x, y, w, h };
    x += w;
    rowH = Math.max(rowH, h);
    const options = demoPanelOptions(d.type);
    return {
      id: idx + 1,
      type: d.type,
      title: d.title,
      gridPos,
      targets: d.scenario ? [
        {
          refId: "A",
          datasource: td,
          scenarioId: d.scenario,
          ...d.stringInput ? { stringInput: d.stringInput } : {},
          ...d.seriesCount ? { seriesCount: d.seriesCount } : {}
        }
      ] : [],
      datasource: td,
      options,
      fieldConfig: { defaults: {}, overrides: [] }
    };
  });
  return {
    uid,
    title: title || "可视化全景演示",
    tags: ["demo", "all-panels"],
    schemaVersion: 39,
    timezone: "browser",
    version: 1,
    refresh: "30s",
    panels: panels2,
    time: { from: "now-6h", to: "now" },
    templating: {
      list: [
        {
          type: "custom",
          name: "job",
          label: "Job",
          query: "api,web,db",
          current: { text: "api", value: "api" },
          options: [
            { text: "api", value: "api", selected: true },
            { text: "web", value: "web", selected: false }
          ],
          multi: false,
          includeAll: false
        },
        {
          type: "interval",
          name: "interval",
          label: "Interval",
          query: "1m,5m,10m,1h",
          current: { text: "1m", value: "1m" },
          auto: true,
          auto_count: 30,
          auto_min: "10s"
        }
      ]
    },
    annotations: { list: [] }
  };
}
async function offlineRequest(opts) {
  seedDemoDashboards();
  const method = (opts.method ?? (opts.data ? "POST" : "GET")).toUpperCase();
  const path = pathOf(opts.url);
  const params = queryParams(opts.url, opts.params);
  {
    const m = path.match(/^\/api\/dashboards\/uid\/([^/]+)\/?$/);
    if (method === "GET" && m) {
      const uid = decodeURIComponent(m[1]);
      const map = readDashMap();
      const rec = map[uid];
      const pluginDash = loadPluginDashboard(
        "",
        "",
        uid,
        rec?.title || uid
      );
      let dashboard = rec?.raw ?? (Array.isArray(pluginDash?.panels) && pluginDash.panels.length > 0 ? pluginDash : demoDashboard(uid, rec?.title));
      const panels2 = dashboard?.panels;
      const panelTypes = new Set(
        (Array.isArray(panels2) ? panels2 : []).map((p) => p?.type).filter(Boolean)
      );
      const hasFreshTrend = (Array.isArray(panels2) ? panels2 : []).some(
        (p) => p?.type === "trend" && Array.isArray(p.targets) && p.targets.some((tg) => tg?.scenarioId === "linear_trend")
      );
      const hasFreshPie = (Array.isArray(panels2) ? panels2 : []).some(
        (p) => p?.type === "piechart" && Array.isArray(p.targets) && p.targets.some(
          (tg) => String(tg?.stringInput || "").includes("10,25,40")
        )
      );
      const needsDemoUpgrade = !Array.isArray(panels2) || panels2.length < 25 || !panelTypes.has("news") || !panelTypes.has("timeseries") || !panels2.some(
        (p) => p && (p.title === "Welcome" || String(p.title || "").includes("可视化"))
      ) || !hasFreshTrend || !hasFreshPie;
      if (needsDemoUpgrade && (uid === "vue-demo" || uid === "demo" || uid === "v1-demo")) {
        dashboard = demoDashboard(
          uid,
          String(dashboard?.title || rec?.title || uid)
        );
        if (rec) {
          map[uid] = {
            ...rec,
            raw: dashboard,
            title: String(dashboard.title || rec.title)
          };
          writeDashMap(map);
        }
      }
      return ok({
        dashboard,
        meta: {
          canSave: true,
          canEdit: true,
          canAdmin: true,
          canStar: false,
          slug: String(dashboard.title || uid).toLowerCase().replace(/\s+/g, "-"),
          url: `/d/${uid}`,
          version: rec?.version ?? 1,
          folderTitle: "General"
        }
      });
    }
  }
  if (method === "POST" && /^\/api\/dashboards\/db\/?$/.test(path)) {
    const body = opts.data ?? {};
    const dash = { ...body.dashboard ?? {} };
    const uid = String(dash.uid || `local-${Date.now().toString(36)}`);
    const title = String(dash.title || "Untitled dashboard");
    const map = readDashMap();
    const prev = map[uid];
    const version = (prev?.version ?? Number(dash.version) ?? 0) + 1;
    const raw = { ...dash, uid, title, version };
    map[uid] = {
      uid,
      title,
      raw,
      savedAt: (/* @__PURE__ */ new Date()).toISOString(),
      version
    };
    writeDashMap(map);
    return ok({
      status: "success",
      slug: title.toLowerCase().replace(/\s+/g, "-"),
      version,
      id: version,
      uid,
      url: `/d/${uid}/${title.toLowerCase().replace(/\s+/g, "-")}`
    });
  }
  if (method === "GET" && /^\/api\/search\/?$/.test(path)) {
    const type = params.type;
    const query = (params.query || params.q || "").toLowerCase();
    const map = readDashMap();
    let items = Object.values(map).map((d) => ({
      id: 0,
      uid: d.uid,
      title: d.title,
      uri: `db/${d.uid}`,
      url: `/d/${d.uid}/${d.title.toLowerCase().replace(/\s+/g, "-")}`,
      type: "dash-db",
      tags: [],
      isStarred: false
    }));
    if (type && type !== "dash-db") {
      items = [];
    }
    if (query) {
      items = items.filter(
        (i) => i.title.toLowerCase().includes(query) || i.uid.includes(query)
      );
    }
    const starredParam = String(params.starred ?? "").toLowerCase();
    if (starredParam === "true" || starredParam === "1") {
      items = items.filter((i) => !!i.isStarred);
    }
    return ok(items);
  }
  if (method === "GET" && /^\/api\/datasources\/?$/.test(path)) {
    return ok(readDatasources().map(toPublicDatasource));
  }
  {
    const m = path.match(/^\/api\/datasources\/uid\/([^/]+)\/?$/);
    if (method === "GET" && m) {
      const uid = decodeURIComponent(m[1]);
      const ds2 = readDatasources().find((d) => d.uid === uid);
      if (!ds2) notFound(`Data source not found: ${uid}`);
      return ok(toPublicDatasource(ds2));
    }
  }
  {
    const m = path.match(/^\/api\/datasources\/uid\/([^/]+)\/health\/?$/);
    if (method === "GET" && m) {
      return ok({ status: "OK", message: "Offline fixture OK" });
    }
  }
  if (method === "POST" && /^\/api\/datasources\/?$/.test(path)) {
    const body = opts.data ?? {};
    const list = readDatasources();
    const uid = body.uid || `ds-${Date.now().toString(36)}`;
    const bodyAny = body;
    const fields = {
      ...bodyAny.secureJsonFields || {}
    };
    if (bodyAny.secureJsonData && typeof bodyAny.secureJsonData === "object") {
      for (const [k, v] of Object.entries(bodyAny.secureJsonData)) {
        if (v != null && v !== "") fields[k] = true;
      }
    }
    const { secureJsonData: _dropSecure, ...bodyRest } = bodyAny;
    const rec = {
      ...bodyRest,
      uid,
      name: body.name || uid,
      type: body.type || "grafana-testdata-datasource",
      access: body.access || "proxy",
      jsonData: body.jsonData || {},
      secureJsonFields: fields
    };
    list.push(rec);
    writeDatasources(list);
    return ok(toPublicDatasource(rec));
  }
  {
    const m = path.match(/^\/api\/datasources\/uid\/([^/]+)\/?$/);
    if (method === "PUT" && m) {
      const uid = decodeURIComponent(m[1]);
      const list = readDatasources();
      const idx = list.findIndex((d) => d.uid === uid);
      if (idx < 0) notFound(`Data source not found: ${uid}`);
      const body = opts.data ?? {};
      const prev = list[idx];
      const bodyAny = body;
      const fields = {
        ...prev.secureJsonFields ?? {},
        ...bodyAny.secureJsonFields ?? {}
      };
      if (bodyAny.secureJsonData && typeof bodyAny.secureJsonData === "object") {
        for (const [k, v] of Object.entries(bodyAny.secureJsonData)) {
          if (v != null && v !== "") fields[k] = true;
        }
      }
      const { secureJsonData: _dropSecure, ...bodyRest } = bodyAny;
      const { secureJsonData: _prevSecure, ...prevRest } = prev;
      list[idx] = {
        ...prevRest,
        ...bodyRest,
        uid,
        secureJsonFields: fields
      };
      writeDatasources(list);
      return ok(toPublicDatasource(list[idx]));
    }
  }
  {
    const m = path.match(/^\/api\/datasources\/uid\/([^/]+)\/?$/);
    if (method === "DELETE" && m) {
      const uid = decodeURIComponent(m[1]);
      writeDatasources(readDatasources().filter((d) => d.uid !== uid));
      return ok({ message: "Data source deleted" });
    }
  }
  if (method === "POST" && /^\/api\/ds\/query\/?$/.test(path)) {
    return ok({ results: {} });
  }
  if (method === "GET" && /^\/api\/health\/?$/.test(path)) {
    return ok({
      database: "ok",
      version: "13.2.0-vue-offline",
      commit: "offline"
    });
  }
  notFound(`Offline backend: no handler for ${method} ${path}`);
}
function createHttpClient(opts) {
  const instance = axios.create({
    baseURL: opts.baseURL,
    timeout: opts.timeoutMs ?? 3e4,
    withCredentials: opts.withCredentials ?? false,
    // Caller decides ok/error — matches prior fetch + res.ok handling in adapters
    validateStatus: () => true,
    // Avoid axios transforming JSON automatically when we need raw text for size checks
    transitional: { forcedJSONParsing: false, silentJSONParsing: true },
    responseType: "text",
    adapter: opts.adapter
  });
  const ejectors = [];
  return {
    kind: opts.kind,
    axios: instance,
    async request(config) {
      return instance.request(config);
    },
    dispose() {
      for (const eject of ejectors) eject();
      ejectors.length = 0;
    }
  };
}
class NormalizedHeaders {
  map = /* @__PURE__ */ new Map();
  constructor(init) {
    if (!init) return;
    if (typeof init.forEach === "function" && typeof init.get === "function") {
      init.forEach((v, k) => this.map.set(k.toLowerCase(), v));
      return;
    }
    for (const [k, v] of Object.entries(init)) {
      if (v == null) continue;
      this.map.set(
        k.toLowerCase(),
        Array.isArray(v) ? String(v[0]) : String(v)
      );
    }
  }
  get(name) {
    return this.map.get(name.toLowerCase()) ?? null;
  }
  has(name) {
    return this.map.has(name.toLowerCase());
  }
  forEach(cb) {
    this.map.forEach((v, k) => cb(v, k));
  }
  entries() {
    return this.map.entries();
  }
}
let backendHttp = null;
let datasourceHttpClient = null;
function getBackendHttp() {
  if (!backendHttp) {
    backendHttp = createHttpClient({
      kind: "backend",
      withCredentials: true,
      timeoutMs: 6e4
    });
  }
  return backendHttp;
}
function getDatasourceHttpClient() {
  if (!datasourceHttpClient) {
    datasourceHttpClient = createHttpClient({
      kind: "datasource",
      withCredentials: false,
      timeoutMs: 6e4
    });
  }
  return datasourceHttpClient;
}
const __vite_import_meta_env__$2 = { "BASE_URL": "/", "DEV": false, "MODE": "production", "PROD": true, "SSR": false };
const STORAGE_KEY = "grafana-vue-auth-token";
const WINDOW_KEY = "__GRAFANA_VUE_AUTH_TOKEN__";
function nonEmpty$1(v) {
  if (v == null) return void 0;
  const s = String(v).trim();
  return s.length ? s : void 0;
}
function readEnvToken() {
  try {
    const meta2 = __vite_import_meta_env__$2;
    const fromVite = nonEmpty$1(meta2?.VITE_GRAFANA_TOKEN) || nonEmpty$1(meta2?.VITE_GRAFANA_API_TOKEN);
    if (fromVite) return fromVite;
  } catch {
  }
  try {
    const g = globalThis;
    return nonEmpty$1(g.process?.env?.GRAFANA_TOKEN) || nonEmpty$1(g.process?.env?.VITE_GRAFANA_TOKEN) || nonEmpty$1(g.process?.env?.GRAFANA_API_TOKEN);
  } catch {
    return void 0;
  }
}
function readWindowToken() {
  if (typeof globalThis === "undefined") return void 0;
  const w = globalThis;
  return nonEmpty$1(w[WINDOW_KEY]);
}
function readStorageToken() {
  try {
    if (typeof localStorage === "undefined") return void 0;
    return nonEmpty$1(localStorage.getItem(STORAGE_KEY));
  } catch {
    return void 0;
  }
}
function getGrafanaAuthToken() {
  return readWindowToken() ?? readStorageToken() ?? readEnvToken() ?? null;
}
class GrafanaAuthError extends Error {
  code = "AUTH_TOKEN_MISSING";
  constructor(message = "Grafana API token missing; set VITE_GRAFANA_TOKEN or window.__GRAFANA_VUE_AUTH_TOKEN__") {
    super(message);
    this.name = "GrafanaAuthError";
  }
}
function requireGrafanaAuthToken() {
  const t = getGrafanaAuthToken();
  if (!t) throw new GrafanaAuthError();
  return t;
}
function applyGrafanaAuthHeaders(headers = {}) {
  const out = { ...headers };
  if (out.Authorization || out.authorization) return out;
  const token = getGrafanaAuthToken();
  if (token) out.Authorization = `Bearer ${token}`;
  return out;
}
function isGrafanaLiveConfigured() {
  if (getGrafanaAuthToken()) return true;
  try {
    const meta2 = __vite_import_meta_env__$2;
    if (nonEmpty$1(meta2?.VITE_GRAFANA_URL) || nonEmpty$1(meta2?.VITE_GRAFANA_API_URL))
      return true;
  } catch {
  }
  try {
    const g = globalThis;
    if (nonEmpty$1(g.__GRAFANA_VUE_GRAFANA_URL__)) return true;
    if (nonEmpty$1(g.process?.env?.GRAFANA_URL) || nonEmpty$1(g.process?.env?.VITE_GRAFANA_URL))
      return true;
  } catch {
  }
  return false;
}
function getGrafanaBaseUrl() {
  try {
    const meta2 = __vite_import_meta_env__$2;
    const fromVite = nonEmpty$1(meta2?.VITE_GRAFANA_URL) || nonEmpty$1(meta2?.VITE_GRAFANA_API_URL);
    if (fromVite) return fromVite.replace(/\/$/, "");
  } catch {
  }
  try {
    const g = globalThis;
    const fromGlobal = nonEmpty$1(g.__GRAFANA_VUE_GRAFANA_URL__);
    if (fromGlobal) return fromGlobal.replace(/\/$/, "");
    const fromEnv = nonEmpty$1(g.process?.env?.GRAFANA_URL) || nonEmpty$1(g.process?.env?.VITE_GRAFANA_URL);
    if (fromEnv) return fromEnv.replace(/\/$/, "");
  } catch {
  }
  return "";
}
let baseUrl = "";
let clientOverride = null;
function configureLiveAdapter(opts) {
  if (opts.baseUrl != null) baseUrl = opts.baseUrl.replace(/\/$/, "");
  if (opts.client) {
    clientOverride = opts.client;
    return;
  }
  if (opts.axiosAdapter) {
    clientOverride = createHttpClient({
      kind: "backend",
      withCredentials: true,
      adapter: opts.axiosAdapter
    });
    return;
  }
  if (opts.fetch) {
    const fetchImpl = opts.fetch;
    clientOverride = createHttpClient({
      kind: "backend",
      withCredentials: true,
      adapter: async (config) => {
        const url = resolveUrl(config);
        const headers = {};
        const raw = config.headers;
        if (raw) {
          for (const [k, v] of Object.entries(raw)) {
            if (v == null || k === "common" || typeof v === "object") continue;
            headers[k] = String(v);
          }
        }
        const res = await fetchImpl(url, {
          method: (config.method || "GET").toUpperCase(),
          headers,
          body: config.data,
          signal: config.signal,
          credentials: "same-origin"
        });
        const text = await res.text();
        const h = {};
        res.headers.forEach((val, key) => {
          h[key] = val;
        });
        return {
          data: text,
          status: res.status,
          statusText: res.statusText,
          headers: h,
          config
        };
      }
    });
  }
}
function resolveUrl(config) {
  const base = config.baseURL || "";
  const url = config.url || "";
  if (url.startsWith("http")) return url;
  if (base) return `${base.replace(/\/$/, "")}/${url.replace(/^\//, "")}`;
  return url;
}
function buildUrl(url, params) {
  const full = url.startsWith("http") ? url : `${baseUrl}${url}`;
  if (!params) return full;
  const u = new URL(full, "http://local");
  for (const [k, v] of Object.entries(params)) {
    if (v !== void 0) u.searchParams.set(k, String(v));
  }
  if (full.startsWith("http")) return u.toString();
  return u.pathname + u.search;
}
async function liveRequest(opts) {
  const method = (opts.method ?? (opts.data ? "POST" : "GET")).toUpperCase();
  let headers = {
    Accept: "application/json",
    ...opts.headers ?? {}
  };
  headers = applyGrafanaAuthHeaders(headers);
  const pathOnly = (() => {
    try {
      const u = opts.url.startsWith("http") ? new URL(opts.url).pathname : opts.url.split("?")[0];
      return u;
    } catch {
      return opts.url;
    }
  })();
  const isGrafanaApi = pathOnly === "/api" || pathOnly.startsWith("/api/") || pathOnly.startsWith("/apis/");
  if (isGrafanaApi && !headers.Authorization && !headers.authorization) {
    if (getGrafanaAuthToken() === null && opts.requireAuth) {
      throw new GrafanaAuthError();
    }
  }
  let body;
  if (opts.data !== void 0) {
    headers["Content-Type"] = headers["Content-Type"] ?? "application/json";
    body = typeof opts.data === "string" ? opts.data : JSON.stringify(opts.data);
  }
  const client = clientOverride ?? getBackendHttp();
  const res = await client.request({
    url: buildUrl(opts.url, opts.params),
    method,
    headers,
    data: body,
    signal: opts.signal,
    responseType: "text",
    withCredentials: true
  });
  const text = typeof res.data === "string" ? res.data : res.data == null ? "" : String(res.data);
  let data;
  try {
    data = text ? JSON.parse(text) : null;
  } catch {
    data = text;
  }
  const normalized = new NormalizedHeaders(res.headers);
  const hdrs = new Headers();
  normalized.forEach((v, k) => hdrs.set(k, v));
  if (res.status < 200 || res.status >= 300) {
    const err = new Error(
      `Backend request failed: ${res.status} ${res.statusText}`
    );
    err.status = res.status;
    err.data = data;
    throw err;
  }
  return {
    data,
    status: res.status,
    statusText: res.statusText || "",
    ok: res.status >= 200 && res.status < 300,
    headers: hdrs
  };
}
let mode = "offline";
let customAdapter = null;
function detectInitialMode() {
  try {
    if (typeof globalThis !== "undefined") {
      const g = globalThis;
      const fromGlobal = g.__GRAFANA_VUE_BACKEND_MODE__;
      if (fromGlobal === "live" || fromGlobal === "offline") return fromGlobal;
      const env = g.process?.env?.GRAFANA_VUE_BACKEND_MODE ?? g.process?.env?.VITE_BACKEND_MODE;
      if (env === "live") return "live";
    }
  } catch {
  }
  return "offline";
}
mode = detectInitialMode();
function getBackendMode() {
  return mode;
}
function configureBackendSrv(opts) {
  if (opts.mode) mode = opts.mode;
  if (opts.adapter !== void 0) customAdapter = opts.adapter;
  const baseUrl2 = opts.baseUrl != null ? opts.baseUrl : getGrafanaBaseUrl();
  if (opts.fetch || opts.baseUrl != null || baseUrl2) {
    configureLiveAdapter({
      fetch: opts.fetch,
      baseUrl: baseUrl2 || opts.baseUrl
    });
  }
  if (opts.requireAuth != null) {
    globalThis.__GRAFANA_VUE_REQUIRE_AUTH__ = !!opts.requireAuth;
  }
}
function shouldServeFromOfflineSeed(url) {
  try {
    const path = url.startsWith("http") ? new URL(url).pathname : url.split("?")[0];
    if (path.startsWith("/zabbix-api") || path.startsWith("/signoz-api") || path.startsWith("/signoz-api") || path.includes("api_jsonrpc")) {
      return false;
    }
    if (isGrafanaLiveConfigured()) {
      const liveGrafanaPrefixes = [
        "/api/dashboards",
        "/api/search",
        "/api/folders",
        "/api/library-elements",
        "/api/annotations",
        "/api/user",
        "/api/org",
        "/api/orgs",
        "/api/frontend",
        "/api/plugins",
        "/api/datasources",
        "/api/ds/query",
        "/api/health"
      ];
      if (liveGrafanaPrefixes.some((p) => path === p || path.startsWith(p + "/"))) {
        return false;
      }
    }
    const offlinePrefixes = [
      "/api/dashboards",
      "/api/search",
      "/api/folders",
      "/api/library-elements",
      "/api/annotations",
      "/api/user",
      "/api/org",
      "/api/orgs",
      "/api/frontend",
      "/api/plugins",
      "/api/datasources",
      "/api/ds/query",
      // offline seeds for local demos without Grafana
      "/api/prometheus",
      "/api/v1",
      "/apis/"
    ];
    return offlinePrefixes.some(
      (p) => path === p || path.startsWith(p + "/") || path.startsWith(p)
    );
  } catch {
    return true;
  }
}
async function backendRequest(opts) {
  if (customAdapter) {
    return customAdapter.request(opts);
  }
  if (mode === "live") {
    if (shouldServeFromOfflineSeed(opts.url)) {
      return offlineRequest(opts);
    }
    if (globalThis.__GRAFANA_VUE_REQUIRE_AUTH__ && isGrafanaLiveConfigured()) {
      try {
        requireGrafanaAuthToken();
      } catch (e) {
        if (e instanceof GrafanaAuthError) throw e;
        throw e;
      }
    }
    return liveRequest({
      ...opts,
      requireAuth: !!globalThis.__GRAFANA_VUE_REQUIRE_AUTH__
    });
  }
  return offlineRequest(opts);
}
const backendSrv = {
  get: (url, params, options) => backendRequest({ ...options, method: "GET", url, params }),
  post: (url, data, options) => backendRequest({ ...options, method: "POST", url, data }),
  put: (url, data, options) => backendRequest({ ...options, method: "PUT", url, data }),
  patch: (url, data, options) => backendRequest({ ...options, method: "PATCH", url, data }),
  delete: (url, options) => backendRequest({ ...options, method: "DELETE", url }),
  request: backendRequest,
  configure: configureBackendSrv,
  getMode: getBackendMode
};
function createDataFrame(opts) {
  const fields = opts.fields.map((f) => ({
    name: f.name,
    type: f.type ?? inferType$1(f.values),
    config: f.config ?? {},
    values: f.values,
    labels: f.labels
  }));
  const length = fields.reduce((max, f) => Math.max(max, f.values.length), 0);
  return {
    refId: opts.refId,
    name: opts.name,
    fields,
    length,
    meta: opts.meta
  };
}
function inferType$1(values) {
  const sample = values.find((v) => v != null);
  if (typeof sample === "number") return "number";
  if (typeof sample === "boolean") return "boolean";
  if (sample instanceof Date) return "time";
  if (typeof sample === "string" && !Number.isNaN(Date.parse(sample)) && /\d{4}-\d{2}-\d{2}/.test(sample)) {
    return "time";
  }
  return typeof sample === "string" ? "string" : "other";
}
function cloneValue(v) {
  if (v == null || typeof v !== "object") return v;
  if (Array.isArray(v)) return v.map(cloneValue);
  return { ...v };
}
function asStringLabels(labels) {
  if (!labels) return void 0;
  const out = {};
  for (const [k, v] of Object.entries(labels)) {
    if (v == null) continue;
    out[String(k)] = String(v);
  }
  return out;
}
function isUint64String(v) {
  if (!/^\d+$/.test(v)) return false;
  if (v.length > 15) return true;
  try {
    const n = Number(v);
    return Number.isFinite(n) && !Number.isSafeInteger(n);
  } catch {
    return true;
  }
}
function normalizeTimeValue(v, trackNs) {
  if (v == null || v === "") return null;
  if (typeof v === "number") {
    if (!Number.isFinite(v)) return null;
    if (v > 1e15) {
      trackNs();
      return Math.floor(v / 1e6);
    }
    if (v > 0 && v < 1e11) return Math.floor(v * 1e3);
    return v;
  }
  if (v instanceof Date) return v.getTime();
  if (typeof v === "string" && /^\d+$/.test(v)) {
    if (v.length > 15) {
      trackNs();
      const ms = Number(v.slice(0, -6));
      return Number.isFinite(ms) ? ms : null;
    }
    const n2 = Number(v);
    if (Number.isFinite(n2)) return normalizeTimeValue(n2, trackNs);
  }
  const n = Number(v);
  if (Number.isFinite(n)) return normalizeTimeValue(n, trackNs);
  const d = Date.parse(String(v));
  return Number.isFinite(d) ? d : null;
}
function padField(f, len) {
  const values = f.values.slice(0, len);
  while (values.length < len) values.push(null);
  return {
    name: f.name,
    type: f.type,
    config: { ...f.config || {} },
    values,
    labels: asStringLabels(f.labels),
    state: f.state ? { ...f.state } : void 0
  };
}
function normalizeDataFrames(frames, ctx) {
  return (frames ?? []).map((frame) => {
    const refId = ctx?.refId ?? frame.refId;
    const fieldsIn = frame.fields ?? [];
    const len = fieldsIn.reduce(
      (m, f) => Math.max(m, f.values?.length ?? 0),
      0
    );
    const uint64Fields = /* @__PURE__ */ new Set();
    const nanosecondFields = /* @__PURE__ */ new Set();
    const fields = fieldsIn.map((f) => {
      let type = f.type;
      let values = (f.values ?? []).map((v) => v);
      if (type === "time" || /^time$/i.test(f.name)) {
        type = "time";
        values = values.map(
          (v) => normalizeTimeValue(v, () => {
            nanosecondFields.add(f.name);
          })
        );
      } else if (type === "number") {
        values = values.map((v) => {
          if (v == null || v === "") return null;
          if (typeof v === "number") return v;
          if (typeof v === "bigint") {
            const s = v.toString();
            if (isUint64String(s) || v > BigInt(Number.MAX_SAFE_INTEGER) || v < BigInt(Number.MIN_SAFE_INTEGER)) {
              uint64Fields.add(f.name);
              return s;
            }
            return Number(v);
          }
          if (typeof v === "string") {
            if (v === "NaN") return NaN;
            if (v === "+Inf" || v === "Infinity") return Infinity;
            if (v === "-Inf" || v === "-Infinity") return -Infinity;
            if (isUint64String(v)) {
              uint64Fields.add(f.name);
              return v;
            }
            const n2 = Number(v);
            return Number.isFinite(n2) || n2 === Infinity || n2 === -Infinity || Number.isNaN(n2) ? n2 : null;
          }
          const n = Number(v);
          return Number.isFinite(n) || n === Infinity || n === -Infinity || Number.isNaN(n) ? n : null;
        });
      }
      return padField(
        {
          name: f.name,
          type,
          config: { ...f.config || {} },
          values,
          labels: asStringLabels(f.labels),
          state: f.state
        },
        len
      );
    });
    const prevMeta = frame.meta ? cloneValue(frame.meta) : {};
    const prevCustom = prevMeta.custom && typeof prevMeta.custom === "object" && !Array.isArray(prevMeta.custom) ? { ...prevMeta.custom } : {};
    const custom = { ...prevCustom };
    if (ctx?.source != null) custom.source = ctx.source;
    if (ctx?.datasourceUid != null) custom.datasourceUid = ctx.datasourceUid;
    if (ctx?.profile != null) custom.profile = ctx.profile;
    if (ctx?.signal != null) custom.signal = ctx.signal;
    if (ctx?.requestId != null) custom.requestId = ctx.requestId;
    if (ctx?.semanticKind != null) custom.semanticKind = ctx.semanticKind;
    if (ctx?.preferredVisualisationType != null) {
      custom.preferredVisualisationType = ctx.preferredVisualisationType;
    }
    if (uint64Fields.size > 0) {
      const existing = Array.isArray(prevCustom.uint64Fields) ? prevCustom.uint64Fields : [];
      custom.uint64Fields = Array.from(/* @__PURE__ */ new Set([...existing, ...uint64Fields]));
    }
    if (nanosecondFields.size > 0) {
      const existing = Array.isArray(prevCustom.nanosecondFields) ? prevCustom.nanosecondFields : [];
      custom.nanosecondFields = Array.from(
        /* @__PURE__ */ new Set([...existing, ...nanosecondFields])
      );
    }
    const meta2 = { ...prevMeta };
    if (Object.keys(custom).length > 0) {
      meta2.custom = custom;
    }
    if (ctx?.preferredVisualisationType != null && meta2.preferredVisualisationType == null) {
      meta2.preferredVisualisationType = ctx.preferredVisualisationType;
    }
    return createDataFrame({
      refId,
      name: frame.name,
      meta: Object.keys(meta2).length > 0 ? meta2 : void 0,
      fields: fields.map((f) => ({
        name: f.name,
        type: f.type,
        values: f.values,
        config: f.config,
        labels: f.labels
      }))
    });
  });
}
function frameFingerprint(frames) {
  return JSON.stringify(
    frames.map((fr) => ({
      name: fr.name,
      refId: fr.refId,
      len: fr.length,
      fields: fr.fields.map((f) => ({
        name: f.name,
        type: f.type,
        labels: f.labels ?? {},
        config: {
          displayName: f.config?.displayName,
          unit: f.config?.unit,
          displayNameFromDS: f.config?.displayNameFromDS
        },
        n: f.values.length,
        head: f.values.slice(0, 3),
        tail: f.values.slice(-2)
      })),
      meta: fr.meta ?? {}
    }))
  );
}
function clamp(value, min = 0, max = 1) {
  return Math.min(Math.max(min, value), max);
}
function hexToRgb(color) {
  color = color.slice(1);
  const re = new RegExp(`.{1,${color.length >= 6 ? 2 : 1}}`, "g");
  let result = color.match(re);
  if (!result) return "";
  let colors = Array.from(result);
  if (colors[0].length === 1) {
    colors = colors.map((n) => n + n);
  }
  return `rgb${colors.length === 4 ? "a" : ""}(${colors.map(
    (n, index2) => index2 < 3 ? parseInt(n, 16) : Math.round(parseInt(n, 16) / 255 * 1e3) / 1e3
  ).join(", ")})`;
}
function hslToRgb(color) {
  const parts = decomposeColor(color);
  const { values } = parts;
  const h = values[0];
  const s = values[1] / 100;
  const l = values[2] / 100;
  const a = s * Math.min(l, 1 - l);
  const f = (n, k = (n + h / 30) % 12) => l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
  let type = "rgb";
  const rgb = [
    Math.round(f(0) * 255),
    Math.round(f(8) * 255),
    Math.round(f(4) * 255)
  ];
  if (parts.type === "hsla") {
    type += "a";
    rgb.push(values[3]);
  }
  return recomposeColor({ type, values: rgb });
}
function decomposeColor(color) {
  if (typeof color !== "string") return color;
  if (color.charAt(0) === "#") return decomposeColor(hexToRgb(color));
  const marker = color.indexOf("(");
  if (marker === -1) throw new Error(`Unsupported '${color}' color.`);
  const type = color.substring(0, marker);
  if (["rgb", "rgba", "hsl", "hsla", "color"].indexOf(type) === -1) {
    throw new Error(`Unsupported '${color}' color.`);
  }
  let values = color.substring(marker + 1, color.length - 1);
  let colorSpace;
  if (type === "color") {
    values = values.split(" ");
    colorSpace = values.shift();
    if (values.length === 4 && values[3].charAt(0) === "/")
      values[3] = values[3].slice(1);
  } else {
    values = values.split(",");
  }
  values = values.map((value) => parseFloat(value));
  return { type, values, colorSpace };
}
function recomposeColor(color) {
  const { type, colorSpace } = color;
  let values = color.values;
  if (type.indexOf("rgb") !== -1) {
    values = values.map(
      (n, i) => i < 3 ? parseInt(String(n), 10) : n
    );
  } else if (type.indexOf("hsl") !== -1) {
    values[1] = `${values[1]}%`;
    values[2] = `${values[2]}%`;
  }
  if (type.indexOf("color") !== -1) {
    values = `${colorSpace} ${values.join(" ")}`;
  } else {
    values = `${values.join(", ")}`;
  }
  return `${type}(${values})`;
}
function getContrastRatio(foreground, background, canvas) {
  const lumA = getLuminance(foreground);
  const lumB = getLuminance(background, canvas);
  return (Math.max(lumA, lumB) + 0.05) / (Math.min(lumA, lumB) + 0.05);
}
function getLuminance(color, background) {
  const parts = decomposeColor(color);
  let rgb = parts.type === "hsl" ? decomposeColor(hslToRgb(color)).values : parts.values;
  if (background && parts.type === "rgba") {
    const backgroundParts = decomposeColor(background);
    const alphaVal = rgb[3];
    rgb[0] = rgb[0] * alphaVal + backgroundParts.values[0] * (1 - alphaVal);
    rgb[1] = rgb[1] * alphaVal + backgroundParts.values[1] * (1 - alphaVal);
    rgb[2] = rgb[2] * alphaVal + backgroundParts.values[2] * (1 - alphaVal);
  }
  const rgbNumbers = rgb.map((val) => {
    if (parts.type !== "color") val /= 255;
    return val <= 0.03928 ? val / 12.92 : ((val + 0.055) / 1.055) ** 2.4;
  });
  return Number(
    (0.2126 * rgbNumbers[0] + 0.7152 * rgbNumbers[1] + 0.0722 * rgbNumbers[2]).toFixed(3)
  );
}
function emphasize(color, coefficient = 0.15) {
  return getLuminance(color) > 0.5 ? darken(color, coefficient) : lighten(color, coefficient);
}
function alpha(color, value) {
  if (color === "") return "#000000";
  value = clamp(value);
  if (color[0] === "#") {
    if (color.length === 9) color = color.substring(0, 7);
    else if (color.length <= 5) {
      let c = "#";
      for (let i = 1; i < 4; i++) c += color[i] + color[i];
      color = c;
    }
    return color + Math.round(value * 255).toString(16).padStart(2, "0");
  } else if (color[3] === "(") {
    return color.replace(")", `, ${value})`);
  } else if (color[4] === "(") {
    return color.substring(0, color.lastIndexOf(",")) + `, ${value})`;
  }
  const parts = decomposeColor(color);
  if (parts.type === "color") parts.values[3] = `/${value}`;
  else parts.values[3] = value;
  return recomposeColor(parts);
}
function darken(color, coefficient) {
  const parts = decomposeColor(color);
  coefficient = clamp(coefficient);
  if (parts.type.indexOf("hsl") !== -1) {
    parts.values[2] *= 1 - coefficient;
  } else if (parts.type.indexOf("rgb") !== -1 || parts.type.indexOf("color") !== -1) {
    for (let i = 0; i < 3; i += 1) parts.values[i] *= 1 - coefficient;
  }
  return recomposeColor(parts);
}
function lighten(color, coefficient) {
  const parts = decomposeColor(color);
  coefficient = clamp(coefficient);
  if (parts.type.indexOf("hsl") !== -1) {
    parts.values[2] += (100 - parts.values[2]) * coefficient;
  } else if (parts.type.indexOf("rgb") !== -1) {
    for (let i = 0; i < 3; i += 1)
      parts.values[i] += (255 - parts.values[i]) * coefficient;
  } else if (parts.type.indexOf("color") !== -1) {
    for (let i = 0; i < 3; i += 1)
      parts.values[i] += (1 - parts.values[i]) * coefficient;
  }
  return recomposeColor(parts);
}
const palette = {
  white: "#ffffff",
  black: "#000000",
  gray05: "#111217",
  gray10: "#181b1f",
  gray15: "#22252b",
  gray20: "#2c2f35",
  gray25: "#383b42",
  gray85: "#e1e2e3",
  gray90: "#ececed",
  gray95: "#f4f5f5",
  gray100: "#fbfbfb",
  blueDarkMain: "#3d71d9",
  blueDarkText: "#6e9fff",
  redDarkMain: "#d10e5c",
  redDarkText: "#ff5286",
  greenDarkMain: "#1a7f4b",
  greenDarkText: "#6ccf8e",
  orangeDarkMain: "#ff9900",
  orangeDarkText: "#fbad37",
  purpleDarkMain: "#C27AFF",
  purpleDarkText: "#D4A0FF",
  blueLightMain: "#3871dc",
  blueLightText: "#1f62e0",
  redLightMain: "#e0226e",
  redLightText: "#cf0e5B",
  greenLightMain: "#1b855e",
  greenLightText: "#0a764e",
  orangeLightMain: "#ff9900",
  orangeLightText: "#B04E0C",
  purpleLightMain: "#A24BC8",
  purpleLightText: "#7c2ea3"
};
function darkBase() {
  const whiteBase = "204, 204, 220";
  const text = {
    primary: `rgb(${whiteBase})`,
    secondary: `rgba(${whiteBase}, 0.65)`,
    disabled: `rgba(${whiteBase}, 0.61)`,
    link: palette.blueDarkText,
    maxContrast: palette.white
  };
  return {
    mode: "dark",
    border: {
      weak: "rgb(54, 57, 64)",
      medium: "rgb(68, 70, 78)",
      strong: "rgb(85, 87, 96)"
    },
    text,
    primary: {
      main: palette.blueDarkMain,
      text: palette.blueDarkText,
      border: palette.blueDarkText
    },
    secondary: {
      main: palette.gray20,
      shade: palette.gray25,
      transparent: `rgba(${whiteBase}, 0.08)`,
      text: text.primary,
      contrastText: `rgb(${whiteBase})`,
      border: `rgba(${whiteBase}, 0.08)`
    },
    tertiary: { main: palette.purpleDarkMain, text: palette.purpleDarkText },
    accent: {
      main: palette.blueDarkMain,
      text: palette.blueDarkText,
      border: palette.blueDarkText
    },
    info: { main: palette.blueDarkMain, text: palette.blueDarkText },
    error: {
      main: palette.redDarkMain,
      text: palette.redDarkText,
      border: palette.redDarkText
    },
    success: { main: palette.greenDarkMain, text: palette.greenDarkText },
    warning: { main: palette.orangeDarkMain, text: palette.orangeDarkText },
    background: {
      canvas: palette.gray05,
      page: palette.gray10,
      primary: palette.gray10,
      secondary: palette.gray15,
      elevated: palette.gray15
    },
    action: {
      hover: `rgba(${whiteBase}, 0.16)`,
      selected: `rgba(${whiteBase}, 0.12)`,
      selectedBorder: palette.orangeDarkMain,
      hoverOpacity: 0.08,
      focus: `rgba(${whiteBase}, 0.16)`,
      disabledBackground: `rgba(${whiteBase}, 0.04)`,
      disabledText: text.disabled,
      disabledOpacity: 0.38
    },
    gradients: {
      brandHorizontal: "linear-gradient(270deg, #F55F3E 0%, #FF8833 100%)",
      brandVertical: "linear-gradient(0.01deg, #F55F3E 0.01%, #FF8833 99.99%)"
    },
    scrollbar: `rgba(${whiteBase}, 0.3)`,
    contrastThreshold: 3,
    hoverFactor: 0.03,
    tonalOffset: 0.15
  };
}
function lightBase() {
  const blackBase = "36, 41, 46";
  const primary = {
    main: palette.blueLightMain,
    border: palette.blueLightText,
    text: palette.blueLightText
  };
  const text = {
    primary: `rgba(${blackBase}, 1)`,
    secondary: `rgba(${blackBase}, 0.75)`,
    disabled: `rgba(${blackBase}, 0.65)`,
    link: primary.text,
    maxContrast: palette.black
  };
  const border = {
    weak: "rgb(229, 229, 230)",
    medium: "rgb(189, 191, 192)",
    strong: "rgb(167, 169, 171)"
  };
  return {
    mode: "light",
    primary,
    text,
    border,
    secondary: {
      main: palette.gray90,
      shade: palette.gray85,
      transparent: `rgba(${blackBase}, 0.08)`,
      contrastText: `rgba(${blackBase}, 1)`,
      text: text.primary,
      border: border.weak
    },
    tertiary: { main: palette.purpleLightMain, text: palette.purpleLightText },
    accent: primary,
    info: { main: palette.blueLightMain, text: palette.blueLightText },
    error: {
      main: palette.redLightMain,
      text: palette.redLightText,
      border: palette.redLightText
    },
    success: { main: palette.greenLightMain, text: palette.greenLightText },
    warning: { main: palette.orangeLightMain, text: palette.orangeLightText },
    background: {
      canvas: palette.gray100,
      page: palette.white,
      primary: palette.white,
      secondary: palette.gray95,
      elevated: palette.white
    },
    action: {
      hover: `rgba(${blackBase}, 0.12)`,
      selected: `rgba(${blackBase}, 0.08)`,
      selectedBorder: palette.orangeLightMain,
      hoverOpacity: 0.08,
      focus: `rgba(${blackBase}, 0.12)`,
      disabledBackground: `rgba(${blackBase}, 0.04)`,
      disabledText: text.disabled,
      disabledOpacity: 0.38
    },
    gradients: {
      brandHorizontal: "linear-gradient(90deg, #FF8833 0%, #F53E4C 100%)",
      brandVertical: "linear-gradient(0.01deg, #F53E4C -31.2%, #FF8833 113.07%)"
    },
    scrollbar: `rgba(${blackBase}, 0.3)`,
    contrastThreshold: 3,
    hoverFactor: 0.03,
    tonalOffset: 0.2
  };
}
function createColors(mode2) {
  const base = mode2 === "light" ? lightBase() : darkBase();
  const tonalOffset = base.tonalOffset;
  const hoverFactor = base.hoverFactor;
  const contrastThreshold = base.contrastThreshold;
  function getContrastText(background, threshold = contrastThreshold) {
    const dark = darkBase();
    const light = lightBase();
    return getContrastRatio(
      dark.text.maxContrast,
      background,
      base.background.primary
    ) >= threshold ? dark.text.maxContrast : light.text.maxContrast;
  }
  function getRichColor(color, name) {
    const result = { ...color, name };
    if (!result.main) result.main = base[name].main;
    if (!result.text) result.text = result.main;
    if (!result.border) result.border = result.text;
    if (!result.shade) {
      result.shade = base.mode === "light" ? darken(result.main, tonalOffset) : lighten(result.main, tonalOffset);
    }
    if (!result.transparent) result.transparent = alpha(result.main, 0.15);
    if (!result.contrastText)
      result.contrastText = getContrastText(result.main);
    if (!result.borderTransparent)
      result.borderTransparent = alpha(result.border, 0.25);
    return result;
  }
  return {
    mode: base.mode,
    text: base.text,
    background: base.background,
    border: base.border,
    gradients: base.gradients,
    action: base.action,
    scrollbar: base.scrollbar,
    hoverFactor,
    contrastThreshold,
    tonalOffset,
    primary: getRichColor(base.primary, "primary"),
    secondary: getRichColor(base.secondary, "secondary"),
    tertiary: getRichColor(base.tertiary, "tertiary"),
    accent: getRichColor(base.accent, "accent"),
    info: getRichColor(base.info, "info"),
    error: getRichColor(base.error, "error"),
    success: getRichColor(base.success, "success"),
    warning: getRichColor(base.warning, "warning"),
    getContrastText,
    emphasize: (color, factor) => emphasize(color, factor ?? hoverFactor)
  };
}
const FALLBACK_COLOR = "#808080";
function createVisualizationColors(colors) {
  const baseHues = colors.mode === "light" ? getLightHues() : getDarkHues();
  const hues = baseHues;
  const byNameIndex = {};
  for (const hue of hues) {
    for (const shade of hue.shades) {
      byNameIndex[shade.name] = shade.color;
      if (shade.aliases) {
        for (const alias of shade.aliases) byNameIndex[alias] = shade.color;
      }
    }
  }
  byNameIndex["transparent"] = colors.mode === "light" ? "rgba(255, 255, 255, 0)" : "rgba(0,0,0,0)";
  byNameIndex["panel-bg"] = colors.background.primary;
  byNameIndex["text"] = colors.text.primary;
  const palette2 = getClassicPalette().map((name) => {
    if (name.startsWith("#")) return name;
    return byNameIndex[name] ?? name;
  });
  const getColorByName = (colorName) => {
    if (!colorName) return FALLBACK_COLOR;
    const realColor = byNameIndex[colorName];
    if (realColor) return realColor;
    if (colorName[0] === "#") return colorName;
    if (colorName.indexOf("rgb") > -1) return colorName;
    const nativeColor = nativeColorNames[colorName.toLowerCase()];
    if (nativeColor) {
      byNameIndex[colorName] = nativeColor;
      return nativeColor;
    }
    return colorName;
  };
  return { hues, palette: palette2, getColorByName };
}
function getDarkHues() {
  return [
    {
      name: "red",
      shades: [
        { color: "#FFA6B0", name: "super-light-red" },
        { color: "#FF7383", name: "light-red" },
        { color: "#F2495C", name: "red", primary: true },
        { color: "#E02F44", name: "semi-dark-red" },
        { color: "#C4162A", name: "dark-red" }
      ]
    },
    {
      name: "orange",
      shades: [
        { color: "#FFCB7D", name: "super-light-orange" },
        { color: "#FFB357", name: "light-orange" },
        { color: "#FF9830", name: "orange", primary: true },
        { color: "#FF780A", name: "semi-dark-orange" },
        { color: "#FA6400", name: "dark-orange" }
      ]
    },
    {
      name: "yellow",
      shades: [
        { color: "#FFF899", name: "super-light-yellow" },
        { color: "#FFEE52", name: "light-yellow" },
        { color: "#FADE2A", name: "yellow", primary: true },
        { color: "#F2CC0C", name: "semi-dark-yellow" },
        { color: "#E0B400", name: "dark-yellow" }
      ]
    },
    {
      name: "green",
      shades: [
        { color: "#C8F2C2", name: "super-light-green" },
        { color: "#96D98D", name: "light-green" },
        { color: "#73BF69", name: "green", primary: true },
        { color: "#56A64B", name: "semi-dark-green" },
        { color: "#37872D", name: "dark-green" }
      ]
    },
    {
      name: "blue",
      shades: [
        { color: "#C0D8FF", name: "super-light-blue" },
        { color: "#8AB8FF", name: "light-blue" },
        { color: "#5794F2", name: "blue", primary: true },
        { color: "#3274D9", name: "semi-dark-blue" },
        { color: "#1F60C4", name: "dark-blue" }
      ]
    },
    {
      name: "purple",
      shades: [
        { color: "#DEB6F2", name: "super-light-purple" },
        { color: "#CA95E5", name: "light-purple" },
        { color: "#B877D9", name: "purple", primary: true },
        { color: "#A352CC", name: "semi-dark-purple" },
        { color: "#8F3BB8", name: "dark-purple" }
      ]
    }
  ];
}
function getLightHues() {
  return [
    {
      name: "red",
      shades: [
        { color: "#FF7383", name: "super-light-red" },
        { color: "#F2495C", name: "light-red" },
        { color: "#E02F44", name: "red", primary: true },
        { color: "#C4162A", name: "semi-dark-red" },
        { color: "#AD0317", name: "dark-red" }
      ]
    },
    {
      name: "orange",
      shades: [
        { color: "#FFB357", name: "super-light-orange" },
        { color: "#FF9830", name: "light-orange" },
        { color: "#FF780A", name: "orange", primary: true },
        { color: "#FA6400", name: "semi-dark-orange" },
        { color: "#E55400", name: "dark-orange" }
      ]
    },
    {
      name: "yellow",
      shades: [
        { color: "#FFEE52", name: "super-light-yellow" },
        { color: "#FADE2A", name: "light-yellow" },
        { color: "#F2CC0C", name: "yellow", primary: true },
        { color: "#E0B400", name: "semi-dark-yellow" },
        { color: "#CC9D00", name: "dark-yellow" }
      ]
    },
    {
      name: "green",
      shades: [
        { color: "#96D98D", name: "super-light-green" },
        { color: "#73BF69", name: "light-green" },
        { color: "#56A64B", name: "green", primary: true },
        { color: "#37872D", name: "semi-dark-green" },
        { color: "#19730E", name: "dark-green" }
      ]
    },
    {
      name: "blue",
      shades: [
        { color: "#8AB8FF", name: "super-light-blue" },
        { color: "#5794F2", name: "light-blue" },
        { color: "#3274D9", name: "blue", primary: true },
        { color: "#1F60C4", name: "semi-dark-blue" },
        { color: "#1250B0", name: "dark-blue" }
      ]
    },
    {
      name: "purple",
      shades: [
        { color: "#CA95E5", name: "super-light-purple" },
        { color: "#B877D9", name: "light-purple" },
        { color: "#A352CC", name: "purple", primary: true },
        { color: "#8F3BB8", name: "semi-dark-purple" },
        { color: "#7C2EA3", name: "dark-purple" }
      ]
    }
  ];
}
function getClassicPalette() {
  return [
    "green",
    "semi-dark-yellow",
    "blue",
    "orange",
    "red",
    "purple",
    "dark-green",
    "dark-yellow",
    "dark-blue",
    "dark-orange",
    "dark-red",
    "dark-purple",
    "super-light-green",
    "super-light-yellow",
    "super-light-blue",
    "super-light-orange",
    "super-light-red",
    "super-light-purple",
    "#447EBC",
    "#C15C17",
    "#890F02",
    "#0A437C",
    "#6D1F62",
    "#584477",
    "#B7DBAB",
    "#F4D598",
    "#70DBED",
    "#F9BA8F",
    "#F29191",
    "#82B5D8",
    "#E5A8E2",
    "#AEA2E0",
    "#629E51",
    "#E5AC0E",
    "#64B0C8",
    "#E0752D",
    "#BF1B00",
    "#0A50A1",
    "#962D82",
    "#614D93",
    "#9AC48A",
    "#F2C96D",
    "#65C5DB",
    "#F9934E",
    "#EA6460",
    "#5195CE",
    "#D683CE",
    "#806EB7",
    "#3F6833",
    "#967302",
    "#2F575E",
    "#99440A",
    "#58140C",
    "#052B51",
    "#511749",
    "#3F2B5B",
    "#E0F9D7",
    "#FCEACA",
    "#CFFAFF",
    "#F9E2D2",
    "#FCE2DE",
    "#BADFF4",
    "#F9D9F9",
    "#DEDAF7"
  ];
}
const nativeColorNames = {
  black: "#000000",
  white: "#ffffff",
  red: "#ff0000",
  green: "#008000",
  blue: "#0000ff",
  yellow: "#ffff00",
  orange: "#ffa500",
  purple: "#800080",
  gray: "#808080",
  grey: "#808080",
  transparent: "rgba(0,0,0,0)"
};
function createComponents(colors, shadows) {
  const elevated = colors.background.elevated;
  const inputBackground = colors.mode === "dark" ? colors.background.canvas : colors.background.primary;
  return {
    height: { sm: 24, md: 32, lg: 48 },
    input: {
      background: inputBackground,
      text: colors.text.primary,
      borderColor: colors.border.medium,
      borderHover: colors.border.strong
    },
    panel: {
      background: colors.background.primary,
      borderColor: colors.border.weak,
      padding: 8,
      contentBg: colors.background.secondary
    },
    dropdown: {
      background: elevated,
      borderColor: colors.border.weak,
      selectedBackground: colors.action.selected
    },
    tooltip: {
      background: elevated,
      text: colors.text.primary,
      borderColor: colors.border.weak
    },
    overlay: {
      background: colors.mode === "dark" ? "rgba(63, 62, 62, 0.5)" : "rgba(208, 209, 211, 0.5)",
      borderColor: colors.border.weak,
      boxShadow: shadows.z3 ?? shadows.z2 ?? "none"
    },
    table: {
      headerBackground: colors.background.secondary,
      rowHoverBackground: colors.action.hover,
      rowSelectedBackground: colors.action.selected
    },
    drawer: {
      background: colors.background.primary,
      borderColor: colors.border.weak
    },
    menu: {
      background: elevated,
      activeBackground: colors.action.selected,
      activeText: colors.text.primary
    }
  };
}
function createSpacing(gridSize = 8) {
  const spacing = ((factor = 1) => `${gridSize * factor}px`);
  spacing.gridSize = gridSize;
  return spacing;
}
function createTheme(options = {}) {
  const mode2 = options.colors?.mode === "light" ? "light" : "dark";
  const colors = createColors(mode2);
  const visualization = createVisualizationColors(colors);
  const typography = {
    fontFamily: "'Inter', 'Helvetica', 'Arial', sans-serif",
    fontFamilyMonospace: "'Roboto Mono', monospace",
    fontSize: 14,
    fontWeightLight: 300,
    fontWeightRegular: 400,
    fontWeightMedium: 500,
    fontWeightBold: 500,
    h1: {
      fontSize: "28px",
      fontWeight: 400,
      lineHeight: 32 / 28,
      letterSpacing: `${-0.25 / 28}em`
    },
    h2: {
      fontSize: "24px",
      fontWeight: 400,
      lineHeight: 28 / 24,
      letterSpacing: "0em"
    },
    h3: {
      fontSize: "22px",
      fontWeight: 400,
      lineHeight: 24 / 22,
      letterSpacing: "0em"
    },
    h4: {
      fontSize: "18px",
      fontWeight: 400,
      lineHeight: 22 / 18,
      letterSpacing: `${0.25 / 18}em`
    },
    h5: {
      fontSize: "16px",
      fontWeight: 400,
      lineHeight: 22 / 16,
      letterSpacing: "0em"
    },
    h6: {
      fontSize: "14px",
      fontWeight: 500,
      lineHeight: 22 / 14,
      letterSpacing: `${0.15 / 14}em`
    },
    body: {
      fontSize: "14px",
      fontWeight: 400,
      lineHeight: 22 / 14,
      letterSpacing: `${0.15 / 14}em`
    },
    bodySmall: {
      fontSize: "12px",
      fontWeight: 400,
      lineHeight: 18 / 12,
      letterSpacing: `${0.15 / 12}em`
    }
  };
  const bp = { xs: 0, sm: 544, md: 769, lg: 992, xl: 1200, xxl: 1440 };
  const shadows = mode2 === "dark" ? {
    z1: "0px 1px 2px rgba(1, 4, 9, 0.75)",
    z2: "0px 4px 8px rgba(1, 4, 9, 0.75)",
    z3: "0px 8px 24px rgb(1, 4, 9)"
  } : {
    z1: "0px 1px 2px rgba(24, 26, 27, 0.2)",
    z2: "0px 4px 8px rgba(24, 26, 27, 0.2)",
    z3: "0px 13px 20px 1px rgba(24, 26, 27, 0.18)"
  };
  return {
    name: options.name ?? (mode2 === "dark" ? "Dark" : "Light"),
    isDark: mode2 === "dark",
    isLight: mode2 === "light",
    colors,
    spacing: createSpacing(8),
    shape: {
      radius: {
        default: "6px",
        sm: "4px",
        md: "6px",
        lg: "10px",
        pill: "9999px",
        circle: "100%"
      }
    },
    typography,
    zIndex: {
      content: 1,
      activePanel: 999,
      dropdown: 1030,
      typeahead: 1030,
      navbarFixed: 1e3,
      sidemenu: 1020,
      tooltip: 1040,
      modalBackdrop: 1050,
      modal: 1060,
      portal: 1061
    },
    shadows,
    transitions: {
      duration: { short: "100ms", medium: "200ms", long: "300ms" },
      easing: { easeInOut: "cubic-bezier(0.4, 0, 0.2, 1)" }
    },
    visualization,
    components: createComponents(colors, shadows),
    flags: { visualDesignRefresh: options.flags?.visualDesignRefresh },
    breakpoints: {
      values: bp,
      up: (key) => `@media (min-width: ${bp[key] ?? 0}px)`,
      down: (key) => `@media (max-width: ${(bp[key] ?? 0) - 0.02}px)`
    }
  };
}
function applyTheme2CssVars(theme, el = document.documentElement) {
  const { colors, typography, spacing, shape, shadows } = theme;
  const map = {
    // legacy / short aliases (compat with existing components)
    "--grafana-bg": colors.background.canvas,
    "--grafana-panel-bg": colors.background.primary,
    "--grafana-canvas-bg": colors.background.canvas,
    "--grafana-dashboard-bg": colors.background.canvas,
    "--grafana-border-color-weak": colors.border.weak,
    "--grafana-border-color-medium": colors.border.medium,
    "--grafana-border-color-strong": colors.border.strong,
    "--grafana-text": colors.text.primary,
    "--grafana-text-secondary": colors.text.secondary,
    "--grafana-primary": colors.primary.main,
    "--grafana-border": colors.border.medium,
    "--grafana-error": colors.error.main,
    "--grafana-success": colors.success.main,
    "--grafana-warning": colors.warning.main,
    "--grafana-hover": colors.action.hover,
    "--grafana-input-bg": theme.components.input.background,
    // background hierarchy
    "--grafana-bg-canvas": colors.background.canvas,
    "--grafana-bg-page": colors.background.page,
    "--grafana-bg-primary": colors.background.primary,
    "--grafana-bg-secondary": colors.background.secondary,
    "--grafana-bg-elevated": colors.background.elevated,
    // text
    "--grafana-text-primary": colors.text.primary,
    "--grafana-text-disabled": colors.text.disabled,
    "--grafana-text-link": colors.text.link,
    "--grafana-text-max-contrast": colors.text.maxContrast,
    // borders
    "--grafana-border-weak": colors.border.weak,
    // legacy alias used by older scoped CSS (Zabbix etc.)
    "--border-weak": colors.border.weak,
    "--grafana-border-medium": colors.border.medium,
    "--grafana-border-strong": colors.border.strong,
    // action
    "--grafana-action-hover": colors.action.hover,
    "--grafana-action-selected": colors.action.selected,
    "--grafana-action-focus": colors.action.focus,
    "--grafana-action-disabled-bg": colors.action.disabledBackground,
    "--grafana-action-disabled-text": colors.action.disabledText,
    "--grafana-action-selected-border": colors.action.selectedBorder,
    // rich colors
    "--grafana-primary-main": colors.primary.main,
    "--grafana-primary-text": colors.primary.text,
    "--grafana-primary-border": colors.primary.border,
    "--grafana-primary-shade": colors.primary.shade,
    "--grafana-primary-transparent": colors.primary.transparent,
    "--grafana-primary-contrast": colors.primary.contrastText,
    "--grafana-secondary-main": colors.secondary.main,
    "--grafana-secondary-text": colors.secondary.text,
    "--grafana-secondary-border": colors.secondary.border,
    "--grafana-secondary-transparent": colors.secondary.transparent,
    "--grafana-error-main": colors.error.main,
    "--grafana-error-text": colors.error.text,
    "--grafana-error-border": colors.error.border,
    "--grafana-error-transparent": colors.error.transparent,
    "--grafana-error-contrast": colors.error.contrastText,
    "--grafana-success-main": colors.success.main,
    "--grafana-success-text": colors.success.text,
    "--grafana-success-transparent": colors.success.transparent,
    "--grafana-warning-main": colors.warning.main,
    "--grafana-warning-text": colors.warning.text,
    "--grafana-warning-transparent": colors.warning.transparent,
    "--grafana-info-main": colors.info.main,
    "--grafana-info-text": colors.info.text,
    // shadows
    "--grafana-shadow-z1": shadows.z1 ?? "",
    "--grafana-shadow-z2": shadows.z2 ?? "",
    "--grafana-shadow-z3": shadows.z3 ?? "",
    // gradients
    "--grafana-gradient-brand-horizontal": colors.gradients.brandHorizontal,
    "--grafana-gradient-brand-vertical": colors.gradients.brandVertical,
    // scrollbar
    "--grafana-scrollbar": colors.scrollbar,
    // typography / shape
    "--grafana-font-family": typography.fontFamily,
    "--grafana-font-size": `${typography.fontSize}px`,
    "--grafana-spacing-grid": `${spacing.gridSize}px`,
    "--grafana-radius": shape.radius.default,
    // panel
    "--grafana-panel-border": theme.components.panel.borderColor,
    "--grafana-panel-padding": `${theme.components.panel.padding}px`,
    "--grafana-panel-content-bg": theme.components.panel.contentBg,
    // component states (from theme.components only)
    "--grafana-input-border-hover": theme.components.input.borderHover,
    "--grafana-dropdown-bg": theme.components.dropdown.background,
    "--grafana-dropdown-border": theme.components.dropdown.borderColor,
    "--grafana-dropdown-selected-bg": theme.components.dropdown.selectedBackground,
    "--grafana-tooltip-bg": theme.components.tooltip.background,
    "--grafana-tooltip-text": theme.components.tooltip.text,
    "--grafana-tooltip-border": theme.components.tooltip.borderColor,
    "--grafana-overlay-bg": theme.components.overlay.background,
    "--grafana-overlay-border": theme.components.overlay.borderColor,
    "--grafana-overlay-shadow": theme.components.overlay.boxShadow,
    "--grafana-table-header-bg": theme.components.table.headerBackground,
    "--grafana-table-row-hover-bg": theme.components.table.rowHoverBackground,
    "--grafana-table-row-selected-bg": theme.components.table.rowSelectedBackground,
    "--grafana-drawer-bg": theme.components.drawer.background,
    "--grafana-drawer-border": theme.components.drawer.borderColor,
    "--grafana-menu-bg": theme.components.menu.background,
    "--grafana-menu-active-bg": theme.components.menu.activeBackground,
    "--grafana-menu-active-text": theme.components.menu.activeText
  };
  for (const [k, v] of Object.entries(map)) {
    if (v !== void 0 && v !== null) el.style.setProperty(k, v);
  }
  el.dataset.theme = colors.mode;
  el.style.colorScheme = colors.mode;
  el.classList.remove("theme-light", "theme-dark");
  el.classList.add(`theme-${colors.mode}`);
  if (theme.flags.visualDesignRefresh) el.dataset.visualDesignRefresh = "true";
  else delete el.dataset.visualDesignRefresh;
  if (el === document.documentElement && document.body) {
    document.body.dataset.theme = colors.mode;
    document.body.classList.remove("theme-light", "theme-dark");
    document.body.classList.add(`theme-${colors.mode}`);
    document.body.style.background = colors.background.canvas;
    document.body.style.color = colors.text.primary;
  }
}
function headingCss(selector, v) {
  return `
${selector} {
  margin: 0;
  margin-bottom: 0.45em;
  font-size: ${v.fontSize};
  font-weight: ${v.fontWeight};
  line-height: ${v.lineHeight};
  font-family: inherit;
  ${v.letterSpacing ? `letter-spacing: ${v.letterSpacing};` : ""}
}`;
}
function createGlobalStyles(theme) {
  const { colors, typography } = theme;
  return `
html {
  box-sizing: border-box;
  height: 100%;
  font-size: ${typography.fontSize}px;
  font-family: ${typography.fontFamily};
  line-height: ${typography.body.lineHeight};
  font-kerning: normal;
}
html, body {
  margin: 0;
  padding: 0;
}
body {
  height: 100%;
  width: 100%;
  background: ${colors.background.canvas};
  color: ${colors.text.primary};
  font-family: ${typography.fontFamily};
  font-size: ${typography.body.fontSize};
  font-weight: ${typography.body.fontWeight};
  line-height: ${typography.body.lineHeight};
  letter-spacing: ${typography.body.letterSpacing ?? "0"};
  font-variant-ligatures: no-contextual;
}
*, *::before, *::after { box-sizing: inherit; }
:focus-visible {
  outline: 2px solid ${colors.primary.main};
  outline-offset: 2px;
}
${headingCss("h1, .h1", typography.h1)}
${headingCss("h2, .h2", typography.h2)}
${headingCss("h3, .h3", typography.h3)}
${headingCss("h4, .h4", typography.h4)}
${headingCss("h5, .h5", typography.h5)}
${headingCss("h6, .h6", typography.h6)}
p {
  margin: 0 0 16px;
}
code, pre, kbd {
  font-family: ${typography.fontFamilyMonospace};
}
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-thumb {
  background: ${colors.border.medium};
  border-radius: 4px;
}
body * {
  scrollbar-color: ${colors.scrollbar} transparent;
  scrollbar-width: thin;
}
::selection {
  background: ${colors.action.selected};
  color: ${colors.text.primary};
}
a {
  color: ${colors.text.link};
  text-decoration: none;
}
a:hover {
  text-decoration: underline;
}
a.external-link, .text-link, .link {
  color: ${colors.text.link};
}
`;
}
function applyGlobalStyles(theme, doc = document) {
  const id = "grafana-vue-global-styles";
  let el = doc.getElementById(id);
  if (!el) {
    el = doc.createElement("style");
    el.id = id;
    doc.head.appendChild(el);
  }
  el.textContent = createGlobalStyles(theme);
}
function applyResolvedTheme(theme, el = document.documentElement) {
  applyTheme2CssVars(theme, el);
  applyGlobalStyles(theme, el.ownerDocument);
}
function watchSystemTheme(cb) {
  if (typeof window === "undefined" || !window.matchMedia) return () => {
  };
  const mql = window.matchMedia("(prefers-color-scheme: dark)");
  const handler = () => cb(mql.matches ? "dark" : "light");
  mql.addEventListener?.("change", handler);
  return () => mql.removeEventListener?.("change", handler);
}
const THEME_STORAGE_KEY = "grafana-vue-theme-preference";
const listeners$1 = /* @__PURE__ */ new Set();
const state = reactive({
  preference: "dark"
});
const theme2Ref = shallowRef(
  createTheme({ colors: { mode: "dark" } })
);
function systemPrefersDark() {
  if (typeof window === "undefined" || !window.matchMedia) return true;
  return window.matchMedia("(prefers-color-scheme: dark)").matches;
}
function resolveMode(pref = state.preference) {
  if (pref === "system") return systemPrefersDark() ? "dark" : "light";
  return pref;
}
function readStoredPreference() {
  if (typeof localStorage === "undefined") return null;
  try {
    const v = localStorage.getItem(THEME_STORAGE_KEY);
    if (v === "light" || v === "dark" || v === "system") return v;
  } catch {
  }
  return null;
}
function writeStoredPreference(pref) {
  if (typeof localStorage === "undefined") return;
  try {
    localStorage.setItem(THEME_STORAGE_KEY, pref);
  } catch {
  }
}
function readUrlTheme() {
  if (typeof window === "undefined") return null;
  try {
    const q = new URLSearchParams(window.location.search);
    const t = q.get("theme");
    if (t === "light" || t === "dark") return t;
  } catch {
  }
  return null;
}
function readBootTheme() {
  try {
    const boot = globalThis.__grafana_boot_data__ ?? globalThis.grafanaBootData;
    const t = boot?.user?.theme;
    if (t === "light" || t === "dark" || t === "system") return t;
  } catch {
  }
  return null;
}
function resolveInitialPreference() {
  const url = readUrlTheme();
  if (url) {
    const stored = readStoredPreference() ?? readBootTheme() ?? "dark";
    return { preference: stored, runtimeOnly: url };
  }
  return { preference: readStoredPreference() ?? readBootTheme() ?? "dark" };
}
function applyDom(mode2, theme) {
  if (typeof document === "undefined") return;
  applyResolvedTheme(theme, document.documentElement);
  document.documentElement.style.colorScheme = mode2;
  document.documentElement.dataset.theme = mode2;
  if (document.body) {
    document.body.style.colorScheme = mode2;
    document.body.dataset.theme = mode2;
  }
}
function notify(mode2) {
  for (const fn of listeners$1) {
    try {
      fn(mode2);
    } catch {
    }
  }
}
function rebuildTheme(mode2, persist) {
  const theme = createTheme({ colors: { mode: mode2 } });
  theme2Ref.value = theme;
  applyDom(mode2, theme);
  if (persist) writeStoredPreference(state.preference);
  notify(mode2);
}
function initTheme(options) {
  const fallback = resolveInitialPreference();
  const preference = fallback.preference;
  const runtimeOnly = fallback.runtimeOnly;
  state.preference = preference;
  const mode2 = runtimeOnly ?? resolveMode(preference);
  rebuildTheme(mode2, !runtimeOnly);
  return mode2;
}
if (typeof window !== "undefined") {
  try {
    watchSystemTheme(() => {
      if (state.preference === "system" && !readUrlTheme()) {
        rebuildTheme(resolveMode("system"), false);
      }
    });
  } catch {
  }
}
class RuntimeDataSourceSettingsError extends Error {
  constructor(message, code) {
    super(message);
    this.code = code;
    this.name = "RuntimeDataSourceSettingsError";
  }
  code;
}
const registry$1 = /* @__PURE__ */ new Map();
function assertNoSecrets(settings) {
  const blob = JSON.stringify(settings);
  if (/(?:"password"|"token"|"secureJsonData"|"apiKey")\s*:\s*"[^"]+"/i.test(blob)) {
    throw new RuntimeDataSourceSettingsError(
      "settings must not contain secret values",
      "SETTINGS_CONTAIN_SECRETS"
    );
  }
  const jd = settings.jsonData || {};
  for (const k of Object.keys(jd)) {
    if (/token|password|secret|apiKey|authorization/i.test(k) && jd[k]) {
      throw new RuntimeDataSourceSettingsError(
        `jsonData must not contain secret field ${k}`,
        "SETTINGS_CONTAIN_SECRETS"
      );
    }
  }
}
function assertSingleDefault(list) {
  const defaults2 = list.filter((s) => s.isDefault);
  if (defaults2.length > 1) {
    throw new RuntimeDataSourceSettingsError(
      `multiple default datasources: ${defaults2.map((d) => d.uid).join(",")}`,
      "DATASOURCE_DEFAULT_CONFLICT"
    );
  }
}
function clearRuntimeDataSourceSettings() {
  registry$1.clear();
}
function configureRuntimeDataSourceSettings(settings) {
  clearRuntimeDataSourceSettings();
  const seen = /* @__PURE__ */ new Set();
  const next = [];
  for (const raw of settings) {
    if (!raw?.uid) {
      throw new RuntimeDataSourceSettingsError(
        "datasource uid is required",
        "MISSING_UID"
      );
    }
    if (seen.has(raw.uid)) {
      throw new RuntimeDataSourceSettingsError(
        `duplicate uid: ${raw.uid}`,
        "DUPLICATE_UID"
      );
    }
    seen.add(raw.uid);
    const entry = {
      ...raw,
      source: raw.source ?? "runtime",
      jsonData: { ...raw.jsonData || {} }
    };
    assertNoSecrets(entry);
    next.push(entry);
  }
  assertSingleDefault(next);
  for (const e of next) registry$1.set(e.uid, e);
}
function listRuntimeDataSourceSettings() {
  return [...registry$1.values()].map((s) => ({
    ...s,
    jsonData: { ...s.jsonData || {} }
  }));
}
const VISIBLE_UIDS = /* @__PURE__ */ new Set(["zabbix-3", "zabbix-14", "signoz"]);
async function listDataSources() {
  const runtime = listRuntimeDataSourceSettings();
  const fromRuntime = runtime.filter((s) => VISIBLE_UIDS.has(s.uid)).map((s) => ({
    uid: s.uid,
    name: s.name,
    type: s.type,
    isDefault: s.isDefault ?? false,
    url: s.url,
    access: s.access,
    jsonData: s.jsonData
  }));
  if (fromRuntime.length > 0) return fromRuntime;
  try {
    const res = await backendSrv.get("/api/datasources");
    const all = res.data ?? [];
    return all.filter((d) => VISIBLE_UIDS.has(d.uid));
  } catch {
    return [];
  }
}
const SECRET_RE = /(authorization|token|password|secret|apikey|api[_-]?key|bearer|auth)\s*[:=]\s*['"]?[^'"\s,}]+/gi;
const JSON_SECRET_RE = /"(authorization|token|password|secret|apikey|api[_-]?key|auth)"\s*:\s*"[^"]*"/gi;
const SECRET_KEY_RE = /^(authorization|token|password|secret|apikey|api[_-]?key|bearer|auth)$/i;
function sanitizeErrorText(text) {
  return String(text ?? "").replace(JSON_SECRET_RE, '"$1":"[REDACTED]"').replace(SECRET_RE, "$1=[REDACTED]");
}
function redactEndpoint(endpoint) {
  if (!endpoint) return void 0;
  try {
    const u = new URL(endpoint);
    u.username = "";
    u.password = "";
    const parts = [];
    for (const [key, value] of u.searchParams.entries()) {
      if (/(token|auth|password|secret|key|bearer)/i.test(key)) {
        parts.push(`${encodeURIComponent(key)}=[REDACTED]`);
      } else {
        parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);
      }
    }
    const base = `${u.origin}${u.pathname}`.replace(/\/\/:+@/, "//").replace(/\/\/@/, "//");
    return parts.length ? `${base}?${parts.join("&")}${u.hash || ""}` : `${base}${u.hash || ""}`;
  } catch {
    return sanitizeErrorText(endpoint);
  }
}
function sanitizeUnknown(value) {
  if (typeof value === "string") return sanitizeErrorText(value);
  if (Array.isArray(value)) return value.map(sanitizeUnknown);
  if (value && typeof value === "object") {
    const out = {};
    for (const [k, v] of Object.entries(value)) {
      out[k] = SECRET_KEY_RE.test(k) ? "[REDACTED]" : sanitizeUnknown(v);
    }
    return out;
  }
  return value;
}
const ALLOWED_DETAIL_KEYS = /* @__PURE__ */ new Set([
  "uid",
  "refId",
  "endpoint",
  "status",
  "upstreamCode",
  "retryAfterMs",
  "url",
  "signal"
]);
function pickDetails(details) {
  if (!details) return void 0;
  const cleaned = sanitizeUnknown(details);
  const out = {};
  for (const key of Object.keys(cleaned)) {
    if (!ALLOWED_DETAIL_KEYS.has(key)) continue;
    out[key] = cleaned[key];
  }
  if (out.endpoint) out.endpoint = redactEndpoint(String(out.endpoint));
  if (out.url) out.url = redactEndpoint(String(out.url));
  return out;
}
class DataSourceError extends Error {
  code;
  details;
  constructor(code, message, details) {
    super(sanitizeErrorText(message));
    this.name = "DataSourceError";
    this.code = code;
    this.details = pickDetails(details);
  }
  static fromHttpStatus(status, _statusText, url) {
    if (status === 401) {
      return new DataSourceError(
        "AUTH_REQUIRED",
        `数据源认证失败（${status}）`,
        { status, url }
      );
    }
    if (status === 403) {
      return new DataSourceError("FORBIDDEN", `数据源拒绝访问（${status}）`, {
        status,
        url
      });
    }
    if (status === 404) {
      return new DataSourceError("NOT_FOUND", `数据源资源不存在（${status}）`, {
        status,
        url
      });
    }
    if (status === 429) {
      return new DataSourceError(
        "RATE_LIMITED",
        `数据源请求过于频繁（${status}）`,
        { status, url }
      );
    }
    if (status >= 500) {
      return new DataSourceError(
        "UPSTREAM_ERROR",
        `数据源服务异常（${status}）`,
        { status, url }
      );
    }
    return new DataSourceError(
      "INVALID_RESPONSE",
      `数据源返回无效 HTTP 状态（${status}）`,
      {
        status,
        url
      }
    );
  }
  static fromNetwork(err, url) {
    if (err instanceof DataSourceError) return err;
    const msg = err instanceof Error ? err.message : String(err);
    const name = err instanceof Error ? err.name : "";
    if (name === "AbortError" || typeof DOMException !== "undefined" && err instanceof DOMException && err.name === "AbortError") {
      return new DataSourceError("CANCELLED", "数据源请求已取消", { url });
    }
    if (/^abort/i.test(msg) && !/timeout/i.test(msg)) {
      return new DataSourceError("CANCELLED", "数据源请求已取消", { url });
    }
    if (/timeout/i.test(msg)) {
      return new DataSourceError("TIMEOUT", "数据源请求超时", { url });
    }
    if (err instanceof TypeError || /failed to fetch|networkerror|cors/i.test(msg)) {
      return new DataSourceError(
        "CORS_BLOCKED",
        "Network/CORS failure — target must allow browser origin",
        {
          url
        }
      );
    }
    return new DataSourceError("NETWORK_ERROR", msg || "Network error", {
      url
    });
  }
}
function withDataSourceContext(error, ctx) {
  const base = error instanceof DataSourceError ? error : new DataSourceError(
    "UNKNOWN",
    error instanceof Error ? error.message : String(error ?? "未知错误")
  );
  return new DataSourceError(base.code, base.message, {
    ...base.details,
    uid: ctx.uid ?? base.details?.uid,
    refId: ctx.refId ?? base.details?.refId,
    endpoint: ctx.endpoint ?? base.details?.endpoint,
    status: ctx.status ?? base.details?.status,
    upstreamCode: ctx.upstreamCode ?? base.details?.upstreamCode,
    retryAfterMs: ctx.retryAfterMs ?? base.details?.retryAfterMs
  });
}
const memory = /* @__PURE__ */ new Map();
function setRuntimeCredential(uid, cred) {
  if (!cred) memory.delete(uid);
  else memory.set(uid, cred);
}
async function getRuntimeCredential(uid) {
  if (memory.has(uid)) return memory.get(uid) ?? null;
  return null;
}
function applyCredentialHeaders(headers, cred) {
  if (!cred) return headers;
  const out = { ...headers };
  if ((cred.kind === "bearer" || cred.kind === "session") && cred.value) {
    out.Authorization = `Bearer ${cred.value}`;
  } else if (cred.kind === "basic" && (cred.username != null || cred.password != null)) {
    const raw = `${cred.username ?? ""}:${cred.password ?? ""}`;
    out.Authorization = `Basic ${typeof btoa === "function" ? btoa(raw) : Buffer.from(raw).toString("base64")}`;
  } else if (cred.kind === "apiKey" && cred.value) {
    out[cred.headerName || "X-API-Key"] = cred.value;
  } else if (cred.kind === "headers" && cred.headers) {
    Object.assign(out, cred.headers);
  }
  return out;
}
const HTTP_LOG_MAX = 40;
const httpLog = [];
function redactUrl(url) {
  try {
    const u = new URL(url);
    for (const key of [...u.searchParams.keys()]) {
      if (/(token|auth|password|secret|key|bearer)/i.test(key))
        u.searchParams.set(key, "[REDACTED]");
    }
    return u.toString();
  } catch {
    return url.replace(
      /(authorization|token|password|secret|apikey|bearer)=([^&\s]+)/gi,
      "$1=[REDACTED]"
    );
  }
}
function previewBody(body, max = 4e3) {
  if (!body) return void 0;
  let text = sanitizeErrorText(body);
  text = text.replace(/"auth"\s*:\s*"[^"]*"/gi, '"auth":"[REDACTED]"');
  text = text.replace(/"token"\s*:\s*"[^"]*"/gi, '"token":"[REDACTED]"');
  text = text.replace(/"password"\s*:\s*"[^"]*"/gi, '"password":"[REDACTED]"');
  if (text.length > max) text = text.slice(0, max) + "…";
  return text;
}
function pushHttpLog(entry) {
  httpLog.push(entry);
  while (httpLog.length > HTTP_LOG_MAX) httpLog.shift();
}
function joinUrl(baseUrl2, path = "") {
  let base = baseUrl2;
  if (base.startsWith("/") && typeof globalThis !== "undefined" && globalThis.location?.origin) {
    base = `${globalThis.location.origin}${base}`;
  } else if (base.startsWith("/") && !base.startsWith("//")) {
    base = `http://local${base}`;
  }
  if (!base.endsWith("/")) base = `${base}/`;
  const p = path.startsWith("/") ? path.slice(1) : path;
  return new URL(p, base);
}
function mergeSignals$1(a, b) {
  if (!a) return b;
  if (!b) return a;
  if (typeof AbortSignal !== "undefined" && "any" in AbortSignal && typeof AbortSignal.any === "function") {
    return AbortSignal.any([a, b]);
  }
  const c = new AbortController();
  const onAbort = () => c.abort();
  if (a.aborted || b.aborted) c.abort();
  else {
    a.addEventListener("abort", onAbort);
    b.addEventListener("abort", onAbort);
  }
  return c.signal;
}
async function sleep(ms, signal) {
  if (ms <= 0) return;
  await new Promise((resolve, reject) => {
    const t = setTimeout(() => resolve(), ms);
    if (signal) {
      const onAbort = () => {
        clearTimeout(t);
        reject(signal.reason || new DOMException("Aborted", "AbortError"));
      };
      if (signal.aborted) return onAbort();
      signal.addEventListener("abort", onAbort, { once: true });
    }
  });
}
function shouldRetry(status, req, attempt, maxRetries) {
  if (req.isWrite) return false;
  if (req.idempotent === false) return false;
  if (attempt >= maxRetries) return false;
  if (status === 401 || status === 403) return false;
  return status === 429 || status === 502 || status === 503 || status === 504;
}
async function datasourceHttp(req) {
  if (getBackendMode() === "offline" && !req.forceNetwork) {
    throw new DataSourceError(
      "OFFLINE",
      "Datasource HTTP disabled in offline mode"
    );
  }
  if (!req.baseUrl) {
    throw new DataSourceError("INVALID_RESPONSE", "Datasource URL is empty");
  }
  const url = joinUrl(req.baseUrl, req.path || "");
  if (req.query) {
    for (const [k, v] of Object.entries(req.query)) {
      if (v == null || v === "") continue;
      if (Array.isArray(v)) {
        for (const item of v) {
          if (item == null || item === "") continue;
          url.searchParams.append(k, String(item));
        }
      } else {
        url.searchParams.set(k, String(v));
      }
    }
  }
  let timeoutCtrl;
  let timer;
  let timedOut = false;
  if (req.timeoutMs && req.timeoutMs > 0) {
    timeoutCtrl = new AbortController();
    timer = setTimeout(() => {
      timedOut = true;
      timeoutCtrl.abort();
    }, req.timeoutMs);
  }
  const signal = mergeSignals$1(req.signal, timeoutCtrl?.signal);
  let cred = req.credential;
  if (cred === void 0 && req.uid) {
    cred = await getRuntimeCredential(req.uid);
  }
  const headers = applyCredentialHeaders(
    { Accept: "application/json", ...req.headers || {} },
    cred
  );
  const method = req.method || (req.body != null ? "POST" : "GET");
  let body;
  if (req.body != null && method !== "GET") {
    headers["Content-Type"] = headers["Content-Type"] || "application/json";
    body = JSON.stringify(req.body);
  }
  let finalMethod = method;
  let finalUrl = url;
  let finalBody = body;
  if (method === "GET" && url.toString().length > 2e3 && req.query) {
    finalMethod = "POST";
    finalUrl = joinUrl(req.baseUrl, req.path || "");
    headers["Content-Type"] = "application/x-www-form-urlencoded";
    const form = new URLSearchParams();
    for (const [k, v] of Object.entries(req.query)) {
      if (v == null || v === "") continue;
      if (Array.isArray(v)) {
        for (const item of v) {
          if (item == null || item === "") continue;
          form.append(k, String(item));
        }
      } else {
        form.append(k, String(v));
      }
    }
    finalBody = form.toString();
  }
  const started = Date.now();
  const logBase = {
    ts: started,
    uid: req.uid,
    method: finalMethod,
    url: redactUrl(finalUrl.toString()),
    bodyPreview: previewBody(finalBody)
  };
  const maxRetries = req.isWrite ? 0 : req.maxRetries ?? 1;
  let attempt = 0;
  try {
    while (true) {
      const client = getDatasourceHttpClient();
      const axiosRes = await client.request({
        url: finalUrl.toString(),
        method: finalMethod,
        headers,
        data: finalBody,
        signal,
        // omit cookies by default unless caller opts in
        withCredentials: req.credentials === "include" || req.credentials === "same-origin",
        responseType: "text",
        // timeout handled by outer timer + AbortSignal
        timeout: 0
      });
      const resHeaders = new NormalizedHeaders(axiosRes.headers);
      const headersOut = new Headers();
      resHeaders.forEach((v, k) => headersOut.set(k, v));
      const res = {
        ok: axiosRes.status >= 200 && axiosRes.status < 300,
        status: axiosRes.status,
        statusText: axiosRes.statusText || "",
        headers: headersOut,
        text: async () => typeof axiosRes.data === "string" ? axiosRes.data : axiosRes.data == null ? "" : String(axiosRes.data)
      };
      if (!res.ok) {
        if (shouldRetry(res.status, req, attempt, maxRetries)) {
          attempt += 1;
          let waitMs = res.status === 429 ? 1e3 : 250 * attempt;
          if (res.status === 429) {
            const ra = res.headers.get("Retry-After");
            if (ra) waitMs = Number(ra) < 100 ? Number(ra) * 1e3 : Number(ra);
          }
          await sleep(waitMs, signal);
          continue;
        }
        if (timer) clearTimeout(timer);
        pushHttpLog({
          ...logBase,
          status: res.status,
          durationMs: Date.now() - started,
          error: `HTTP ${res.status}`
        });
        if (res.status === 429) {
          const ra = res.headers.get("Retry-After");
          const retryAfterMs = ra ? Number(ra) < 100 ? Number(ra) * 1e3 : Number(ra) : void 0;
          throw new DataSourceError(
            "RATE_LIMITED",
            `Rate limited (${res.status})`,
            {
              status: res.status,
              url: finalUrl.toString(),
              retryAfterMs
            }
          );
        }
        throw DataSourceError.fromHttpStatus(
          res.status,
          res.statusText,
          finalUrl.toString()
        );
      }
      if (timer) clearTimeout(timer);
      if (res.status === 204) {
        pushHttpLog({
          ...logBase,
          status: 204,
          durationMs: Date.now() - started
        });
        return {
          data: null,
          status: 204,
          headers: res.headers,
          url: finalUrl.toString()
        };
      }
      const text = await res.text();
      const max = req.maxBodyBytes ?? 10485760;
      if (text.length > max) {
        pushHttpLog({
          ...logBase,
          status: res.status,
          durationMs: Date.now() - started,
          error: "response too large"
        });
        throw new DataSourceError(
          "INVALID_RESPONSE",
          `Response exceeds size limit (${max} bytes)`,
          {
            url: finalUrl.toString()
          }
        );
      }
      if (!text) {
        pushHttpLog({
          ...logBase,
          status: res.status,
          durationMs: Date.now() - started
        });
        return {
          data: null,
          status: res.status,
          headers: res.headers,
          url: finalUrl.toString()
        };
      }
      try {
        const data = JSON.parse(text);
        pushHttpLog({
          ...logBase,
          status: res.status,
          durationMs: Date.now() - started
        });
        return {
          data,
          status: res.status,
          headers: res.headers,
          url: finalUrl.toString()
        };
      } catch {
        pushHttpLog({
          ...logBase,
          status: res.status,
          durationMs: Date.now() - started,
          error: "invalid JSON"
        });
        throw new DataSourceError(
          "INVALID_RESPONSE",
          "Response is not valid JSON",
          {
            status: res.status,
            url: finalUrl.toString()
          }
        );
      }
    }
  } catch (e) {
    if (timer) clearTimeout(timer);
    if (timedOut) {
      const timeoutError = new DataSourceError(
        "TIMEOUT",
        `数据源请求在 ${req.timeoutMs}ms 后超时`,
        {
          url: finalUrl.toString()
        }
      );
      pushHttpLog({
        ...logBase,
        durationMs: Date.now() - started,
        error: timeoutError.message
      });
      throw timeoutError;
    }
    if (e instanceof DataSourceError) {
      if (!httpLog.some((x) => x.ts === started && x.uid === req.uid)) {
        pushHttpLog({
          ...logBase,
          durationMs: Date.now() - started,
          error: e.message
        });
      }
      throw e;
    }
    pushHttpLog({
      ...logBase,
      durationMs: Date.now() - started,
      error: e instanceof Error ? e.message : String(e)
    });
    throw DataSourceError.fromNetwork(e, finalUrl.toString());
  }
}
const __vite_glob_0_0 = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M11.29,12l3.54-3.54a1,1,0,0,0,0-1.41,1,1,0,0,0-1.42,0L9.17,11.29a1,1,0,0,0,0,1.42L13.41,17a1,1,0,0,0,.71.29,1,1,0,0,0,.71-.29,1,1,0,0,0,0-1.41Z"/></svg>';
const __vite_glob_0_1 = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M14.83,11.29,10.59,7.05a1,1,0,0,0-1.42,0,1,1,0,0,0,0,1.41L12.71,12,9.17,15.54a1,1,0,0,0,0,1.41,1,1,0,0,0,.71.29,1,1,0,0,0,.71-.29l4.24-4.24A1,1,0,0,0,14.83,11.29Z"/></svg>';
const __vite_glob_0_2 = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M10,13H3a1,1,0,0,0-1,1v7a1,1,0,0,0,1,1h7a1,1,0,0,0,1-1V14A1,1,0,0,0,10,13ZM9,20H4V15H9ZM21,2H14a1,1,0,0,0-1,1v7a1,1,0,0,0,1,1h7a1,1,0,0,0,1-1V3A1,1,0,0,0,21,2ZM20,9H15V4h5Zm1,4H14a1,1,0,0,0-1,1v7a1,1,0,0,0,1,1h7a1,1,0,0,0,1-1V14A1,1,0,0,0,21,13Zm-1,7H15V15h5ZM10,2H3A1,1,0,0,0,2,3v7a1,1,0,0,0,1,1h7a1,1,0,0,0,1-1V3A1,1,0,0,0,10,2ZM9,9H4V4H9Z"/></svg>';
const __vite_glob_0_3 = '<svg xmlns="http://www.w3.org/2000/svg" data-name="Layer 1" viewBox="0 0 24 24"><path d="M17,11H9.41l3.3-3.29a1,1,0,1,0-1.42-1.42l-5,5a1,1,0,0,0-.21.33,1,1,0,0,0,0,.76,1,1,0,0,0,.21.33l5,5a1,1,0,0,0,1.42,0,1,1,0,0,0,0-1.42L9.41,13H17a1,1,0,0,0,0-2Z"/></svg>';
const __vite_glob_0_4 = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M18.71,7.21a1,1,0,0,0-1.42,0L9.84,14.67,6.71,11.53A1,1,0,1,0,5.29,13l3.84,3.84a1,1,0,0,0,1.42,0l8.16-8.16A1,1,0,0,0,18.71,7.21Z"/></svg>';
const __vite_glob_0_5 = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M21.32,9.55l-1.89-.63.89-1.78A1,1,0,0,0,20.13,6L18,3.87a1,1,0,0,0-1.15-.19l-1.78.89-.63-1.89A1,1,0,0,0,13.5,2h-3a1,1,0,0,0-.95.68L8.92,4.57,7.14,3.68A1,1,0,0,0,6,3.87L3.87,6a1,1,0,0,0-.19,1.15l.89,1.78-1.89.63A1,1,0,0,0,2,10.5v3a1,1,0,0,0,.68.95l1.89.63-.89,1.78A1,1,0,0,0,3.87,18L6,20.13a1,1,0,0,0,1.15.19l1.78-.89.63,1.89a1,1,0,0,0,.95.68h3a1,1,0,0,0,.95-.68l.63-1.89,1.78.89A1,1,0,0,0,18,20.13L20.13,18a1,1,0,0,0,.19-1.15l-.89-1.78,1.89-.63A1,1,0,0,0,22,13.5v-3A1,1,0,0,0,21.32,9.55ZM20,12.78l-1.2.4A2,2,0,0,0,17.64,16l.57,1.14-1.1,1.1L16,17.64a2,2,0,0,0-2.79,1.16l-.4,1.2H11.22l-.4-1.2A2,2,0,0,0,8,17.64l-1.14.57-1.1-1.1L6.36,16A2,2,0,0,0,5.2,13.18L4,12.78V11.22l1.2-.4A2,2,0,0,0,6.36,8L5.79,6.89l1.1-1.1L8,6.36A2,2,0,0,0,10.82,5.2l.4-1.2h1.56l.4,1.2A2,2,0,0,0,16,6.36l1.14-.57,1.1,1.1L17.64,8a2,2,0,0,0,1.16,2.79l1.2.4ZM12,8a4,4,0,1,0,4,4A4,4,0,0,0,12,8Zm0,6a2,2,0,1,1,2-2A2,2,0,0,1,12,14Z"/></svg>';
const __vite_glob_0_6 = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M21,8.94a1.31,1.31,0,0,0-.06-.27l0-.09a1.07,1.07,0,0,0-.19-.28h0l-6-6h0a1.07,1.07,0,0,0-.28-.19.32.32,0,0,0-.09,0A.88.88,0,0,0,14.05,2H10A3,3,0,0,0,7,5V6H6A3,3,0,0,0,3,9V19a3,3,0,0,0,3,3h8a3,3,0,0,0,3-3V18h1a3,3,0,0,0,3-3V9S21,9,21,8.94ZM15,5.41,17.59,8H16a1,1,0,0,1-1-1ZM15,19a1,1,0,0,1-1,1H6a1,1,0,0,1-1-1V9A1,1,0,0,1,6,8H7v7a3,3,0,0,0,3,3h5Zm4-4a1,1,0,0,1-1,1H10a1,1,0,0,1-1-1V5a1,1,0,0,1,1-1h3V7a3,3,0,0,0,3,3h3Z"/></svg>';
const __vite_glob_0_7 = '<svg xmlns="http://www.w3.org/2000/svg" data-name="Layer 1" viewBox="0 0 24 24"><path d="M12,14a1,1,0,0,0,1-1V7a1,1,0,0,0-2,0v6A1,1,0,0,0,12,14Zm0,4a1.25,1.25,0,1,0-1.25-1.25A1.25,1.25,0,0,0,12,18Z"/></svg>';
const __vite_glob_0_8 = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M18,10.82a1,1,0,0,0-1,1V19a1,1,0,0,1-1,1H5a1,1,0,0,1-1-1V8A1,1,0,0,1,5,7h7.18a1,1,0,0,0,0-2H5A3,3,0,0,0,2,8V19a3,3,0,0,0,3,3H16a3,3,0,0,0,3-3V11.82A1,1,0,0,0,18,10.82Zm3.92-8.2a1,1,0,0,0-.54-.54A1,1,0,0,0,21,2H15a1,1,0,0,0,0,2h3.59L8.29,14.29a1,1,0,0,0,0,1.42,1,1,0,0,0,1.42,0L20,5.41V9a1,1,0,0,0,2,0V3A1,1,0,0,0,21.92,2.62Z"/></svg>';
const __vite_glob_0_9 = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M21.92,11.6C19.9,6.91,16.1,4,12,4S4.1,6.91,2.08,11.6a1,1,0,0,0,0,.8C4.1,17.09,7.9,20,12,20s7.9-2.91,9.92-7.6A1,1,0,0,0,21.92,11.6ZM12,18c-3.17,0-6.17-2.29-7.9-6C5.83,8.29,8.83,6,12,6s6.17,2.29,7.9,6C18.17,15.71,15.17,18,12,18ZM12,8a4,4,0,1,0,4,4A4,4,0,0,0,12,8Zm0,6a2,2,0,1,1,2-2A2,2,0,0,1,12,14Z"/></svg>';
const __vite_glob_0_10 = '<svg xmlns="http://www.w3.org/2000/svg" data-name="Layer 1" viewBox="0 0 24 24"><path d="M12,10a1,1,0,0,0-1,1v6a1,1,0,0,0,2,0V11A1,1,0,0,0,12,10Zm0-4a1.25,1.25,0,1,0,1.25,1.25A1.25,1.25,0,0,0,12,6Z"/></svg>';
const __vite_glob_0_11 = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12,7a2,2,0,1,0-2-2A2,2,0,0,0,12,7Zm0,10a2,2,0,1,0,2,2A2,2,0,0,0,12,17Zm0-7a2,2,0,1,0,2,2A2,2,0,0,0,12,10Z"/></svg>';
const __vite_glob_0_12 = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19,11H13V5a1,1,0,0,0-2,0v6H5a1,1,0,0,0,0,2h6v6a1,1,0,0,0,2,0V13h6a1,1,0,0,0,0-2Z"/></svg>';
const __vite_glob_0_13 = '<svg xmlns="http://www.w3.org/2000/svg" data-name="Layer 1" viewBox="0 0 24 24"><path d="M20.71,9.29l-6-6a1,1,0,0,0-.32-.21A1.09,1.09,0,0,0,14,3H6A3,3,0,0,0,3,6V18a3,3,0,0,0,3,3H18a3,3,0,0,0,3-3V10A1,1,0,0,0,20.71,9.29ZM9,5h4V7H9Zm6,14H9V16a1,1,0,0,1,1-1h4a1,1,0,0,1,1,1Zm4-1a1,1,0,0,1-1,1H17V16a3,3,0,0,0-3-3H10a3,3,0,0,0-3,3v3H6a1,1,0,0,1-1-1V6A1,1,0,0,1,6,5H7V8A1,1,0,0,0,8,9h6a1,1,0,0,0,1-1V6.41l4,4Z"/></svg>';
const __vite_glob_0_14 = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M21.71,20.29,18,16.61A9,9,0,1,0,16.61,18l3.68,3.68a1,1,0,0,0,1.42,0A1,1,0,0,0,21.71,20.29ZM11,18a7,7,0,1,1,7-7A7,7,0,0,1,11,18Z"/></svg>';
const __vite_glob_0_15 = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20.28,3.43a3.23,3.23,0,0,0-3.29,0L8,8.84V6A3,3,0,0,0,2,6V18a3,3,0,0,0,6,0V15.16l9,5.37a3.28,3.28,0,0,0,1.68.47,3.24,3.24,0,0,0,1.61-.43,3.38,3.38,0,0,0,1.72-3V6.42A3.38,3.38,0,0,0,20.28,3.43ZM6,18a1,1,0,0,1-2,0V6A1,1,0,0,1,6,6Zm14-.42a1.4,1.4,0,0,1-.71,1.25,1.23,1.23,0,0,1-1.28,0L8.68,13.23a1.45,1.45,0,0,1,0-2.46L18,5.19A1.23,1.23,0,0,1,18.67,5a1.29,1.29,0,0,1,.62.17A1.4,1.4,0,0,1,20,6.42Z"/></svg>';
const __vite_glob_0_16 = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19.91,15.51H15.38a1,1,0,0,0,0,2h2.4A8,8,0,0,1,4,12a1,1,0,0,0-2,0,10,10,0,0,0,16.88,7.23V21a1,1,0,0,0,2,0V16.5A1,1,0,0,0,19.91,15.51ZM12,2A10,10,0,0,0,5.12,4.77V3a1,1,0,0,0-2,0V7.5a1,1,0,0,0,1,1h4.5a1,1,0,0,0,0-2H6.22A8,8,0,0,1,20,12a1,1,0,0,0,2,0A10,10,0,0,0,12,2Z"/></svg>';
const __vite_glob_0_17 = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M13.41,12l4.3-4.29a1,1,0,1,0-1.42-1.42L12,10.59,7.71,6.29A1,1,0,0,0,6.29,7.71L10.59,12l-4.3,4.29a1,1,0,0,0,0,1.42,1,1,0,0,0,1.42,0L12,13.41l4.29,4.3a1,1,0,0,0,1.42,0,1,1,0,0,0,0-1.42Z"/></svg>';
const __vite_glob_0_18 = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20,6H16V5a3,3,0,0,0-3-3H11A3,3,0,0,0,8,5V6H4A1,1,0,0,0,4,8H5V19a3,3,0,0,0,3,3h8a3,3,0,0,0,3-3V8h1a1,1,0,0,0,0-2ZM10,5a1,1,0,0,1,1-1h2a1,1,0,0,1,1,1V6H10Zm7,14a1,1,0,0,1-1,1H8a1,1,0,0,1-1-1V8H17Z"/></svg>';
const registry = /* @__PURE__ */ new Map();
const modules = /* @__PURE__ */ Object.assign({
  "./assets/angle-left.svg": __vite_glob_0_0,
  "./assets/angle-right.svg": __vite_glob_0_1,
  "./assets/apps.svg": __vite_glob_0_2,
  "./assets/arrow-left.svg": __vite_glob_0_3,
  "./assets/check.svg": __vite_glob_0_4,
  "./assets/cog.svg": __vite_glob_0_5,
  "./assets/copy.svg": __vite_glob_0_6,
  "./assets/exclamation-triangle.svg": __vite_glob_0_7,
  "./assets/external-link-alt.svg": __vite_glob_0_8,
  "./assets/eye.svg": __vite_glob_0_9,
  "./assets/info.svg": __vite_glob_0_10,
  "./assets/more.svg": __vite_glob_0_11,
  "./assets/plus.svg": __vite_glob_0_12,
  "./assets/save.svg": __vite_glob_0_13,
  "./assets/search.svg": __vite_glob_0_14,
  "./assets/step-backward.svg": __vite_glob_0_15,
  "./assets/sync.svg": __vite_glob_0_16,
  "./assets/times.svg": __vite_glob_0_17,
  "./assets/trash.svg": __vite_glob_0_18
});
function parseSvg(svg) {
  const viewBoxMatch = svg.match(/viewBox="([^"]+)"/i);
  const viewBox = viewBoxMatch?.[1] ?? "0 0 24 24";
  const inner = svg.replace(/^[\s\S]*?<svg[^>]*>/i, "").replace(/<\/svg>\s*$/i, "");
  return { viewBox, body: inner.trim() };
}
for (const [path, svg] of Object.entries(modules)) {
  const file = path.split("/").pop().replace(/\.svg$/, "");
  const parsed = parseSvg(svg);
  registry.set(file, {
    name: file,
    svg,
    viewBox: parsed.viewBox,
    body: parsed.body
  });
}
const ALIASES$1 = {
  setting: "cog",
  settings: "cog",
  trash: "trash",
  "trash-alt": "trash",
  inspect: "search",
  share: "share-alt",
  "share-alt": "copy",
  // fallback if share missing
  more: "more",
  ellipsis: "more",
  "info-circle": "info",
  "exclamation-triangle": "exclamation-triangle",
  warning: "exclamation-triangle",
  fullscreen: "apps",
  expand: "apps",
  "expand-arrows": "apps",
  pen: "cog",
  edit: "cog",
  times: "times",
  close: "times",
  question: "info",
  dashboard: "apps",
  database: "apps",
  clock: "info",
  "clock-circle": "info",
  bell: "info",
  link: "copy",
  camera: "eye",
  "check-circle": "check",
  "step-backward": "times",
  // temporary until asset; LiveRenderer uses path via GIcon name
  "fullscreen-exit": "apps"
};
function registerIcon(def) {
  registry.set(def.name, def);
}
function resolveIconName(name) {
  if (registry.has(name)) return name;
  if (ALIASES$1[name] && registry.has(ALIASES$1[name])) return ALIASES$1[name];
  if (ALIASES$1[name]) return ALIASES$1[name];
  return name;
}
function getIcon(name, { strict = false } = {}) {
  const resolved = resolveIconName(name);
  const hit = registry.get(resolved) ?? registry.get(name);
  if (!hit && strict) {
    throw new Error(`unknown icon: ${name}`);
  }
  return hit;
}
registerIcon({
  name: "step-backward",
  viewBox: "0 0 24 24",
  body: '<path d="M20.28,3.43a3.23,3.23,0,0,0-3.29,0L8,8.84V6A3,3,0,0,0,2,6V18a3,3,0,0,0,6,0V15.16l9,5.37a3.28,3.28,0,0,0,1.68.47,3.24,3.24,0,0,0,1.61-.43,3.38,3.38,0,0,0,1.72-3V6.42A3.38,3.38,0,0,0,20.28,3.43ZM6,18a1,1,0,0,1-2,0V6A1,1,0,0,1,6,6Zm14-.42a1.4,1.4,0,0,1-.71,1.25,1.23,1.23,0,0,1-1.28,0L8.68,13.23a1.45,1.45,0,0,1,0-2.46L18,5.19A1.23,1.23,0,0,1,18.67,5a1.29,1.29,0,0,1,.62.17A1.4,1.4,0,0,1,20,6.42Z"/>'
});
for (const name of [
  "cog",
  "trash",
  "copy",
  "search",
  "plus",
  "save",
  "sync",
  "eye",
  "info",
  "check",
  "times",
  "more"
]) {
  if (!registry.has(name)) {
    registerIcon({ name, viewBox: "0 0 24 24", body: "" });
  }
}
const _sfc_main$1e = /* @__PURE__ */ defineComponent({
  __name: "GButton",
  props: {
    variant: { default: "secondary" },
    size: { default: "md" },
    disabled: { type: Boolean },
    loading: { type: Boolean },
    htmlType: { default: "button" },
    testId: {}
  },
  setup(__props) {
    const props = __props;
    const type = computed(() => {
      if (props.variant === "primary") return "primary";
      if (props.variant === "destructive") return "primary";
      if (props.variant === "text") return "text";
      return "default";
    });
    const danger = computed(() => props.variant === "destructive");
    const size = computed(
      () => props.size === "sm" ? "small" : props.size === "lg" ? "large" : "middle"
    );
    return (_ctx, _cache) => {
      return openBlock(), createBlock(unref(Button), {
        type: type.value,
        danger: danger.value,
        size: size.value,
        disabled: __props.disabled,
        loading: __props.loading,
        "html-type": __props.htmlType,
        "data-testid": __props.testId,
        class: "g-button"
      }, {
        default: withCtx(() => [
          renderSlot(_ctx.$slots, "default", {}, void 0, true)
        ]),
        _: 3
        /* FORWARDED */
      }, 8, ["type", "danger", "size", "disabled", "loading", "html-type", "data-testid"]);
    };
  }
});
const GButton = /* @__PURE__ */ _export_sfc(_sfc_main$1e, [["__scopeId", "data-v-087259e6"]]);
const _sfc_main$1d = /* @__PURE__ */ defineComponent({
  __name: "GSelect",
  props: {
    value: {},
    options: {},
    placeholder: {},
    disabled: { type: Boolean },
    allowClear: { type: Boolean },
    mode: {},
    testId: {},
    ariaLabel: {},
    showSearch: { type: Boolean, default: true },
    size: { default: "middle" },
    filterOption: { type: [Boolean, Function] },
    virtual: { type: Boolean, default: true }
  },
  emits: ["update:value", "change"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const mode2 = computed(() => props.mode);
    function defaultFilterOption(input, option) {
      const q = String(input ?? "").trim().toLowerCase();
      if (!q) return true;
      const label = String(option?.label ?? option?.children ?? "").toLowerCase();
      const value = String(option?.value ?? "").toLowerCase();
      return label.includes(q) || value.includes(q);
    }
    const resolvedFilterOption = computed(() => {
      if (props.filterOption === void 0) return defaultFilterOption;
      return props.filterOption;
    });
    function onUpdate(v) {
      emit("update:value", v);
      emit("change", v);
    }
    return (_ctx, _cache) => {
      return openBlock(), createBlock(unref(Select), {
        class: "g-select",
        value: __props.value,
        options: __props.options ?? [],
        placeholder: __props.placeholder || "请选择",
        disabled: __props.disabled,
        "allow-clear": __props.allowClear,
        mode: mode2.value,
        "show-search": __props.showSearch,
        size: __props.size,
        "option-filter-prop": "label",
        "filter-option": resolvedFilterOption.value,
        "data-testid": __props.testId,
        "aria-label": __props.ariaLabel || __props.placeholder || "Select",
        style: { "width": "100%" },
        "popup-class-name": "g-select-dropdown",
        virtual: __props.virtual,
        "onUpdate:value": onUpdate
      }, null, 8, ["value", "options", "placeholder", "disabled", "allow-clear", "mode", "show-search", "size", "filter-option", "data-testid", "aria-label", "virtual"]);
    };
  }
});
const GSelect = /* @__PURE__ */ _export_sfc(_sfc_main$1d, [["__scopeId", "data-v-75041926"]]);
const _sfc_main$1c = /* @__PURE__ */ defineComponent({
  __name: "GForm",
  props: {
    layout: {},
    model: {},
    testId: {}
  },
  emits: ["finish", "finishFailed"],
  setup(__props, { emit: __emit }) {
    const emit = __emit;
    return (_ctx, _cache) => {
      return openBlock(), createBlock(unref(Form), {
        layout: __props.layout ?? "vertical",
        model: __props.model,
        "data-testid": __props.testId,
        onFinish: _cache[0] || (_cache[0] = ($event) => emit("finish", $event)),
        onFinishFailed: _cache[1] || (_cache[1] = ($event) => emit("finishFailed", $event))
      }, {
        default: withCtx(() => [
          renderSlot(_ctx.$slots, "default")
        ]),
        _: 3
        /* FORWARDED */
      }, 8, ["layout", "model", "data-testid"]);
    };
  }
});
const _hoisted_1$13 = ["viewBox", "width", "height", "aria-hidden", "role", "aria-label", "data-icon-name", "innerHTML"];
const _hoisted_2$Q = ["title"];
const _sfc_main$1b = /* @__PURE__ */ defineComponent({
  __name: "GIcon",
  props: {
    name: {},
    size: { default: 16 },
    color: {},
    title: {},
    spin: { type: Boolean, default: false },
    strict: { type: Boolean, default: false }
  },
  setup(__props) {
    const props = __props;
    const icon = computed(() => getIcon(props.name, { strict: props.strict }));
    const px = computed(
      () => typeof props.size === "number" ? `${props.size}px` : props.size
    );
    return (_ctx, _cache) => {
      return icon.value ? (openBlock(), createElementBlock("svg", {
        key: 0,
        class: normalizeClass(["g-icon", { "is-spin": __props.spin }]),
        viewBox: icon.value.viewBox || "0 0 24 24",
        width: px.value,
        height: px.value,
        "aria-hidden": __props.title ? void 0 : "true",
        role: __props.title ? "img" : void 0,
        "aria-label": __props.title,
        style: normalizeStyle({ color: __props.color }),
        "data-testid": "g-icon",
        "data-icon-name": __props.name,
        innerHTML: icon.value.body || ""
      }, null, 14, _hoisted_1$13)) : !__props.strict ? (openBlock(), createElementBlock("span", {
        key: 1,
        class: "g-icon-missing",
        title: __props.name,
        "data-testid": "g-icon-missing"
      }, "?", 8, _hoisted_2$Q)) : createCommentVNode("v-if", true);
    };
  }
});
const GIcon = /* @__PURE__ */ _export_sfc(_sfc_main$1b, [["__scopeId", "data-v-eaa1ba73"]]);
const _sfc_main$1a = /* @__PURE__ */ defineComponent({
  ...{ inheritAttrs: false },
  __name: "GInput",
  props: {
    value: {},
    modelValue: {},
    placeholder: {},
    type: { default: "text" },
    disabled: { type: Boolean },
    testId: {}
  },
  emits: ["update:value", "update:modelValue", "focus", "blur"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const attrs = useAttrs();
    const current = computed(
      () => props.modelValue !== void 0 ? props.modelValue : props.value
    );
    const resolvedTestId = computed(
      () => props.testId ?? attrs["data-testid"]
    );
    function onUpdate(v) {
      emit("update:value", v);
      emit("update:modelValue", v);
    }
    return (_ctx, _cache) => {
      return openBlock(), createBlock(unref(Input), mergeProps(unref(attrs), {
        value: current.value,
        placeholder: __props.placeholder,
        type: __props.type,
        disabled: __props.disabled,
        "data-testid": resolvedTestId.value,
        "onUpdate:value": onUpdate,
        onFocus: _cache[0] || (_cache[0] = ($event) => emit("focus", $event)),
        onBlur: _cache[1] || (_cache[1] = ($event) => emit("blur", $event))
      }), null, 16, ["value", "placeholder", "type", "disabled", "data-testid"]);
    };
  }
});
const GInput = /* @__PURE__ */ _export_sfc(_sfc_main$1a, [["__scopeId", "data-v-b06821cd"]]);
const _sfc_main$19 = /* @__PURE__ */ defineComponent({
  __name: "GSwitch",
  props: {
    checked: { type: Boolean },
    disabled: { type: Boolean },
    testId: {}
  },
  emits: ["update:checked"],
  setup(__props, { emit: __emit }) {
    const emit = __emit;
    function onChange(v) {
      emit("update:checked", !!v);
    }
    return (_ctx, _cache) => {
      return openBlock(), createBlock(unref(Switch), {
        style: { width: "46px" },
        checked: __props.checked,
        disabled: __props.disabled,
        "data-testid": __props.testId,
        "onUpdate:checked": onChange
      }, null, 8, ["checked", "disabled", "data-testid"]);
    };
  }
});
const _sfc_main$18 = /* @__PURE__ */ defineComponent({
  __name: "GTooltip",
  props: {
    title: {}
  },
  setup(__props) {
    return (_ctx, _cache) => {
      return openBlock(), createBlock(unref(Tooltip), { title: __props.title }, {
        default: withCtx(() => [
          renderSlot(_ctx.$slots, "default")
        ]),
        _: 3
        /* FORWARDED */
      }, 8, ["title"]);
    };
  }
});
const _hoisted_1$12 = ["data-testid"];
const _hoisted_2$P = ["value", "readonly"];
const _sfc_main$17 = /* @__PURE__ */ defineComponent({
  __name: "GCodeEditor",
  props: {
    value: { default: "" },
    language: { default: "plaintext" },
    height: { default: 160 },
    readOnly: { type: Boolean, default: false },
    testId: {}
  },
  emits: ["update:value", "change"],
  setup(__props, { emit: __emit }) {
    function getDocumentThemeMode() {
      if (typeof document === "undefined") return "dark";
      const mode2 = document.documentElement.dataset.theme || document.body?.dataset.theme || "";
      return mode2 === "light" ? "light" : "dark";
    }
    function monacoThemeForMode(mode2) {
      return mode2 === "light" ? "vs" : "vs-dark";
    }
    const props = __props;
    const emit = __emit;
    const host = ref(null);
    const failed = ref(false);
    let editor = null;
    let monaco = null;
    let themeObserver = null;
    async function ensureMonaco() {
      if (monaco) return monaco;
      const mod = await import("monaco-editor");
      monaco = mod.default ?? mod;
      if (typeof Worker !== "undefined") {
        try {
          globalThis.MonacoEnvironment = {
            getWorker(_, _label) {
              return new Worker(
                new URL(
                  /* @vite-ignore */
                  "/assets/editor.worker-BhziHrDZ.js",
                  import.meta.url
                ),
                {
                  type: "module"
                }
              );
            }
          };
        } catch {
        }
      }
      try {
        registerLanguages(monaco);
      } catch {
      }
      return monaco;
    }
    function registerLanguages(m) {
      if (!(m.languages.getLanguages() || []).some((l) => l.id === "promql")) {
        m.languages.register({ id: "promql" });
        m.languages.setMonarchTokensProvider("promql", {
          tokenizer: {
            root: [
              [/#.*$/, "comment"],
              [
                /\b(sum|rate|irate|avg|min|max|count|topk|bottomk|histogram_quantile|increase|delta)\b/,
                "keyword"
              ],
              [/[{}=!,]/, "delimiter"],
              [/"([^"\\]|\\.)*"/, "string"],
              [/'([^'\\]|\\.)*'/, "string"],
              [/[0-9]+(\.[0-9]+)?/, "number"],
              [/[a-zA-Z_:][a-zA-Z0-9_:]*/, "identifier"]
            ]
          }
        });
      }
      if (!(m.languages.getLanguages() || []).some((l) => l.id === "logql")) {
        m.languages.register({ id: "logql" });
        m.languages.setMonarchTokensProvider("logql", {
          tokenizer: {
            root: [
              [/#.*$/, "comment"],
              [
                /\b(rate|count_over_time|sum|avg|max|min|unwrap|json|logfmt|line_format|label_format)\b/,
                "keyword"
              ],
              [/[{}=!~|]/, "delimiter"],
              [/"([^"\\]|\\.)*"/, "string"],
              [/`([^`\\]|\\.)*`/, "string"],
              [/[0-9]+(\.[0-9]+)?/, "number"],
              [/[a-zA-Z_][a-zA-Z0-9_]*/, "identifier"]
            ]
          }
        });
      }
      if (!(m.languages.getLanguages() || []).some((l) => l.id === "sql")) {
        m.languages.register({ id: "sql" });
        m.languages.setMonarchTokensProvider("sql", {
          tokenizer: {
            root: [
              [/--.*$/, "comment"],
              [
                /\b(SELECT|FROM|WHERE|GROUP|BY|ORDER|LIMIT|AS|AND|OR|JOIN|ON|INNER|LEFT|RIGHT|INSERT|UPDATE|DELETE|WITH)\b/i,
                "keyword"
              ],
              [/'([^'\\]|\\.)*'/, "string"],
              [/[0-9]+(\.[0-9]+)?/, "number"],
              [/[a-zA-Z_][a-zA-Z0-9_]*/, "identifier"]
            ]
          }
        });
      }
    }
    onMounted(async () => {
      if (!host.value) return;
      try {
        const m = await ensureMonaco();
        const mode2 = getDocumentThemeMode();
        editor = m.editor.create(host.value, {
          value: props.value,
          language: props.language,
          theme: monacoThemeForMode(mode2),
          minimap: { enabled: false },
          automaticLayout: true,
          fontSize: 12,
          lineNumbers: "on",
          scrollBeyondLastLine: false,
          wordWrap: "on",
          readOnly: props.readOnly,
          tabSize: 2
        });
        editor.onDidChangeModelContent(() => {
          const v = editor?.getValue() ?? "";
          emit("update:value", v);
          emit("change", v);
        });
        themeObserver = new MutationObserver(() => {
          if (!editor || !monaco) return;
          monaco.editor.setTheme(monacoThemeForMode(getDocumentThemeMode()));
        });
        themeObserver.observe(document.documentElement, {
          attributes: true,
          attributeFilter: ["data-theme", "class"]
        });
      } catch {
        failed.value = true;
      }
    });
    watch(
      () => props.value,
      (v) => {
        if (editor && editor.getValue() !== v) editor.setValue(v ?? "");
      }
    );
    watch(
      () => props.language,
      (lang) => {
        if (editor && monaco) {
          const model = editor.getModel();
          if (model) monaco.editor.setModelLanguage(model, lang || "plaintext");
        }
      }
    );
    onBeforeUnmount(() => {
      themeObserver?.disconnect();
      themeObserver = null;
      editor?.dispose();
      editor = null;
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", {
        class: "g-code-editor",
        "data-testid": __props.testId || "code-editor",
        style: normalizeStyle({ height: typeof __props.height === "number" ? __props.height + "px" : __props.height })
      }, [
        withDirectives(createElementVNode(
          "div",
          {
            ref_key: "host",
            ref: host,
            class: "g-code-editor__monaco"
          },
          null,
          512
          /* NEED_PATCH */
        ), [
          [vShow, !failed.value]
        ]),
        failed.value ? (openBlock(), createElementBlock("textarea", {
          key: 0,
          class: "g-code-editor__fallback",
          value: __props.value,
          readonly: __props.readOnly,
          "data-testid": "code-editor-fallback",
          onInput: _cache[0] || (_cache[0] = ($event) => {
            emit("update:value", $event.target.value);
            emit("change", $event.target.value);
          })
        }, null, 40, _hoisted_2$P)) : createCommentVNode("v-if", true)
      ], 12, _hoisted_1$12);
    };
  }
});
const GCodeEditor = /* @__PURE__ */ _export_sfc(_sfc_main$17, [["__scopeId", "data-v-9304afbe"]]);
const _hoisted_1$11 = {
  key: 0,
  class: "req"
};
const _hoisted_2$O = ["title"];
const _hoisted_3$G = { class: "g-inline-field__control" };
const _sfc_main$16 = /* @__PURE__ */ defineComponent({
  __name: "GInlineField",
  props: {
    label: {},
    labelWidth: { default: 12 },
    tooltip: {},
    grow: { type: Boolean, default: false },
    disabled: { type: Boolean },
    required: { type: Boolean }
  },
  setup(__props) {
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock(
        "div",
        {
          class: normalizeClass(["g-inline-field", { grow: __props.grow, disabled: __props.disabled }]),
          "data-testid": "g-inline-field"
        },
        [
          __props.label ? (openBlock(), createElementBlock(
            "label",
            {
              key: 0,
              class: "g-inline-field__label",
              style: normalizeStyle({ width: __props.labelWidth * 8 + "px" })
            },
            [
              createTextVNode(
                toDisplayString(__props.label),
                1
                /* TEXT */
              ),
              __props.required ? (openBlock(), createElementBlock("span", _hoisted_1$11, "*")) : createCommentVNode("v-if", true),
              __props.tooltip ? (openBlock(), createElementBlock("span", {
                key: 1,
                class: "tip",
                title: __props.tooltip
              }, "?", 8, _hoisted_2$O)) : createCommentVNode("v-if", true)
            ],
            4
            /* STYLE */
          )) : createCommentVNode("v-if", true),
          createElementVNode("div", _hoisted_3$G, [
            renderSlot(_ctx.$slots, "default", {}, void 0, true)
          ])
        ],
        2
        /* CLASS */
      );
    };
  }
});
const GInlineField = /* @__PURE__ */ _export_sfc(_sfc_main$16, [["__scopeId", "data-v-e9723eaf"]]);
const _hoisted_1$10 = { class: "g-alert__body" };
const _hoisted_2$N = {
  key: 0,
  class: "g-alert__title"
};
const _hoisted_3$F = { class: "g-alert__content" };
const _sfc_main$15 = /* @__PURE__ */ defineComponent({
  __name: "GAlert",
  props: {
    title: {},
    severity: { default: "info" },
    closable: { type: Boolean, default: false }
  },
  emits: ["close"],
  setup(__props, { emit: __emit }) {
    const emit = __emit;
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock(
        "div",
        {
          class: normalizeClass(["g-alert", "is-" + __props.severity]),
          "data-testid": "g-alert",
          role: "alert"
        },
        [
          createElementVNode("div", _hoisted_1$10, [
            __props.title ? (openBlock(), createElementBlock(
              "div",
              _hoisted_2$N,
              toDisplayString(__props.title),
              1
              /* TEXT */
            )) : createCommentVNode("v-if", true),
            createElementVNode("div", _hoisted_3$F, [
              renderSlot(_ctx.$slots, "default", {}, void 0, true)
            ])
          ]),
          __props.closable ? (openBlock(), createElementBlock("button", {
            key: 0,
            type: "button",
            class: "g-alert__close",
            "aria-label": "close",
            onClick: _cache[0] || (_cache[0] = ($event) => emit("close"))
          }, " × ")) : createCommentVNode("v-if", true)
        ],
        2
        /* CLASS */
      );
    };
  }
});
const GAlert = /* @__PURE__ */ _export_sfc(_sfc_main$15, [["__scopeId", "data-v-3dfe15aa"]]);
function registerBuiltinPanels() {
}
async function registerGeomapPanel() {
  const mod = await Promise.resolve().then(() => module$5);
  if (mod.plugin) {
    const { registerPanelPlugin: registerPanelPlugin2 } = await Promise.resolve().then(() => index$1);
    registerPanelPlugin2(mod.plugin);
  }
}
const register$2 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
  __proto__: null,
  registerBuiltinPanels,
  registerGeomapPanel
}, Symbol.toStringTag, { value: "Module" }));
const ALIASES = {
  prometheus: "prometheus",
  prom: "prometheus",
  loki: "loki",
  mysql: "mysql",
  mssql: "mssql",
  postgres: "grafana-postgresql-datasource",
  postgresql: "grafana-postgresql-datasource",
  "grafana-postgresql-datasource": "grafana-postgresql-datasource",
  influxdb: "influxdb",
  influx: "influxdb",
  graphite: "graphite",
  cloudwatch: "cloudwatch",
  "cloud-watch": "cloudwatch",
  "grafana-testdata-datasource": "grafana-testdata-datasource",
  testdata: "grafana-testdata-datasource",
  testData: "grafana-testdata-datasource",
  elasticsearch: "elasticsearch",
  "grafana-elasticsearch-datasource": "elasticsearch",
  tempo: "tempo",
  opentelemetry: "opentelemetry",
  otel: "opentelemetry",
  signoz: "signoz",
  "alexanderzobnin-zabbix-datasource": "alexanderzobnin-zabbix-datasource",
  zabbix: "alexanderzobnin-zabbix-datasource",
  jaeger: "jaeger",
  "grafana-pyroscope-datasource": "grafana-pyroscope-datasource",
  pyroscope: "grafana-pyroscope-datasource",
  "grafana-azure-monitor-datasource": "grafana-azure-monitor-datasource",
  "azure-monitor": "grafana-azure-monitor-datasource",
  azuremonitor: "grafana-azure-monitor-datasource",
  grafana: "grafana",
  dashboard: "dashboard",
  mixed: "mixed",
  "-- Mixed --": "mixed",
  alertmanager: "alertmanager"
};
function normalizeDsType(type) {
  const raw = String(type ?? "").trim();
  if (!raw) return "";
  if (ALIASES[raw]) return ALIASES[raw];
  const lower = raw.toLowerCase();
  if (ALIASES[lower]) return ALIASES[lower];
  if (lower.includes("postgres")) return "grafana-postgresql-datasource";
  if (lower.includes("prometheus")) return "prometheus";
  if (lower.includes("loki")) return "loki";
  if (lower.includes("elastic")) return "elasticsearch";
  if (lower.includes("opentelemetry") || lower === "otel")
    return "opentelemetry";
  if (lower.includes("signoz")) return "signoz";
  if (lower.includes("zabbix")) return "alexanderzobnin-zabbix-datasource";
  if (lower.includes("pyroscope")) return "grafana-pyroscope-datasource";
  if (lower.includes("azure")) return "grafana-azure-monitor-datasource";
  if (lower.includes("testdata") || lower.includes("test-data"))
    return "grafana-testdata-datasource";
  return raw;
}
function queryFieldFamily(type) {
  const t = normalizeDsType(type);
  switch (t) {
    case "prometheus":
      return "prometheus";
    case "loki":
      return "loki";
    case "mysql":
    case "mssql":
    case "grafana-postgresql-datasource":
      return "sql";
    case "influxdb":
      return "influxdb";
    case "graphite":
      return "graphite";
    case "cloudwatch":
      return "cloudwatch";
    case "grafana-testdata-datasource":
      return "testdata";
    case "elasticsearch":
      return "elasticsearch";
    case "tempo":
      return "tempo";
    case "jaeger":
      return "jaeger";
    case "grafana-pyroscope-datasource":
      return "pyroscope";
    case "grafana-azure-monitor-datasource":
      return "azure";
    case "grafana":
      return "grafana";
    case "dashboard":
      return "dashboard";
    case "mixed":
      return "mixed";
    case "alertmanager":
      return "alertmanager";
    case "alexanderzobnin-zabbix-datasource":
      return "zabbix";
    case "opentelemetry":
      return "opentelemetry";
    case "signoz":
      return "signoz";
    default:
      return "generic";
  }
}
const DS_TYPE_LABELS = {
  prometheus: "Prometheus",
  loki: "Loki",
  mysql: "MySQL",
  mssql: "MSSQL",
  "grafana-postgresql-datasource": "PostgreSQL",
  influxdb: "InfluxDB",
  graphite: "Graphite",
  cloudwatch: "CloudWatch",
  "grafana-testdata-datasource": "TestData",
  elasticsearch: "Elasticsearch",
  tempo: "Tempo",
  opentelemetry: "OpenTelemetry",
  signoz: "SigNoz",
  "alexanderzobnin-zabbix-datasource": "Zabbix",
  jaeger: "Jaeger",
  "grafana-pyroscope-datasource": "Pyroscope",
  "grafana-azure-monitor-datasource": "Azure Monitor",
  grafana: "Grafana",
  dashboard: "Dashboard",
  mixed: "Mixed",
  alertmanager: "Alertmanager"
};
function dsTypeLabel(type) {
  const t = normalizeDsType(type);
  return DS_TYPE_LABELS[t] || t || "未知";
}
function dsTypeBadge(type) {
  const t = normalizeDsType(type);
  const map = {
    prometheus: "Prom",
    loki: "Loki",
    mysql: "MySQL",
    mssql: "MSSQL",
    "grafana-postgresql-datasource": "PG",
    influxdb: "Influx",
    graphite: "Graphite",
    cloudwatch: "CW",
    "grafana-testdata-datasource": "Test",
    elasticsearch: "ES",
    tempo: "Tempo",
    opentelemetry: "OTel",
    signoz: "SigNoz",
    "alexanderzobnin-zabbix-datasource": "Zabbix",
    jaeger: "Jaeger",
    "grafana-pyroscope-datasource": "Prof",
    "grafana-azure-monitor-datasource": "Azure",
    grafana: "Graf",
    dashboard: "Dash",
    mixed: "Mixed",
    alertmanager: "AM"
  };
  return map[t] || (t ? t.slice(0, 6) : "?");
}
function buildDurationLiteralWithSameLength(len) {
  const L = Math.max(0, Math.floor(len));
  if (L <= 1) return "1".repeat(L);
  return `${"1".repeat(L - 1)}s`;
}
function sanitizePromqlForLezer(expr) {
  const s = String(expr ?? "");
  let out = "";
  let i = 0;
  let inString = false;
  while (i < s.length) {
    const ch = s[i];
    if (inString) {
      out += ch;
      if (ch === "\\" && i + 1 < s.length) {
        out += s[i + 1];
        i += 2;
        continue;
      }
      if (ch === '"') inString = false;
      i++;
      continue;
    }
    if (ch === '"') {
      inString = true;
      out += ch;
      i++;
      continue;
    }
    if (ch === "[") {
      const start = i;
      i++;
      let inner = "";
      while (i < s.length && s[i] !== "]") {
        inner += s[i];
        i++;
      }
      if (i < s.length && s[i] === "]") {
        const replacedInner = inner.replace(
          /\$__[\w]+|\$\{__[\w]+\}|\[\[__[\w]+\]\]/g,
          (m) => buildDurationLiteralWithSameLength(m.length)
        );
        out += "[" + replacedInner + "]";
        i++;
        continue;
      }
      out += s.slice(start);
      break;
    }
    out += ch;
    i++;
  }
  return out.replace(
    /\boffset\s+\$__[\w]+/g,
    (m) => m.replace(/\$__[\w]+/, (v) => buildDurationLiteralWithSameLength(v.length))
  );
}
function collectLezerErrors(tree) {
  const out = [];
  const cursor = tree.cursor();
  do {
    if (cursor.type.isError) {
      out.push({
        severity: "error",
        message: "PromQL 语法错误（parser 发现无法解析的片段）",
        range: { from: cursor.from, to: cursor.to }
      });
    }
  } while (cursor.next());
  out.sort((a, b) => (a.range?.from ?? 0) - (b.range?.from ?? 0));
  const merged = [];
  for (const d of out) {
    const last = merged[merged.length - 1];
    if (last?.range && d.range && d.range.from <= last.range.to) {
      last.range = {
        from: last.range.from,
        to: Math.max(last.range.to, d.range.to)
      };
      continue;
    }
    merged.push(d);
  }
  return merged;
}
function parsePromqlToAst(expr) {
  const raw = String(expr ?? "");
  if (!raw.trim()) {
    return { ok: true, ast: parser.parse(""), diagnostics: [] };
  }
  const text = sanitizePromqlForLezer(raw);
  const ast = parser.parse(text);
  const diagnostics = collectLezerErrors(ast);
  const ok2 = diagnostics.every((d) => d.severity !== "error");
  return ok2 ? { ok: true, ast, diagnostics } : { ok: false, ast, diagnostics };
}
function isValidPromql(expr) {
  return parsePromqlToAst(expr).ok;
}
function isDsQueryWireResponse(raw) {
  if (!raw || typeof raw !== "object") return false;
  const r = raw;
  if (r.results == null) return false;
  if (typeof r.results !== "object") return false;
  return true;
}
function assertDsQueryWireShape(raw) {
  if (!isDsQueryWireResponse(raw)) {
    throw new Error("Invalid /api/ds/query response: missing results map");
  }
  for (const [refId, result] of Object.entries(raw.results ?? {})) {
    if (!result || typeof result !== "object") {
      throw new Error(`Invalid result for ${refId}`);
    }
    if (result.error != null && typeof result.error !== "string") {
      throw new Error(`Invalid error for ${refId}`);
    }
    if (result.frames != null && !Array.isArray(result.frames)) {
      throw new Error(`Invalid frames for ${refId}`);
    }
    for (const frame of result.frames ?? []) {
      validateWireFrame(frame, refId);
    }
  }
}
function validateWireFrame(frame, refId) {
  if (!frame || typeof frame !== "object") {
    throw new Error(`Invalid frame in ${refId}`);
  }
  const fields = frame.schema?.fields ?? frame.fields;
  if (fields != null && !Array.isArray(fields)) {
    throw new Error(`Invalid fields in ${refId}`);
  }
  if (frame.data?.values != null && !Array.isArray(frame.data.values)) {
    throw new Error(`Invalid data.values in ${refId}`);
  }
}
function wireResponseToDataFrames(raw, fallbackRefIds = []) {
  assertDsQueryWireShape(raw);
  const out = [];
  const entries = Object.entries(raw.results ?? {});
  if (!entries.length) return out;
  for (const [refId, result] of entries) {
    if (result.error) continue;
    for (const frame of result.frames ?? []) {
      out.push(wireFrameToDataFrame(frame, refId));
    }
  }
  if (fallbackRefIds.length) {
    out.sort((a, b) => {
      const ai = fallbackRefIds.indexOf(a.refId ?? "");
      const bi = fallbackRefIds.indexOf(b.refId ?? "");
      return (ai === -1 ? 999 : ai) - (bi === -1 ? 999 : bi);
    });
  }
  return out;
}
function wireFrameToDataFrame(frame, refId) {
  const schemaFields = frame.schema?.fields ?? frame.fields ?? [];
  const values = frame.data?.values;
  const fields = schemaFields.map((field, fi) => {
    const typeRaw = field.type ?? "string";
    const type = typeRaw === "time" || typeRaw === "number" || typeRaw === "boolean" || typeRaw === "other" ? typeRaw : typeRaw === "string" ? "string" : "string";
    return {
      name: field.name ?? `field_${fi}`,
      type,
      values: values?.[fi] ?? field.values ?? [],
      config: field.config ?? {},
      labels: field.labels
    };
  });
  return createDataFrame({
    refId: frame.schema?.refId ?? frame.refId ?? refId,
    name: frame.schema?.name ?? frame.name,
    fields,
    meta: frame.schema?.meta
  });
}
function timeSeries(query, range, name, valuesFn) {
  const from = range.from.getTime();
  const to = range.to.getTime();
  const steps = Math.min(200, Math.max(20, Math.floor((to - from) / 6e4)));
  const times = [];
  const values = [];
  for (let i = 0; i < steps; i++) {
    times.push(from + (to - from) * i / Math.max(steps - 1, 1));
    values.push(valuesFn(i, steps));
  }
  const legend = String(query.legendFormat || "").trim();
  const labels = { job: "api", instance: "localhost:9090" };
  let display = name;
  if (legend) {
    display = legend.replace(
      /\{\{\s*([a-zA-Z_][\w]*)\s*\}\}/g,
      (_, k) => labels[k] ?? ""
    );
  }
  if (!display || display === "Value" || /^Value\s*\{/.test(display)) {
    display = Object.entries(labels).map(([k, v]) => `${k}=${v}`).join(", ") || name || "series";
  }
  return createDataFrame({
    refId: query.refId,
    name: display,
    fields: [
      { name: "Time", type: "time", values: times },
      {
        name: "Value",
        type: "number",
        values,
        labels,
        config: { displayNameFromDS: display }
      }
    ]
  });
}
function seriesForScenario(query, range, name, metaId) {
  const from = range.from.getTime();
  const to = range.to.getTime();
  const scenario = String(
    query.scenarioId ?? query.query ?? "random_walk"
  );
  const alias = String(query.alias ?? name);
  const expr = String(
    query.expr ?? query.query ?? query.rawSql ?? query.target ?? ""
  );
  if (metaId === "prometheus" || expr.includes("up") || scenario === "prometheus_like") {
    return timeSeries(
      query,
      range,
      alias || "prometheus",
      (i) => Math.sin(i / 3) * 20 + 50 + i * 0.1
    );
  }
  if (metaId === "loki" || expr.includes("{") && expr.includes("}")) {
    const lines = Math.min(50, Number(query.maxLines ?? 30));
    return createDataFrame({
      refId: query.refId,
      name: "logs",
      fields: [
        {
          name: "Time",
          type: "time",
          values: Array.from({ length: lines }, (_, i) => from + i * 1e3)
        },
        {
          name: "Line",
          type: "string",
          values: Array.from({ length: lines }, (_, i) => {
            const level = i % 7 === 0 ? "error" : i % 5 === 0 ? "warn" : "info";
            return `${level} log line ${i} ${expr || scenario}`;
          })
        },
        {
          name: "level",
          type: "string",
          values: Array.from(
            { length: lines },
            (_, i) => i % 7 === 0 ? "error" : i % 5 === 0 ? "warn" : "info"
          )
        },
        {
          name: "labels",
          type: "other",
          values: Array.from({ length: lines }, () => ({ job: "varlogs" }))
        }
      ],
      meta: { preferredVisualisationType: "logs" }
    });
  }
  if (metaId === "mysql" || metaId === "mssql" || metaId === "grafana-postgresql-datasource" || query.rawSql) {
    const n = 12;
    return createDataFrame({
      refId: query.refId,
      name: alias,
      fields: [
        {
          name: "time",
          type: "time",
          values: Array.from(
            { length: n },
            (_, i) => from + (to - from) * i / n
          )
        },
        {
          name: "value",
          type: "number",
          values: Array.from({ length: n }, (_, i) => 10 + i * 3)
        },
        {
          name: "metric",
          type: "string",
          values: Array.from({ length: n }, (_, i) => `row-${i}`)
        }
      ]
    });
  }
  if (metaId === "influxdb") {
    return timeSeries(query, range, alias, (i) => Math.cos(i / 4) * 30 + 40);
  }
  if (metaId === "graphite") {
    return timeSeries(
      query,
      range,
      String(query.target || alias),
      (i) => i % 15
    );
  }
  if (metaId === "cloudwatch") {
    return timeSeries(
      query,
      range,
      String(query.metricName || "CPUUtilization"),
      (i) => 20 + i % 10 * 5
    );
  }
  if (metaId === "tempo" || metaId === "jaeger") {
    const n = 8;
    const spanIDs = Array.from({ length: n }, (_, i) => `span-${i}`);
    return createDataFrame({
      refId: query.refId,
      name: "trace",
      fields: [
        { name: "spanID", type: "string", values: spanIDs },
        {
          name: "parentSpanID",
          type: "string",
          values: Array.from(
            { length: n },
            (_, i) => i === 0 ? null : "span-0"
          )
        },
        {
          name: "operationName",
          type: "string",
          values: Array.from(
            { length: n },
            (_, i) => i === 0 ? "HTTP GET" : `op-${i}`
          )
        },
        {
          name: "serviceName",
          type: "string",
          values: Array.from({ length: n }, (_, i) => `svc-${i % 3}`)
        },
        {
          name: "startTimeUnixNano",
          type: "number",
          values: Array.from({ length: n }, (_, i) => 1e15 + i * 1e7)
        },
        {
          name: "durationNano",
          type: "number",
          values: Array.from(
            { length: n },
            (_, i) => i === 0 ? 1e8 : 2e7 + i * 1e6
          )
        },
        {
          name: "statusCode",
          type: "string",
          values: Array.from(
            { length: n },
            (_, i) => i === 5 ? "ERROR" : "OK"
          )
        }
      ],
      meta: { preferredVisualisationType: "trace" }
    });
  }
  if (metaId === "grafana-pyroscope-datasource") {
    const names = [
      "root",
      "main",
      "parse",
      "query",
      "scan",
      "agg",
      "render",
      "gc"
    ];
    const values = [100, 80, 20, 35, 20, 15, 25, 20];
    return createDataFrame({
      refId: query.refId,
      name: "profile",
      fields: [
        { name: "name", type: "string", values: names },
        { name: "self", type: "number", values },
        { name: "total", type: "number", values: values.map((v) => v * 1.2) },
        { name: "level", type: "number", values: [0, 1, 2, 2, 3, 3, 2, 1] }
      ],
      meta: { preferredVisualisationType: "table" }
    });
  }
  if (metaId === "grafana-azure-monitor-datasource") {
    return timeSeries(query, range, "azure-metric", (i) => 5 + i);
  }
  if (metaId === "alertmanager") {
    return createDataFrame({
      refId: query.refId,
      name: "alerts",
      fields: [
        { name: "alertname", type: "string", values: ["HighCPU", "DiskFull"] },
        { name: "state", type: "string", values: ["firing", "pending"] },
        { name: "severity", type: "string", values: ["critical", "warning"] }
      ]
    });
  }
  if (metaId === "grafana") {
    return createDataFrame({
      refId: query.refId,
      name: "grafana",
      fields: [
        { name: "Time", type: "time", values: [from, to] },
        { name: "Value", type: "number", values: [1, 1] }
      ]
    });
  }
  if (metaId === "grafana-testdata-datasource" || metaId === "testdata") {
    const seriesCount = Math.max(
      1,
      Math.min(20, Number(query.seriesCount ?? 1))
    );
    const noise = Number(query.noise ?? 0);
    const withNoise = (v, i) => v + (noise ? i * 17 % 10 * (noise / 10) : 0);
    if (scenario === "no_data") {
      return createDataFrame({
        refId: query.refId,
        name: alias || "no_data",
        fields: [
          { name: "Time", type: "time", values: [] },
          { name: "Value", type: "number", values: [] }
        ],
        meta: { noValue: true }
      });
    }
    if (scenario === "slow_query") {
      return timeSeries(
        query,
        range,
        alias || "slow",
        (i) => withNoise(Math.sin(i / 5) * 40 + 60, i)
      );
    }
    if (scenario === "csv_metric_values") {
      const raw = String(query.stringInput ?? "1,20,90,30,5,0");
      const nums = raw.split(/[\s,;]+/).map((s) => Number(s)).filter((n) => Number.isFinite(n));
      const vals = nums.length ? nums : [1, 20, 90, 30, 5, 0];
      const times = vals.map(
        (_, i) => from + (to - from) * i / Math.max(vals.length - 1, 1)
      );
      return createDataFrame({
        refId: query.refId,
        name: alias || "csv",
        fields: [
          { name: "Time", type: "time", values: times },
          { name: "Value", type: "number", values: vals }
        ]
      });
    }
    if (scenario === "logs") {
      const lines = Math.min(
        200,
        Math.max(10, Number(query.lines ?? 40))
      );
      return createDataFrame({
        refId: query.refId,
        name: "logs",
        fields: [
          {
            name: "Time",
            type: "time",
            values: Array.from({ length: lines }, (_, i) => from + i * 1500)
          },
          {
            name: "Line",
            type: "string",
            values: Array.from({ length: lines }, (_, i) => {
              const level = i % 7 === 0 ? "error" : i % 5 === 0 ? "warn" : "info";
              return `${level} testdata log line ${i}`;
            })
          },
          {
            name: "level",
            type: "string",
            values: Array.from(
              { length: lines },
              (_, i) => i % 7 === 0 ? "error" : i % 5 === 0 ? "warn" : "info"
            )
          },
          {
            name: "labels",
            type: "other",
            values: Array.from({ length: lines }, () => ({
              job: "testdata",
              filename: "/var/log/app.log"
            }))
          }
        ],
        meta: { preferredVisualisationType: "logs" }
      });
    }
    if (scenario === "trace") {
      const n = 10;
      return createDataFrame({
        refId: query.refId,
        name: "trace",
        fields: [
          {
            name: "traceID",
            type: "string",
            values: Array.from({ length: n }, () => "trace-demo")
          },
          {
            name: "spanID",
            type: "string",
            values: Array.from({ length: n }, (_, i) => `span-${i}`)
          },
          {
            name: "parentSpanID",
            type: "string",
            values: Array.from(
              { length: n },
              (_, i) => i === 0 ? null : "span-0"
            )
          },
          {
            name: "operationName",
            type: "string",
            values: Array.from(
              { length: n },
              (_, i) => i === 0 ? "HTTP GET /api" : `db.query.${i}`
            )
          },
          {
            name: "serviceName",
            type: "string",
            values: Array.from(
              { length: n },
              (_, i) => ["gateway", "api", "db"][i % 3]
            )
          },
          {
            name: "startTimeUnixNano",
            type: "number",
            values: Array.from({ length: n }, (_, i) => from * 1e6 + i * 1e7)
          },
          {
            name: "durationNano",
            type: "number",
            values: Array.from(
              { length: n },
              (_, i) => i === 0 ? 5e8 : 1e7 + i * 2e6
            )
          },
          {
            name: "statusCode",
            type: "string",
            values: Array.from(
              { length: n },
              (_, i) => i === 7 ? "ERROR" : "OK"
            )
          }
        ],
        meta: { preferredVisualisationType: "trace" }
      });
    }
    if (scenario === "node_graph") {
      const nodes = ["A", "B", "C", "D", "E"];
      return createDataFrame({
        refId: query.refId,
        name: "nodes",
        fields: [
          { name: "id", type: "string", values: nodes },
          {
            name: "title",
            type: "string",
            values: nodes.map((n) => `Service ${n}`)
          },
          {
            name: "mainstat",
            type: "number",
            values: nodes.map((_, i) => 10 + i * 7)
          },
          {
            name: "secondarystat",
            type: "number",
            values: nodes.map((_, i) => 0.1 * i)
          },
          {
            name: "arc__success",
            type: "number",
            values: nodes.map((_, i) => 0.7 + i * 0.05)
          },
          {
            name: "arc__failed",
            type: "number",
            values: nodes.map((_, i) => 0.3 - i * 0.05)
          }
        ],
        meta: { preferredVisualisationType: "nodeGraph" }
      });
    }
    if (scenario === "flame_graph") {
      const n = 16;
      return createDataFrame({
        refId: query.refId,
        name: "flame",
        fields: [
          {
            name: "level",
            type: "number",
            values: Array.from({ length: n }, (_, i) => i % 5)
          },
          {
            name: "value",
            type: "number",
            values: Array.from({ length: n }, (_, i) => 1e3 - i * 40)
          },
          {
            name: "self",
            type: "number",
            values: Array.from({ length: n }, (_, i) => 20 + i % 7 * 5)
          },
          {
            name: "label",
            type: "string",
            values: Array.from(
              { length: n },
              (_, i) => `fn_${i % 5}_block_${i}`
            )
          }
        ],
        meta: { preferredVisualisationType: "flamegraph" }
      });
    }
    if (scenario === "usa") {
      const states = ["CA", "TX", "NY", "FL", "WA", "IL", "PA", "OH"];
      return createDataFrame({
        refId: query.refId,
        name: alias || "usa",
        fields: [
          { name: "state", type: "string", values: states },
          {
            name: "value",
            type: "number",
            values: states.map((_, i) => 20 + i * 13 + i % 3 * 5)
          },
          {
            name: "lat",
            type: "number",
            values: [36.7, 31, 43, 27.8, 47.4, 40, 41.2, 40.4]
          },
          {
            name: "lon",
            type: "number",
            values: [-119.4, -99.9, -75.5, -81.7, -120.5, -89, -77.2, -82.8]
          }
        ]
      });
    }
    if (scenario === "linear_trend" || scenario === "steps") {
      const steps = Math.min(
        80,
        Math.max(20, Math.floor((to - from) / 6e4))
      );
      const xs = Array.from({ length: steps }, (_, i) => i);
      const ys = xs.map(
        (i) => withNoise(Math.sin(i / 3) * 40 + 50 + i % 7, i)
      );
      return createDataFrame({
        refId: query.refId,
        name: alias || "trend",
        fields: [
          { name: "x", type: "number", values: xs },
          {
            name: "y",
            type: "number",
            values: ys,
            config: { displayNameFromDS: alias || "y" }
          }
        ]
      });
    }
    if (scenario === "predictable_pulse") {
      return timeSeries(
        query,
        range,
        alias || "pulse",
        (i) => withNoise(i % 10 < 3 ? 100 : 0, i)
      );
    }
    if (scenario === "predictable_csv_wave") {
      return timeSeries(
        query,
        range,
        alias || "wave",
        (i) => withNoise(Math.sin(i / 3) * 50 + 50, i)
      );
    }
    if (scenario === "random_walk" || scenario === "random_walk_table") {
      if (seriesCount > 1) {
        const steps = Math.min(
          120,
          Math.max(20, Math.floor((to - from) / 6e4))
        );
        const times = Array.from(
          { length: steps },
          (_, i) => from + (to - from) * i / Math.max(steps - 1, 1)
        );
        const fields = [{ name: "Time", type: "time", values: times }];
        for (let s = 0; s < seriesCount; s++) {
          let acc2 = 50 + s * 3;
          const vals = [];
          for (let i = 0; i < steps; i++) {
            acc2 += Math.sin((i + s) / 4) * 2 + (i + s) % 5 * 0.1;
            vals.push(withNoise(acc2, i + s));
          }
          fields.push({
            name: "Value",
            type: "number",
            values: vals,
            labels: { series: String(s), name: `${alias || "walk"}-${s}` },
            config: { displayNameFromDS: `${alias || "walk"}-${s}` }
          });
        }
        return createDataFrame({
          refId: query.refId,
          name: alias || "walk",
          fields
        });
      }
      let acc = 50;
      return timeSeries(query, range, alias || "walk", (i) => {
        acc += Math.sin(i / 4) * 2 + i % 5 * 0.1;
        return withNoise(acc, i);
      });
    }
    return timeSeries(
      query,
      range,
      alias,
      (i) => withNoise(Math.sin(i / 3) * 50 + 50 + i, i)
    );
  }
  return timeSeries(query, range, alias, (i) => {
    const x = i / 3;
    switch (scenario) {
      case "predictable_pulse":
        return i % 10 < 3 ? 100 : 0;
      case "predictable_csv_wave":
        return Math.sin(x) * 50 + 50;
      case "csv_metric_values":
        return i * 7 % 100;
      case "random_walk":
      default:
        return Math.sin(x) * 50 + 50 + i + scenario.length % 7;
    }
  });
}
function createBuiltinDataSourceApi(instance, meta2) {
  return {
    uid: instance.uid,
    type: meta2.id,
    name: instance.name,
    capabilities: {
      signals: [
        meta2.metrics !== false ? "metrics" : null,
        meta2.logs ? "logs" : null,
        meta2.tracing ? "traces" : null
      ].filter(Boolean),
      query: true,
      health: true,
      metadata: true,
      variables: true,
      annotations: true,
      exemplars: false,
      streaming: false,
      queryLanguages: []
    },
    async query(request, signal) {
      const isFixtureDs = meta2.id === "grafana-testdata-datasource" || meta2.id === "testdata" || meta2.id === "mixed" || meta2.id === "dashboard" || meta2.id === "grafana";
      if (!isFixtureDs && getBackendMode() === "live" && meta2.backend && instance.uid) {
        try {
          const res = await backendSrv.post(
            "/api/ds/query",
            {
              queries: request.targets.map((t) => ({
                ...t,
                datasource: { type: instance.type, uid: instance.uid },
                maxDataPoints: request.maxDataPoints,
                intervalMs: request.intervalMs
              })),
              from: String(request.range.from.getTime()),
              to: String(request.range.to.getTime())
            },
            { signal }
          );
          const frames = wireResponseToDataFrames(
            res.data ?? {},
            request.targets.map((t) => t.refId)
          );
          return { data: frames };
        } catch (e) {
          const msg = e instanceof Error ? e.message : String(e);
          return {
            data: request.targets.filter((t) => !t.hide).map(
              (t) => createDataFrame({
                refId: t.refId,
                name: "error",
                fields: [],
                meta: { error: msg }
              })
            )
          };
        }
      }
      if (meta2.id === "mixed") {
        return { data: [] };
      }
      if (meta2.id === "dashboard") {
        return {
          data: [
            createDataFrame({
              refId: request.targets[0]?.refId ?? "A",
              fields: [
                {
                  name: "Time",
                  type: "time",
                  values: [
                    request.range.from.getTime(),
                    request.range.to.getTime()
                  ]
                },
                { name: "Value", type: "number", values: [0, 0] }
              ]
            })
          ]
        };
      }
      const targets = request.targets.filter((t) => !t.hide);
      if (meta2.id === "grafana-testdata-datasource" && targets.some(
        (t) => String(t.scenarioId ?? "") === "slow_query"
      )) {
        await new Promise((r) => setTimeout(r, 400));
      }
      return {
        data: targets.map(
          (t) => seriesForScenario(t, request.range, instance.name, meta2.id)
        )
      };
    },
    async testDatasource() {
      if (meta2.id === "mixed" || meta2.id === "dashboard") {
        return {
          status: "success",
          message: `${meta2.name} is a built-in meta datasource`
        };
      }
      if (getBackendMode() === "live") {
        try {
          await backendSrv.get(`/api/datasources/uid/${instance.uid}/health`);
          return {
            status: "success",
            message: `Data source is working (${meta2.name})`
          };
        } catch {
          return {
            status: "error",
            message: `Health check failed (${meta2.name})`
          };
        }
      }
      return {
        status: "success",
        message: `Data source offline fixture OK (${meta2.name})`
      };
    },
    async metricFindQuery(query) {
      const q = String(query ?? "");
      if (meta2.id === "prometheus") {
        return [
          "up",
          "process_cpu_seconds_total",
          "go_goroutines",
          "node_cpu_seconds_total"
        ].filter((m) => !q || m.includes(q)).map((m) => ({ text: m, value: m }));
      }
      if (meta2.id === "loki") {
        if (/label_names\s*\(/i.test(q)) {
          return [
            "filename",
            "job",
            "level",
            "namespace",
            "instance",
            "host"
          ].map((m) => ({ text: m, value: m }));
        }
        if (/label_values\s*\(/i.test(q)) {
          if (/\bjob\b/i.test(q)) {
            return ["varlogs", "nginx", "api"].map((m) => ({
              text: m,
              value: m
            }));
          }
          if (/filename|label_name/i.test(q)) {
            return ["/var/log/nginx/json_access.log", "/var/log/app.log"].map(
              (m) => ({ text: m, value: m })
            );
          }
          if (/instance/i.test(q)) {
            return ["localhost:3100", "nginx-1:3100"].map((m) => ({
              text: m,
              value: m
            }));
          }
          return ["a", "b", "all"].map((m) => ({ text: m, value: m }));
        }
        return ["job", "filename", "level", "namespace"].map((m) => ({
          text: m,
          value: m
        }));
      }
      if (meta2.id === "mysql" || meta2.id === "mssql" || meta2.id === "grafana-postgresql-datasource") {
        return ["id", "name", "value"].map((m) => ({ text: m, value: m }));
      }
      if (meta2.id === "cloudwatch") {
        return ["CPUUtilization", "NetworkIn", "NetworkOut"].filter((m) => !q || m.toLowerCase().includes(q.toLowerCase())).map((m) => ({ text: m, value: m }));
      }
      if (meta2.id === "influxdb") {
        return ["cpu", "mem", "disk"].map((m) => ({ text: m, value: m }));
      }
      if (meta2.id === "elasticsearch") {
        const ES_FIELDS = [
          "@timestamp",
          "message",
          "host",
          "service",
          "level",
          "status",
          "duration",
          "bytes",
          "method",
          "path"
        ];
        if (/fields\s*\(/i.test(q) || !q || q === "*") {
          return ES_FIELDS.map((m) => ({ text: m, value: m }));
        }
        return ES_FIELDS.filter((m) => m.includes(q)).map((m) => ({
          text: m,
          value: m
        }));
      }
      if (meta2.id === "graphite") {
        const GRAPHITE_TREE = [
          "servers.web01.cpu.idle",
          "servers.web01.cpu.user",
          "servers.web01.mem.used",
          "servers.web02.cpu.idle",
          "servers.web02.disk.bytes",
          "apps.api.requests",
          "apps.api.errors",
          "apps.worker.queue"
        ];
        const cleaned = q.replace(/\.\*$/, "").replace(/\*$/, "").replace(/\.$/, "");
        if (!cleaned || cleaned === "*") {
          const roots = [...new Set(GRAPHITE_TREE.map((m) => m.split(".")[0]))];
          return roots.map((m) => ({ text: m, value: m, expandable: true }));
        }
        if (cleaned.startsWith("expand(")) {
          const inner = cleaned.slice(7).replace(/\)$/, "");
          return GRAPHITE_TREE.filter(
            (m) => m.includes(inner.replace(/\*/g, ""))
          ).map((m) => ({ text: m, value: m, expandable: false }));
        }
        const partsQ = cleaned.split(".").filter(Boolean);
        const depth = partsQ.length;
        const segs = /* @__PURE__ */ new Map();
        for (const m of GRAPHITE_TREE) {
          const parts = m.split(".");
          let match = true;
          for (let i = 0; i < depth; i++) {
            if (parts[i] !== partsQ[i] && partsQ[i] !== "*") {
              match = false;
              break;
            }
          }
          if (!match) continue;
          if (parts.length === depth) {
            segs.set(parts[depth - 1], false);
          } else if (parts.length > depth) {
            segs.set(parts[depth], parts.length > depth + 1);
          }
        }
        if (!segs.size) {
          return GRAPHITE_TREE.filter((m) => m.includes(cleaned)).map((m) => ({
            text: m,
            value: m,
            expandable: false
          }));
        }
        return [...segs.entries()].map(([text, expandable]) => ({
          text,
          value: text,
          expandable
        }));
      }
      return [
        { text: "A", value: "A" },
        { text: "B", value: "B" },
        { text: q || "all", value: q || "all" }
      ];
    },
    /** Annotation query support — returns event frames. */
    async annotationQuery(options) {
      const from = options.range.from.getTime();
      const to = options.range.to.getTime();
      const n = 5;
      return createDataFrame({
        name: String(options.annotation.name ?? "annotations"),
        fields: [
          {
            name: "time",
            type: "time",
            values: Array.from(
              { length: n },
              (_, i) => from + (to - from) * i / n
            )
          },
          {
            name: "text",
            type: "string",
            values: Array.from(
              { length: n },
              (_, i) => `${meta2.name} event ${i}`
            )
          },
          {
            name: "tags",
            type: "string",
            values: Array.from({ length: n }, () => "outage,deploy")
          }
        ]
      });
    }
  };
}
let factory$1 = null;
function registerPrometheusDataSourceFactory(fn) {
  factory$1 = fn;
}
function createPrometheusDataSource(instance, meta2) {
  if (!factory$1) {
    throw new Error(
      "Prometheus data source factory not registered — call registerBuiltinPlugins() / load prometheus module first"
    );
  }
  return factory$1(instance, meta2);
}
function hasPrometheusDataSourceFactory() {
  return factory$1 != null;
}
function resetPrometheusDataSourceFactory() {
  factory$1 = null;
}
function computeStepMs(opts) {
  if (opts.step != null && opts.step !== "") {
    const s = typeof opts.step === "number" ? opts.step : parseDurationMs$1(String(opts.step));
    if (s > 0) return s;
  }
  const maxPoints = Math.max(1, opts.maxDataPoints ?? 1100);
  const minInterval = Math.max(
    1,
    opts.minIntervalMs ?? opts.intervalMs ?? 15e3
  );
  const raw = Math.ceil(Math.max(1, opts.rangeMs) / maxPoints);
  const step = Math.max(minInterval, raw);
  const nice = [
    1e3,
    5e3,
    1e4,
    15e3,
    3e4,
    6e4,
    12e4,
    3e5,
    6e5,
    9e5,
    18e5,
    36e5
  ];
  for (const n of nice) {
    if (n >= step) return n;
  }
  return step;
}
function parseDurationMs$1(input) {
  const m = String(input).trim().match(/^(\d+(?:\.\d+)?)(ms|s|m|h|d)?$/i);
  if (!m) {
    const n = Number(input);
    return Number.isFinite(n) ? n : 0;
  }
  const v = Number(m[1]);
  const u = (m[2] || "s").toLowerCase();
  if (u === "ms") return v;
  if (u === "s") return v * 1e3;
  if (u === "m") return v * 6e4;
  if (u === "h") return v * 36e5;
  if (u === "d") return v * 864e5;
  return v;
}
function formatDurationProm(ms) {
  if (ms % 864e5 === 0) return `${ms / 864e5}d`;
  if (ms % 36e5 === 0) return `${ms / 36e5}h`;
  if (ms % 6e4 === 0) return `${ms / 6e4}m`;
  if (ms % 1e3 === 0) return `${ms / 1e3}s`;
  return `${ms}ms`;
}
function interpolatePromMacros(expr, ctx) {
  const interval = formatDurationProm(Math.max(1, ctx.intervalMs));
  const rate = formatDurationProm(
    Math.max(ctx.intervalMs * 4, ctx.rateIntervalMs ?? ctx.intervalMs * 4)
  );
  const rangeS = Math.max(1, Math.floor(ctx.rangeMs / 1e3));
  const range = formatDurationProm(ctx.rangeMs);
  let out = expr.replace(/\$__rate_interval/g, rate).replace(/\$__interval_ms/g, String(ctx.intervalMs)).replace(/\$__interval/g, interval).replace(/\$__range_ms/g, String(ctx.rangeMs)).replace(/\$__range_s/g, String(rangeS)).replace(/\$__range/g, range);
  if (ctx.interpolate) out = ctx.interpolate(out);
  return out;
}
function formatPromLegend(legendFormat, labels = {}) {
  if (!legendFormat) {
    const entries = Object.entries(labels).filter(
      ([k, v]) => k !== "__name__" && v != null && v !== ""
    );
    const metric = labels.__name__ || "";
    if (!entries.length) return metric;
    if (entries.length === 1) return String(entries[0][1]);
    const body = entries.map(([k, v]) => `${k}="${v}"`).join(", ");
    return metric ? `${metric}{${body}}` : `{${body}}`;
  }
  return legendFormat.replace(
    /\{\{\s*([a-zA-Z_][\w]*)\s*\}\}/g,
    (_, k) => labels[k] ?? ""
  );
}
function mapPrometheusResponse(body, opts) {
  if (body?.status === "error" || body?.error) {
    throw new Error(body.error || body.errorType || "Prometheus query error");
  }
  const resultType = body?.data?.resultType ?? "matrix";
  const result = body?.data?.result ?? [];
  if (resultType === "scalar" || resultType === "string") {
    const pair = Array.isArray(result) ? result : [0, result];
    const t = Number(pair[0]) * (Number(pair[0]) < 1e12 ? 1e3 : 1);
    const v = resultType === "string" ? null : Number(pair[1]);
    return [
      createDataFrame({
        refId: opts.refId,
        name: opts.expr || "scalar",
        meta: { preferredVisualisationType: "table", resultType },
        fields: [
          { name: "Time", type: "time", values: [t] },
          {
            name: "Value",
            type: "number",
            values: [v],
            config: { displayNameFromDS: "Value" }
          }
        ]
      })
    ];
  }
  return result.map((series, idx) => {
    const metric = series.metric || {};
    const labels = {};
    for (const [k, v] of Object.entries(metric)) {
      if (k === "__name__") continue;
      labels[k] = String(v);
    }
    const name = formatPromLegend(opts.legendFormat || "", {
      ...labels,
      __name__: metric.__name__ || ""
    }) || metric.__name__ || opts.expr || `series ${idx}`;
    let times = [];
    let values = [];
    if (resultType === "vector") {
      const t = Number(series.value?.[0] ?? 0);
      times = [t < 1e12 ? t * 1e3 : t];
      const raw = series.value?.[1];
      values = [raw == null || raw === "NaN" ? null : Number(raw)];
    } else {
      const pts = series.values || [];
      times = pts.map((p) => {
        const t = Number(p[0]);
        return t < 1e12 ? t * 1e3 : t;
      });
      values = pts.map((p) => {
        const raw = p[1];
        if (raw == null || raw === "NaN") return null;
        if (raw === "+Inf") return Infinity;
        if (raw === "-Inf") return -Infinity;
        const n = Number(raw);
        return Number.isFinite(n) ? n : null;
      });
    }
    return createDataFrame({
      refId: opts.refId,
      name,
      meta: { resultType, preferredVisualisationType: "graph" },
      fields: [
        { name: "Time", type: "time", values: times },
        {
          name: "Value",
          type: "number",
          values,
          labels,
          config: { displayNameFromDS: name }
        }
      ]
    });
  });
}
function normalizePromQuery(q) {
  const instant = q.instant ?? false;
  const range = q.range ?? !instant;
  return {
    refId: q.refId,
    expr: q.expr ?? "",
    legendFormat: q.legendFormat ?? "",
    interval: q.interval,
    intervalFactor: q.intervalFactor ?? 1,
    instant,
    range: instant ? false : range,
    exemplar: q.exemplar ?? false,
    format: q.format ?? "time_series",
    editorMode: q.editorMode ?? "code",
    utcOffsetSec: q.utcOffsetSec ?? 0,
    datasource: q.datasource,
    hide: q.hide
  };
}
function normalizeLokiQuery(q) {
  const instant = q.instant === true || q.queryType === "instant";
  return {
    refId: q.refId,
    expr: q.expr ?? "",
    legendFormat: q.legendFormat ?? "",
    maxLines: q.maxLines ?? 1e3,
    queryType: q.queryType ?? (instant ? "instant" : "range"),
    instant,
    range: instant ? false : q.range !== false,
    editorMode: q.editorMode ?? "code",
    resolution: q.resolution ?? 1,
    direction: q.direction ?? "backward",
    step: q.step,
    datasource: q.datasource,
    hide: q.hide
  };
}
let factory = null;
function registerSignozDataSourceFactory(fn) {
  factory = fn;
}
function createSignozDataSource$1(instance, meta2) {
  if (!factory) {
    throw new Error(
      "SigNoz data source factory not registered — call registerHeavyPlugins() / load signoz module first"
    );
  }
  return factory(instance, meta2);
}
function hasSignozDataSourceFactory() {
  return factory != null;
}
function resetSignozDataSourceFactory() {
  factory = null;
}
const ZABBIX_TYPE$1 = "alexanderzobnin-zabbix-datasource";
const SIGNOZ_TYPE$1 = "signoz";
function ds(type, uid) {
  return { type, uid };
}
function panel(id, type, title, gridPos, targets, extra = {}) {
  return {
    id,
    type,
    title,
    gridPos,
    targets,
    options: extra.options || {},
    fieldConfig: extra.fieldConfig || { defaults: {}, overrides: [] },
    datasource: targets[0]?.datasource,
    ...extra
  };
}
function assertNoEmptyDupTargets(panels2, uid) {
  const seen = /* @__PURE__ */ new Set();
  for (const p of panels2) {
    for (const t of p.targets || []) {
      const key = JSON.stringify({
        refId: t.refId,
        queryType: t.queryType,
        signal: t.signal,
        requestType: t.requestType,
        expr: t.expr,
        item: t.item,
        schema: t.schema
      });
      if (seen.has(key) && !t.expr && !t.item?.filter && !(t.queries || []).length) {
        throw new Error(`${uid}: duplicate empty target ${key}`);
      }
      seen.add(`${p.id}:${t.refId}`);
      if (!t.datasource?.uid) {
        throw new Error(`${uid}: target ${t.refId} missing datasource uid`);
      }
    }
  }
}
function zabbixScopeFilters() {
  return { group: { filter: "$Group" }, host: { filter: "$Host" } };
}
function zabbixTemplating(datasource) {
  return {
    list: [
      {
        name: "Group",
        type: "query",
        datasource,
        query: { queryType: "group", filter: "" },
        current: { text: "All", value: "/.*/" },
        includeAll: true,
        allValue: "/.*/",
        refresh: 1
      },
      {
        name: "Host",
        type: "query",
        datasource,
        query: { queryType: "host", group: "$Group", filter: "" },
        current: { text: "All", value: "/.*/" },
        includeAll: true,
        allValue: "/.*/",
        refresh: 1
      }
    ]
  };
}
function buildLiveZabbixMetrics(uid = "live-zabbix-metrics") {
  const d = ds(ZABBIX_TYPE$1, "zabbix");
  const scope = zabbixScopeFilters();
  const panels2 = [
    panel(1, "timeseries", "History metrics", { x: 0, y: 0, w: 12, h: 8 }, [
      {
        refId: "A",
        queryType: "0",
        ...scope,
        item: { filter: "system.cpu.util" },
        datasource: d
      }
    ]),
    panel(2, "timeseries", "Trends metrics", { x: 12, y: 0, w: 12, h: 8 }, [
      {
        refId: "B",
        queryType: "0",
        useTrends: "true",
        ...scope,
        item: { filter: "vm.memory.util" },
        datasource: d
      }
    ]),
    panel(3, "stat", "Latest single", { x: 0, y: 8, w: 8, h: 6 }, [
      {
        refId: "C",
        queryType: "0",
        ...scope,
        item: { filter: "agent.ping" },
        datasource: d
      }
    ]),
    panel(4, "table", "Item inventory", { x: 8, y: 8, w: 16, h: 6 }, [
      {
        refId: "D",
        queryType: "2",
        ...scope,
        item: { filter: "system.uname" },
        datasource: d
      }
    ])
  ];
  assertNoEmptyDupTargets(panels2, uid);
  return {
    uid,
    title: "Live Zabbix Metrics",
    schemaVersion: 39,
    requireLiveFrames: true,
    tags: ["live", "zabbix", "metrics"],
    time: { from: "now-1h", to: "now" },
    templating: zabbixTemplating(d),
    meta: { liveOnly: true, datasourceUid: "zabbix" },
    panels: panels2
  };
}
function buildLiveZabbixItemid(uid = "live-zabbix-itemid") {
  const d = ds(ZABBIX_TYPE$1, "zabbix");
  const panels2 = [
    panel(1, "timeseries", "By itemids", { x: 0, y: 0, w: 24, h: 10 }, [
      { refId: "A", queryType: "0", itemids: ["10001"], datasource: d },
      { refId: "B", queryType: "0", itemids: ["10002"], datasource: d }
    ])
  ];
  assertNoEmptyDupTargets(panels2, uid);
  return {
    uid,
    title: "Live Zabbix ItemIDs",
    schemaVersion: 39,
    requireLiveFrames: true,
    meta: { liveOnly: true, datasourceUid: "zabbix" },
    panels: panels2
  };
}
function buildLiveZabbixText(uid = "live-zabbix-text") {
  const d = ds(ZABBIX_TYPE$1, "zabbix");
  const panels2 = [
    panel(1, "logs", "Text / log items", { x: 0, y: 0, w: 24, h: 12 }, [
      {
        refId: "A",
        queryType: "2",
        ...zabbixScopeFilters(),
        item: { filter: "log[*]" },
        datasource: d
      }
    ])
  ];
  assertNoEmptyDupTargets(panels2, uid);
  return {
    uid,
    title: "Live Zabbix Text",
    schemaVersion: 39,
    requireLiveFrames: true,
    templating: zabbixTemplating(ds(ZABBIX_TYPE$1, "zabbix")),
    meta: { liveOnly: true, datasourceUid: "zabbix" },
    panels: panels2
  };
}
function buildLiveZabbixServices(uid = "live-zabbix-services") {
  const d = ds(ZABBIX_TYPE$1, "zabbix");
  const panels2 = [
    panel(1, "table", "IT Services", { x: 0, y: 0, w: 24, h: 12 }, [
      {
        refId: "A",
        queryType: "1",
        service: { filter: "/.*/" },
        itServiceFilter: "/.*/",
        slaProperty: "sli",
        datasource: d
      }
    ])
  ];
  assertNoEmptyDupTargets(panels2, uid);
  return {
    uid,
    title: "Live Zabbix Services",
    schemaVersion: 39,
    requireLiveFrames: true,
    meta: { liveOnly: true, datasourceUid: "zabbix" },
    panels: panels2
  };
}
function buildLiveZabbixTriggers(uid = "live-zabbix-triggers") {
  const d = ds(ZABBIX_TYPE$1, "zabbix");
  const panels2 = [
    panel(1, "table", "Triggers", { x: 0, y: 0, w: 24, h: 12 }, [
      {
        refId: "A",
        queryType: "4",
        ...zabbixScopeFilters(),
        trigger: { filter: "" },
        options: { limit: 100 },
        datasource: d
      }
    ])
  ];
  assertNoEmptyDupTargets(panels2, uid);
  return {
    uid,
    title: "Live Zabbix Triggers",
    schemaVersion: 39,
    requireLiveFrames: true,
    templating: zabbixTemplating(ds(ZABBIX_TYPE$1, "zabbix")),
    meta: { liveOnly: true, datasourceUid: "zabbix" },
    panels: panels2
  };
}
function buildLiveZabbixProblems(uid = "live-zabbix-problems") {
  const d = ds(ZABBIX_TYPE$1, "zabbix");
  const panels2 = [
    panel(
      1,
      "alexanderzobnin-zabbix-triggers-panel",
      "Problems panel",
      { x: 0, y: 0, w: 24, h: 14 },
      [
        {
          refId: "A",
          queryType: "5",
          ...zabbixScopeFilters(),
          options: { useTimeRange: true, minSeverity: 2, limit: 50 },
          datasource: d
        }
      ]
    )
  ];
  assertNoEmptyDupTargets(panels2, uid);
  return {
    uid,
    title: "Live Zabbix Problems",
    schemaVersion: 39,
    requireLiveFrames: true,
    templating: zabbixTemplating(ds(ZABBIX_TYPE$1, "zabbix")),
    meta: { liveOnly: true, datasourceUid: "zabbix" },
    panels: panels2
  };
}
function buildLiveZabbixMacros(uid = "live-zabbix-macros") {
  const d = ds(ZABBIX_TYPE$1, "zabbix");
  const panels2 = [
    panel(1, "table", "User macros", { x: 0, y: 0, w: 24, h: 10 }, [
      {
        refId: "A",
        queryType: "6",
        ...zabbixScopeFilters(),
        macro: { filter: "" },
        datasource: d
      }
    ])
  ];
  assertNoEmptyDupTargets(panels2, uid);
  return {
    uid,
    title: "Live Zabbix Macros",
    schemaVersion: 39,
    requireLiveFrames: true,
    templating: zabbixTemplating(ds(ZABBIX_TYPE$1, "zabbix")),
    meta: { liveOnly: true, datasourceUid: "zabbix" },
    panels: panels2
  };
}
function buildLiveZabbixLld(uid = "live-zabbix-lld") {
  const d = ds(ZABBIX_TYPE$1, "zabbix");
  const panels2 = [
    panel(1, "table", "LLD discovery", { x: 0, y: 0, w: 24, h: 10 }, [
      {
        refId: "A",
        queryType: "0",
        executionMode: "lld",
        lld: {
          ruleId: "10001",
          ruleName: "Mounted filesystem discovery",
          prototypeIds: [],
          prototypeKeys: ["vfs.fs.size[{#FSNAME},pused]"]
        },
        ...zabbixScopeFilters(),
        application: { filter: "/.*/" },
        datasource: d
      }
    ])
  ];
  assertNoEmptyDupTargets(panels2, uid);
  return {
    uid,
    title: "Live Zabbix LLD",
    schemaVersion: 39,
    requireLiveFrames: true,
    templating: zabbixTemplating(ds(ZABBIX_TYPE$1, "zabbix")),
    meta: { liveOnly: true, datasourceUid: "zabbix" },
    panels: panels2
  };
}
function signozBuilder(refId, signal, requestType, uid, extra = {}) {
  return {
    refId,
    schema: 1,
    apiProfile: extra.apiProfile || "signoz-v5",
    requestType,
    signal,
    datasource: ds(SIGNOZ_TYPE$1, uid),
    queries: [
      {
        type: "builder_query",
        queryType: extra.queryType || "builder",
        spec: {
          name: refId,
          signal,
          disabled: false,
          filter: {
            expression: extra.filter != null ? String(extra.filter) : ""
          },
          having: { expression: "" },
          groupBy: [],
          order: [],
          legend: "",
          functions: [],
          aggregations: extra.aggregations || (signal === "metrics" ? [
            {
              metricName: "up",
              temporality: "Unspecified",
              timeAggregation: "avg",
              spaceAggregation: "avg"
            }
          ] : signal === "logs" || signal === "traces" ? [{ expression: "count()" }] : []),
          tags: [],
          service: extra.service,
          operation: extra.operation,
          stepInterval: null
        },
        rawQuery: extra.rawQuery || ""
      }
    ],
    ...extra.flat
  };
}
function buildLiveSignozNativeMetrics(uid = "live-signoz-native-metrics") {
  const dsUid = "signoz";
  const panels2 = [
    panel(1, "timeseries", "Builder metrics", { x: 0, y: 0, w: 12, h: 8 }, [
      signozBuilder("A", "metrics", "time_series", dsUid)
    ]),
    panel(2, "timeseries", "PromQL", { x: 12, y: 0, w: 12, h: 8 }, [
      signozBuilder("B", "metrics", "time_series", dsUid, {
        queryType: "promql",
        rawQuery: "up"
      })
    ]),
    panel(3, "stat", "Scalar", { x: 0, y: 8, w: 8, h: 6 }, [
      signozBuilder("C", "metrics", "scalar", dsUid)
    ]),
    panel(4, "table", "ClickHouse SQL", { x: 8, y: 8, w: 16, h: 6 }, [
      signozBuilder("D", "metrics", "time_series", dsUid, {
        queryType: "clickhouse_sql",
        rawQuery: "SELECT 1"
      })
    ])
  ];
  assertNoEmptyDupTargets(panels2, uid);
  return {
    uid,
    title: "Live SigNoz Native Metrics",
    schemaVersion: 39,
    requireLiveFrames: true,
    templating: {
      list: [
        {
          name: "service",
          type: "query",
          datasource: ds(SIGNOZ_TYPE$1, dsUid),
          query: { type: "service" }
        },
        {
          name: "metric",
          type: "query",
          datasource: ds(SIGNOZ_TYPE$1, dsUid),
          query: { type: "metric" }
        }
      ]
    },
    meta: { liveOnly: true, datasourceUid: dsUid, apiProfile: "signoz-v5" },
    panels: panels2
  };
}
function buildLiveSignozNativeLogs(uid = "live-signoz-native-logs") {
  const dsUid = "signoz";
  const panels2 = [
    panel(1, "logs", "Raw logs", { x: 0, y: 0, w: 24, h: 10 }, [
      signozBuilder("A", "logs", "raw", dsUid, { filter: "severity = error" })
    ]),
    panel(2, "logs", "Raw stream shape", { x: 0, y: 10, w: 24, h: 8 }, [
      signozBuilder("B", "logs", "raw_stream", dsUid, {
        filter: "body exists"
      })
    ])
  ];
  assertNoEmptyDupTargets(panels2, uid);
  return {
    uid,
    title: "Live SigNoz Native Logs",
    schemaVersion: 39,
    requireLiveFrames: true,
    annotations: {
      list: [
        {
          name: "error logs",
          enable: true,
          datasource: ds(SIGNOZ_TYPE$1, dsUid),
          target: { source: "errorLogs" }
        }
      ]
    },
    meta: { liveOnly: true, datasourceUid: dsUid, apiProfile: "signoz-v5" },
    panels: panels2
  };
}
function buildLiveSignozNativeTraces(uid = "live-signoz-native-traces") {
  const dsUid = "signoz";
  const panels2 = [
    panel(1, "traces", "Trace list", { x: 0, y: 0, w: 24, h: 10 }, [
      signozBuilder("A", "traces", "trace", dsUid, {
        filter: "has_error = true"
      })
    ]),
    panel(2, "traces", "Trace operator", { x: 0, y: 10, w: 24, h: 8 }, [
      {
        refId: "B",
        schema: 1,
        apiProfile: "signoz-v5",
        requestType: "trace",
        signal: "traces",
        datasource: ds(SIGNOZ_TYPE$1, dsUid),
        queries: [
          {
            type: "builder_trace_operator",
            spec: { name: "B", expression: "A", legend: "op" }
          }
        ]
      }
    ])
  ];
  assertNoEmptyDupTargets(panels2, uid);
  return {
    uid,
    title: "Live SigNoz Native Traces",
    schemaVersion: 39,
    requireLiveFrames: true,
    meta: { liveOnly: true, datasourceUid: dsUid, apiProfile: "signoz-v5" },
    panels: panels2
  };
}
function buildLiveSignozNativeQueryModes(uid = "live-signoz-native-query-modes") {
  const dsUid = "signoz";
  const panels2 = [
    panel(1, "timeseries", "builder", { x: 0, y: 0, w: 8, h: 8 }, [
      signozBuilder("A", "metrics", "time_series", dsUid, {
        queryType: "builder"
      })
    ]),
    panel(2, "timeseries", "promql", { x: 8, y: 0, w: 8, h: 8 }, [
      signozBuilder("B", "metrics", "time_series", dsUid, {
        queryType: "promql",
        rawQuery: "up"
      })
    ]),
    panel(3, "timeseries", "clickhouse_sql", { x: 16, y: 0, w: 8, h: 8 }, [
      signozBuilder("C", "metrics", "time_series", dsUid, {
        queryType: "clickhouse_sql",
        rawQuery: "SELECT now()"
      })
    ])
  ];
  assertNoEmptyDupTargets(panels2, uid);
  return {
    uid,
    title: "Live SigNoz Query Modes",
    schemaVersion: 39,
    requireLiveFrames: true,
    meta: { liveOnly: true, datasourceUid: dsUid, apiProfile: "signoz-v5" },
    panels: panels2
  };
}
function buildLiveSignozNativeResults(uid = "live-signoz-native-results") {
  const dsUid = "signoz";
  const panels2 = [
    panel(1, "timeseries", "time_series", { x: 0, y: 0, w: 12, h: 7 }, [
      signozBuilder("A", "metrics", "time_series", dsUid)
    ]),
    panel(2, "stat", "scalar", { x: 12, y: 0, w: 12, h: 7 }, [
      signozBuilder("B", "metrics", "scalar", dsUid)
    ]),
    panel(3, "logs", "raw", { x: 0, y: 7, w: 12, h: 7 }, [
      signozBuilder("C", "logs", "raw", dsUid)
    ]),
    panel(4, "traces", "trace", { x: 12, y: 7, w: 12, h: 7 }, [
      signozBuilder("D", "traces", "trace", dsUid)
    ])
  ];
  assertNoEmptyDupTargets(panels2, uid);
  return {
    uid,
    title: "Live SigNoz Result Types",
    schemaVersion: 39,
    requireLiveFrames: true,
    meta: { liveOnly: true, datasourceUid: dsUid, apiProfile: "signoz-v5" },
    panels: panels2
  };
}
function buildLiveSignoz(uid = "live-signoz") {
  const dsUid = "signoz";
  const panels2 = [
    panel(
      1,
      "timeseries",
      "SigNoz metrics (query_range)",
      { x: 0, y: 0, w: 24, h: 10 },
      [
        signozBuilder("A", "metrics", "time_series", dsUid, {
          apiProfile: "signoz-v5"
        })
      ]
    ),
    panel(
      2,
      "text",
      "SigNoz capability diagnostics",
      { x: 0, y: 10, w: 24, h: 6 },
      [],
      {
        options: {
          content: "Diagnostics only: profile=signoz-v5; official SigNoz endpoints; tokens never shown.",
          mode: "markdown"
        },
        targets: [
          {
            refId: "diag",
            datasource: ds(SIGNOZ_TYPE$1, dsUid),
            hide: true,
            apiProfile: "signoz-v5"
          }
        ]
      }
    )
  ];
  assertNoEmptyDupTargets(
    panels2.map((p) => ({
      ...p,
      targets: (p.targets || []).filter((t) => !t.hide)
    })),
    uid
  );
  return {
    uid,
    title: "Live SigNoz",
    schemaVersion: 39,
    requireLiveFrames: true,
    meta: {
      liveOnly: true,
      datasourceUid: dsUid,
      apiProfile: "signoz-v5",
      diagnostics: {
        profile: "signoz-v5",
        supported: [
          "metrics.list",
          "attribute.keys",
          "attribute.values",
          "services",
          "operations",
          "query_range",
          "alerts"
        ]
      }
    },
    panels: panels2
  };
}
function buildLiveSignozObservability(uid = "live-signoz-observability") {
  const dsUid = "signoz";
  const panels2 = [
    panel(1, "timeseries", "RED metrics", { x: 0, y: 0, w: 12, h: 8 }, [
      signozBuilder("A", "metrics", "time_series", dsUid, {
        aggregations: [{ metricName: "signoz_latency", expression: "P95" }]
      })
    ]),
    panel(2, "logs", "Error logs", { x: 12, y: 0, w: 12, h: 8 }, [
      signozBuilder("B", "logs", "raw", dsUid, { filter: "severity = error" })
    ]),
    panel(3, "traces", "Error traces", { x: 0, y: 8, w: 12, h: 8 }, [
      signozBuilder("C", "traces", "trace", dsUid, {
        filter: "has_error = true"
      })
    ]),
    panel(4, "signoz-issues", "Issues", { x: 12, y: 8, w: 12, h: 8 }, [
      {
        refId: "D",
        signal: "alerts",
        schema: 1,
        datasource: ds(SIGNOZ_TYPE$1, dsUid),
        queries: []
      }
    ])
  ];
  assertNoEmptyDupTargets(panels2, uid);
  return {
    uid,
    title: "Live SigNoz Observability",
    schemaVersion: 39,
    requireLiveFrames: true,
    meta: { liveOnly: true, datasourceUid: dsUid, apiProfile: "signoz-v5" },
    panels: panels2
  };
}
function buildLiveDiagnostics(uid = "live-observability-diagnostics") {
  return {
    uid,
    title: "Observability Diagnostics",
    schemaVersion: 39,
    meta: {
      diagnostics: {
        fields: [
          "urlPath",
          "version",
          "profile",
          "authKind",
          "credentialHeaderName",
          "supportedQueryTypes",
          "supportedResultTypes",
          "supportedMetadata",
          "supportedDetail",
          "supportedActions",
          "lastChecked",
          "error"
        ],
        forbidden: ["token", "password", "apiKey", "authorization"]
      }
    },
    panels: [
      panel(
        1,
        "text",
        "Capability matrix (sanitized)",
        { x: 0, y: 0, w: 24, h: 12 },
        [],
        {
          options: {
            mode: "markdown",
            content: "## Diagnostics\n\n- URL path / profile / version\n- Auth kind + header **name** only\n- Query / result / metadata / detail / action support\n- Last checked + error code\n\n**Never display tokens.**"
          }
        }
      )
    ]
  };
}
function buildLiveZabbixFull(uid = "live-zabbix-full") {
  const z3 = ds(ZABBIX_TYPE$1, "zabbix-3");
  const z14 = ds(ZABBIX_TYPE$1, "zabbix-14");
  const g = { filter: "$Group" };
  const h = { filter: "$Host" };
  const lineCfg = (fill = 10) => ({
    defaults: {
      custom: {
        drawStyle: "line",
        lineInterpolation: "smooth",
        lineWidth: 2,
        fillOpacity: fill,
        showPoints: "never",
        spanNulls: false,
        axisPlacement: "auto"
      },
      unit: "percent"
    },
    overrides: []
  });
  const barCfg = (fill = 50) => ({
    defaults: {
      custom: {
        drawStyle: "bars",
        lineWidth: 1,
        fillOpacity: fill,
        showPoints: "never",
        spanNulls: false,
        axisPlacement: "auto"
      },
      unit: "percent"
    },
    overrides: []
  });
  const legendOpts = {
    legend: {
      showLegend: true,
      displayMode: "list",
      placement: "bottom",
      calcs: ["mean", "max", "last"]
    },
    tooltip: { mode: "multi", sort: "desc" }
  };
  const panels2 = [
    panel(
      1,
      "timeseries",
      "Z3 · CPU 趋势 · 折线图 (trend.get)",
      { x: 0, y: 0, w: 12, h: 9 },
      [
        {
          refId: "A",
          queryType: "0",
          group: g,
          host: h,
          item: { filter: "/system.cpu.util/" },
          options: { useTrends: "true" },
          datasource: z3
        }
      ],
      { options: legendOpts, fieldConfig: lineCfg(12) }
    ),
    panel(
      2,
      "timeseries",
      "Z3 · CPU 趋势 · 柱状图 (trend.get)",
      { x: 12, y: 0, w: 12, h: 9 },
      [
        {
          refId: "B",
          queryType: "0",
          group: g,
          host: h,
          item: { filter: "/system.cpu.util/" },
          options: { useTrends: "true" },
          datasource: z3
        }
      ],
      { options: legendOpts, fieldConfig: barCfg(55) }
    ),
    panel(
      13,
      "timeseries",
      "Z3 · Memory 趋势 · 折线 (trend.get)",
      { x: 0, y: 9, w: 12, h: 8 },
      [
        {
          refId: "M",
          queryType: "0",
          group: g,
          host: h,
          item: { filter: "/vm.memory.utilization|vm.memory.size|memory/" },
          options: { useTrends: "true" },
          datasource: z3
        }
      ],
      { options: legendOpts, fieldConfig: lineCfg(15) }
    ),
    panel(
      14,
      "timeseries",
      "Z3 · History 柱状 (history.get)",
      { x: 12, y: 9, w: 12, h: 8 },
      [
        {
          refId: "Hbar",
          queryType: "0",
          group: g,
          host: h,
          item: { filter: "/agent.ping|system.cpu.util$/" },
          options: { useTrends: "false" },
          datasource: z3
        }
      ],
      {
        options: legendOpts,
        fieldConfig: {
          defaults: {
            custom: {
              drawStyle: "bars",
              fillOpacity: 40,
              lineWidth: 1,
              showPoints: "never"
            }
          },
          overrides: []
        }
      }
    ),
    panel(
      9,
      "timeseries",
      "Z14 · Metrics 折线 (trends→history fallback)",
      { x: 0, y: 17, w: 24, h: 8 },
      [
        {
          refId: "I",
          queryType: "0",
          group: g,
          host: h,
          item: { filter: "/system.cpu.util|cpu|load|agent.ping/" },
          options: { useTrends: "true" },
          datasource: z14
        }
      ],
      { options: legendOpts, fieldConfig: lineCfg(8) }
    ),
    panel(
      3,
      "timeseries",
      "Z3 · agent.ping history 折线",
      { x: 0, y: 25, w: 12, h: 7 },
      [
        {
          refId: "C",
          queryType: "0",
          group: g,
          host: h,
          item: { filter: "agent.ping" },
          options: { useTrends: "false" },
          datasource: z3
        }
      ],
      {
        options: { legend: { showLegend: true, displayMode: "list", placement: "bottom" } },
        fieldConfig: {
          defaults: { custom: { drawStyle: "line", lineWidth: 2 } },
          overrides: []
        }
      }
    ),
    panel(4, "logs", "Z3 · Text / log items", { x: 12, y: 25, w: 12, h: 7 }, [
      {
        refId: "D",
        queryType: "2",
        group: g,
        host: h,
        item: { filter: "/log\\[|text|system.uname/" },
        datasource: z3
      }
    ]),
    panel(5, "table", "Z3 · Problems", { x: 0, y: 32, w: 12, h: 8 }, [
      {
        refId: "E",
        queryType: "5",
        group: g,
        host: h,
        showProblems: "problems",
        options: { sortProblems: "lastchange", limit: 50, useTimeRange: true },
        datasource: z3
      }
    ]),
    panel(6, "table", "Z3 · Triggers", { x: 12, y: 32, w: 12, h: 8 }, [
      {
        refId: "F",
        queryType: "4",
        group: g,
        host: h,
        trigger: { filter: "" },
        options: { limit: 100 },
        datasource: z3
      }
    ]),
    panel(7, "table", "Z3 · Macros", { x: 0, y: 40, w: 8, h: 7 }, [
      {
        refId: "G",
        queryType: "6",
        group: g,
        host: h,
        macro: { filter: "" },
        datasource: z3
      }
    ]),
    panel(8, "table", "Z3 · IT Services / SLA", { x: 8, y: 40, w: 8, h: 7 }, [
      {
        refId: "H",
        queryType: "1",
        service: { filter: "/.*/" },
        itServiceFilter: "/.*/",
        slaProperty: "sli",
        datasource: z3
      }
    ]),
    panel(10, "table", "Z14 · Problems", { x: 16, y: 40, w: 8, h: 7 }, [
      {
        refId: "J",
        queryType: "5",
        group: g,
        host: h,
        showProblems: "problems",
        options: { sortProblems: "priority", limit: 50, useTimeRange: true },
        datasource: z14
      }
    ]),
    panel(11, "table", "Z14 · Triggers", { x: 0, y: 47, w: 12, h: 8 }, [
      {
        refId: "K",
        queryType: "4",
        group: g,
        host: h,
        trigger: { filter: "" },
        options: { limit: 100 },
        datasource: z14
      }
    ]),
    panel(
      12,
      "text",
      "Zabbix live 全量说明",
      { x: 12, y: 47, w: 12, h: 8 },
      [],
      {
        options: {
          mode: "markdown",
          content: "### Live Zabbix Full\\n- 顶部：**CPU 趋势折线 / CPU 趋势柱状 / Memory 趋势 / History 柱状**\\n- 时间默认 `now-7d`（`trend.get` 需要足够宽的时间窗）\\n- Group/Host=All 时走 item-first 搜索（不取空名主机）\\n- z14 若无 trend 行会自动回退 history.get\\n- 数据源: `zabbix-3`(6.x) + `zabbix-14`(7.x)"
        }
      }
    )
  ];
  assertNoEmptyDupTargets(
    panels2.filter((p) => (p.targets || []).length).map((p) => ({ ...p, targets: p.targets })),
    uid
  );
  return {
    uid,
    title: "Live Zabbix Full (真实接口全量)",
    schemaVersion: 39,
    requireLiveFrames: true,
    tags: ["live", "zabbix", "full", "real-api", "trends"],
    // 2d keeps trend.get responsive while still exercising trends path.
    time: { from: "now-2d", to: "now" },
    templating: {
      list: [
        {
          name: "Group",
          type: "query",
          datasource: z3,
          query: { queryType: "group", filter: "" },
          current: { text: "All", value: "/.*/" },
          includeAll: true,
          allValue: "/.*/",
          refresh: 1
        },
        {
          name: "Host",
          type: "query",
          datasource: z3,
          query: { queryType: "host", group: "$Group", filter: "" },
          // Prefer a host with real metrics; All remains available via includeAll.
          current: { text: "Zabbix server", value: "Zabbix server" },
          includeAll: true,
          allValue: "/.*/",
          refresh: 1
        }
      ]
    },
    meta: { liveOnly: true, datasourceUid: "zabbix-3" },
    panels: panels2
  };
}
function buildLiveSignozFull(uid = "live-signoz-full") {
  const dsUid = "signoz";
  const panels2 = [
    panel(
      1,
      "timeseries",
      "Metrics · builder (rate/sum)",
      { x: 0, y: 0, w: 12, h: 8 },
      [
        signozBuilder("A", "metrics", "time_series", dsUid, {
          aggregations: [
            {
              metricName: "app.ads.ad_requests",
              temporality: "cumulative",
              timeAggregation: "rate",
              spaceAggregation: "sum"
            }
          ]
        })
      ]
    ),
    panel(
      2,
      "timeseries",
      "Metrics · PromQL up",
      { x: 12, y: 0, w: 12, h: 8 },
      [
        signozBuilder("B", "metrics", "time_series", dsUid, {
          queryType: "promql",
          rawQuery: "up"
        })
      ]
    ),
    panel(3, "stat", "Metrics · scalar avg", { x: 0, y: 8, w: 6, h: 6 }, [
      signozBuilder("C", "metrics", "scalar", dsUid, {
        aggregations: [
          {
            metricName: "up",
            temporality: "Unspecified",
            timeAggregation: "avg",
            spaceAggregation: "avg",
            reduceTo: "avg"
          }
        ]
      })
    ]),
    panel(
      4,
      "table",
      "Traces · scalar table (count/p99/errors)",
      { x: 6, y: 8, w: 10, h: 6 },
      [
        // multi-query scalar is built as single target; adapter may run one builder
        signozBuilder("D", "traces", "scalar", dsUid, {
          aggregations: [{ expression: "count()" }],
          filter: "",
          flat: {
            queries: [
              {
                type: "builder_query",
                queryType: "builder",
                spec: {
                  name: "A",
                  signal: "traces",
                  disabled: false,
                  filter: { expression: "" },
                  having: { expression: "" },
                  groupBy: [
                    {
                      name: "service.name",
                      signal: "traces",
                      fieldContext: "resource",
                      fieldDataType: "string"
                    }
                  ],
                  order: [],
                  legend: "",
                  functions: [],
                  aggregations: [{ expression: "count()" }],
                  tags: [],
                  stepInterval: null,
                  limit: 20
                }
              }
            ]
          }
        })
      ]
    ),
    panel(5, "logs", "Logs · raw ERROR", { x: 16, y: 8, w: 8, h: 6 }, [
      signozBuilder("E", "logs", "raw", dsUid, {
        filter: "severity_text = 'ERROR'"
      })
    ]),
    panel(
      6,
      "timeseries",
      "Traces · request rate by service",
      { x: 0, y: 14, w: 12, h: 8 },
      [
        signozBuilder("F", "traces", "time_series", dsUid, {
          aggregations: [{ expression: "count()" }],
          filter: "",
          flat: {
            queries: [
              {
                type: "builder_query",
                queryType: "builder",
                spec: {
                  name: "A",
                  signal: "traces",
                  disabled: false,
                  stepInterval: 60,
                  filter: { expression: "" },
                  having: { expression: "" },
                  groupBy: [
                    {
                      name: "service.name",
                      signal: "traces",
                      fieldContext: "resource",
                      fieldDataType: "string"
                    }
                  ],
                  order: [],
                  legend: "{{service.name}}",
                  functions: [],
                  aggregations: [{ expression: "count()" }],
                  tags: [],
                  limit: 10
                }
              }
            ]
          }
        })
      ]
    ),
    panel(7, "table", "Traces · list", { x: 12, y: 14, w: 12, h: 8 }, [
      signozBuilder("G", "traces", "trace", dsUid, {
        aggregations: [],
        filter: ""
      })
    ]),
    panel(
      8,
      "timeseries",
      "ClickHouse SQL · count",
      { x: 0, y: 22, w: 12, h: 7 },
      [
        signozBuilder("H", "metrics", "scalar", dsUid, {
          queryType: "clickhouse_sql",
          rawQuery: "SELECT count() AS c FROM argus_apm_traces.distributed_index_v3 WHERE timestamp >= now() - INTERVAL 30 MINUTE"
        })
      ]
    ),
    panel(
      9,
      "timeseries",
      "Metrics · having + legend",
      { x: 12, y: 22, w: 12, h: 7 },
      [
        signozBuilder("I", "traces", "time_series", dsUid, {
          aggregations: [{ expression: "count()", alias: "count" }],
          flat: {
            queries: [
              {
                type: "builder_query",
                queryType: "builder",
                spec: {
                  name: "A",
                  signal: "traces",
                  stepInterval: 60,
                  disabled: false,
                  filter: { expression: "" },
                  having: { expression: "count() > 0" },
                  groupBy: [
                    {
                      name: "service.name",
                      signal: "traces",
                      fieldContext: "resource",
                      fieldDataType: "string"
                    }
                  ],
                  order: [],
                  legend: "{{service.name}}",
                  functions: [],
                  aggregations: [{ expression: "count()", alias: "count" }],
                  tags: [],
                  limit: 5
                }
              }
            ]
          }
        })
      ]
    ),
    panel(
      10,
      "text",
      "SigNoz / argus-web 对齐说明",
      { x: 0, y: 29, w: 24, h: 6 },
      [],
      {
        options: {
          mode: "markdown",
          content: '### Live SigNoz Full（对齐 `refs/argus-web-4.0/src/views/signoz` + `api/signoz.ts`）\\n- 端点: `POST /api/v5/query_range`、`POST /api/v2/services`（ns epoch 字符串）、fields/metrics\\n- metrics aggregation: `{metricName,timeAggregation,spaceAggregation,temporality}`（禁止 `expression:"avg"`）\\n- traces/logs aggregation: `{expression:"count()"}` / `p99(duration_nano)`\\n- filter 一律 `{expression: string}`；字符串字面量单引号转义（见 `filterExpr.ts`）\\n- 数据源 uid=`signoz` profile=`signoz-v5`；JWT 见 `.env.local` / Vite 注入\\n- 真实样本: `artifacts/zabbix-signoz-parity/REAL-API-FULL-EXAMPLES.md`'
        }
      }
    )
  ];
  assertNoEmptyDupTargets(
    panels2.map((p) => ({
      ...p,
      targets: (p.targets || []).filter((t) => t.refId)
    })),
    uid
  );
  return {
    uid,
    title: "Live SigNoz Full (真实接口全量)",
    schemaVersion: 39,
    requireLiveFrames: true,
    tags: ["live", "signoz", "full", "real-api", "argus-aligned"],
    time: { from: "now-1h", to: "now" },
    templating: {
      list: [
        {
          name: "service",
          type: "query",
          datasource: ds(SIGNOZ_TYPE$1, dsUid),
          query: { type: "service" },
          includeAll: true,
          allValue: ""
        },
        {
          name: "metric",
          type: "query",
          datasource: ds(SIGNOZ_TYPE$1, dsUid),
          query: { type: "metric" },
          includeAll: false
        }
      ]
    },
    meta: {
      liveOnly: true,
      datasourceUid: dsUid,
      apiProfile: "signoz-v5",
      diagnostics: {
        reference: "refs/argus-web-4.0/src/views/signoz + api/signoz.ts",
        endpoints: [
          "/api/v5/query_range",
          "/api/v2/services",
          "/api/v1/fields/keys",
          "/api/v2/metrics"
        ]
      }
    },
    panels: panels2
  };
}
const LIVE_DASHBOARD_BUILDERS = {
  "live-zabbix-metrics": () => buildLiveZabbixMetrics(),
  "live-zabbix-itemid": () => buildLiveZabbixItemid(),
  "live-zabbix-text": () => buildLiveZabbixText(),
  "live-zabbix-services": () => buildLiveZabbixServices(),
  "live-zabbix-triggers": () => buildLiveZabbixTriggers(),
  "live-zabbix-problems": () => buildLiveZabbixProblems(),
  "live-zabbix-macros": () => buildLiveZabbixMacros(),
  "live-zabbix-lld": () => buildLiveZabbixLld(),
  "live-zabbix-full": () => buildLiveZabbixFull(),
  "live-signoz-native-metrics": () => buildLiveSignozNativeMetrics(),
  "live-signoz-native-logs": () => buildLiveSignozNativeLogs(),
  "live-signoz-native-traces": () => buildLiveSignozNativeTraces(),
  "live-signoz-native-query-modes": () => buildLiveSignozNativeQueryModes(),
  "live-signoz-native-results": () => buildLiveSignozNativeResults(),
  "live-signoz": () => buildLiveSignoz(),
  "live-signoz-observability": () => buildLiveSignozObservability(),
  "live-signoz-full": () => buildLiveSignozFull(),
  "live-observability-diagnostics": () => buildLiveDiagnostics()
};
const DATASOURCE_IDS = [
  "dashboard",
  "mixed",
  "grafana",
  "grafana-testdata-datasource",
  "grafana-postgresql-datasource",
  "mysql",
  "mssql",
  "influxdb",
  "graphite",
  "prometheus",
  "loki",
  "jaeger",
  "tempo",
  "grafana-pyroscope-datasource",
  "cloudwatch",
  "grafana-azure-monitor-datasource",
  "alertmanager",
  "opentelemetry",
  "alexanderzobnin-zabbix-datasource",
  "signoz"
];
const caps = (partial) => ({
  query: true,
  health: true,
  metadata: false,
  variables: false,
  annotations: false,
  exemplars: false,
  streaming: false,
  queryLanguages: [],
  ...partial
});
const HEAVY_ZABBIX = "alexanderzobnin-zabbix-datasource";
const HEAVY_SIGNOZ = "signoz";
const CATALOG = [
  {
    id: "dashboard",
    name: "仪表盘",
    category: "core",
    icon: "gf-grid",
    capabilities: caps({
      signals: ["metrics"],
      health: false,
      queryLanguages: ["dashboard"]
    })
  },
  {
    id: "mixed",
    name: "混合",
    category: "core",
    icon: "gf-glue",
    capabilities: caps({
      signals: ["metrics", "logs", "traces"],
      health: false,
      queryLanguages: ["mixed"]
    })
  },
  {
    id: "grafana",
    name: "Grafana",
    category: "core",
    icon: "grafana",
    capabilities: caps({
      signals: ["metrics"],
      queryLanguages: ["grafana"]
    })
  },
  {
    id: "grafana-testdata-datasource",
    name: "测试数据",
    category: "core",
    icon: "database",
    capabilities: caps({
      signals: ["metrics"],
      variables: true,
      annotations: true,
      queryLanguages: ["testdata"]
    })
  },
  {
    id: "grafana-postgresql-datasource",
    name: "PostgreSQL",
    category: "sql",
    icon: "postgres",
    capabilities: caps({
      signals: ["metrics"],
      variables: true,
      annotations: true,
      metadata: true,
      queryLanguages: ["sql"]
    })
  },
  {
    id: "mysql",
    name: "MySQL",
    category: "sql",
    icon: "mysql",
    capabilities: caps({
      signals: ["metrics"],
      variables: true,
      annotations: true,
      metadata: true,
      queryLanguages: ["sql"]
    })
  },
  {
    id: "mssql",
    name: "Microsoft SQL Server",
    category: "sql",
    icon: "mssql",
    capabilities: caps({
      signals: ["metrics"],
      variables: true,
      annotations: true,
      metadata: true,
      queryLanguages: ["sql"]
    })
  },
  {
    id: "influxdb",
    name: "InfluxDB",
    category: "metrics",
    icon: "influxdb",
    capabilities: caps({
      signals: ["metrics"],
      variables: true,
      annotations: true,
      metadata: true,
      queryLanguages: ["influxql", "flux"]
    })
  },
  {
    id: "graphite",
    name: "Graphite",
    category: "metrics",
    icon: "graphite",
    capabilities: caps({
      signals: ["metrics"],
      variables: true,
      annotations: true,
      metadata: true,
      queryLanguages: ["graphite"]
    })
  },
  {
    id: "prometheus",
    name: "Prometheus",
    category: "metrics",
    icon: "prometheus",
    capabilities: caps({
      signals: ["metrics"],
      variables: true,
      annotations: true,
      metadata: true,
      exemplars: true,
      queryLanguages: ["promql"]
    })
  },
  {
    id: "loki",
    name: "Loki",
    category: "logs",
    icon: "loki",
    capabilities: caps({
      signals: ["logs"],
      variables: true,
      annotations: true,
      metadata: true,
      streaming: true,
      queryLanguages: ["logql"]
    })
  },
  {
    id: "jaeger",
    name: "Jaeger",
    category: "traces",
    icon: "jaeger",
    capabilities: caps({
      signals: ["traces"],
      metadata: true,
      queryLanguages: ["jaeger"]
    })
  },
  {
    id: "tempo",
    name: "Tempo",
    category: "traces",
    icon: "tempo",
    capabilities: caps({
      signals: ["traces"],
      metadata: true,
      queryLanguages: ["traceql"]
    })
  },
  {
    id: "grafana-pyroscope-datasource",
    name: "Pyroscope",
    category: "metrics",
    icon: "pyroscope",
    capabilities: caps({
      signals: ["metrics"],
      metadata: true,
      queryLanguages: ["pyroscope"]
    })
  },
  {
    id: "cloudwatch",
    name: "CloudWatch",
    category: "cloud",
    icon: "cloudwatch",
    capabilities: caps({
      signals: ["metrics", "logs"],
      variables: true,
      annotations: true,
      metadata: true,
      queryLanguages: ["cloudwatch"]
    })
  },
  {
    id: "grafana-azure-monitor-datasource",
    name: "Azure Monitor",
    category: "cloud",
    icon: "azure",
    capabilities: caps({
      signals: ["metrics", "logs", "traces"],
      variables: true,
      annotations: true,
      metadata: true,
      queryLanguages: ["azure-monitor"]
    })
  },
  {
    id: "alertmanager",
    name: "Alertmanager",
    category: "core",
    icon: "bell",
    capabilities: caps({
      signals: ["metrics"],
      query: false,
      health: true,
      queryLanguages: []
    })
  },
  {
    id: "opentelemetry",
    name: "OpenTelemetry",
    category: "observability",
    icon: "opentelemetry",
    capabilities: caps({
      signals: ["metrics", "logs", "traces"],
      metadata: true,
      variables: true,
      queryLanguages: ["promql", "logql", "traceql"]
    })
  },
  {
    id: HEAVY_ZABBIX,
    name: "Zabbix",
    category: "observability",
    icon: "zabbix",
    capabilities: caps({
      signals: ["metrics"],
      metadata: true,
      variables: true,
      annotations: true,
      queryLanguages: ["zabbix-json-rpc"]
    }),
    lazy: async () => {
      const { registerZabbixPlugin: registerZabbixPlugin2 } = await Promise.resolve().then(() => register$1);
      await registerZabbixPlugin2();
    }
  },
  {
    id: HEAVY_SIGNOZ,
    name: "SigNoz",
    category: "observability",
    icon: "signoz",
    capabilities: caps({
      signals: ["metrics", "logs", "traces"],
      metadata: true,
      variables: true,
      annotations: true,
      streaming: true,
      queryLanguages: ["promql", "clickhouse", "trace"]
    }),
    lazy: async () => {
      const { registerSigNozPlugin: registerSigNozPlugin2 } = await Promise.resolve().then(() => register);
      await registerSigNozPlugin2();
    }
  }
];
const byId = new Map(CATALOG.map((e) => [e.id, e]));
const VISIBLE_CATALOG_IDS = /* @__PURE__ */ new Set([HEAVY_ZABBIX, HEAVY_SIGNOZ]);
function listBuiltinDatasourceCatalog() {
  return CATALOG.filter((e) => VISIBLE_CATALOG_IDS.has(e.id));
}
function getBuiltinDatasourceCatalogEntry(id) {
  return byId.get(id);
}
async function ensureDatasourceCatalogEntryRegistered(id) {
  const entry = getBuiltinDatasourceCatalogEntry(id);
  if (!entry) {
    throw new DataSourceError("NOT_FOUND", `未知数据源类型: ${id}`);
  }
  if (getDataSourcePlugin(id)) return;
  await entry.lazy?.();
  if (!getDataSourcePlugin(id)) {
    throw new Error(`数据源注册失败: ${id}`);
  }
}
function catalogCoversDatasourceIds() {
  const ids = CATALOG.map((x) => x.id).sort();
  const expected = [...DATASOURCE_IDS].sort();
  return ids.length === expected.length && ids.every((id, i) => id === expected[i]);
}
function defaultQueryForType(type, refId = "A") {
  const t = normalizeDsType(type);
  switch (t) {
    case "prometheus":
      return {
        refId,
        expr: "up",
        range: true,
        instant: false,
        exemplar: false,
        format: "time_series",
        editorMode: "code",
        datasource: { type: t }
      };
    case "loki":
      return {
        refId,
        expr: '{job="varlogs"}',
        queryType: "range",
        maxLines: 1e3,
        editorMode: "code",
        datasource: { type: t }
      };
    case "grafana-postgresql-datasource":
    case "mysql":
    case "mssql":
      return {
        refId,
        rawSql: "SELECT 1 AS value",
        format: 1,
        rawQuery: true,
        datasource: { type: t }
      };
    case "grafana-testdata-datasource":
      return {
        refId,
        scenarioId: "random_walk",
        alias: "test",
        seriesCount: 1,
        datasource: { type: t }
      };
    case "graphite":
      return {
        refId,
        target: "stats.counters.*",
        textEditor: true,
        datasource: { type: t }
      };
    case "influxdb":
      return {
        refId,
        query: "SELECT mean(value) FROM cpu",
        rawQuery: true,
        resultFormat: "time_series",
        datasource: { type: t }
      };
    case "cloudwatch":
      return {
        refId,
        queryMode: "Metrics",
        region: "default",
        namespace: "AWS/EC2",
        metricName: "CPUUtilization",
        statistic: "Average",
        period: "",
        matchExact: true,
        expression: "",
        datasource: { type: t }
      };
    case "jaeger":
      return {
        refId,
        query: "",
        service: "",
        operation: "",
        datasource: { type: t }
      };
    case "grafana-pyroscope-datasource":
      return {
        refId,
        query: "process_cpu:cpu:nanoseconds:cpu:nanoseconds{}",
        profileTypeId: "process_cpu:cpu:nanoseconds:cpu:nanoseconds",
        labelSelector: "{}",
        groupBy: [],
        datasource: { type: t }
      };
    case "grafana-azure-monitor-datasource":
      return {
        refId,
        queryType: "Azure Monitor",
        azureMonitor: {
          timeGrain: "auto",
          metricName: "",
          aggregation: "Average"
        },
        datasource: { type: t }
      };
    case "elasticsearch":
      return {
        refId,
        query: "*",
        timeField: "@timestamp",
        metrics: [{ type: "count", id: "1" }],
        bucketAggs: [
          { type: "date_histogram", id: "2", settings: { interval: "auto" } }
        ],
        datasource: { type: t }
      };
    case "tempo":
      return {
        refId,
        query: "{}",
        queryType: "traceql",
        limit: 20,
        datasource: { type: t }
      };
    case "grafana":
      return { refId, queryType: "randomWalk", datasource: { type: t } };
    case "dashboard":
      return { refId, panelId: void 0, datasource: { type: t } };
    case "alertmanager":
      return { refId, query: "", expr: "", datasource: { type: t } };
    case "mixed":
      return { refId, datasource: { type: "mixed", uid: "mixed" } };
    default:
      return { refId, query: "", datasource: t ? { type: t } : void 0 };
  }
}
function switchQueryDatasource(current, ds2) {
  const type = normalizeDsType(ds2.type);
  const base = defaultQueryForType(type, current.refId);
  return {
    ...base,
    refId: current.refId,
    hide: current.hide,
    datasource: {
      type,
      uid: ds2.uid || type,
      ...ds2.name ? { name: ds2.name } : {}
    }
  };
}
const INTERPOLATE_KEYS = [
  "expr",
  "query",
  "rawSql",
  "target",
  "alias",
  "legendFormat",
  "expression",
  "namespace",
  "metricName",
  "service",
  "operation",
  "labelSelector",
  "rawQuery",
  "rawLegend"
];
function deepReplaceStrings(value, replace, depth = 0) {
  if (depth > 12) return value;
  if (typeof value === "string") return replace(value);
  if (Array.isArray(value)) {
    return value.map((v) => deepReplaceStrings(v, replace, depth + 1));
  }
  if (value && typeof value === "object") {
    const out = {};
    for (const [k, v] of Object.entries(value)) {
      out[k] = deepReplaceStrings(v, replace, depth + 1);
    }
    return out;
  }
  return value;
}
function interpolateQuery(query, replace) {
  const deep = deepReplaceStrings(query, replace);
  const next = { ...deep };
  for (const key of INTERPOLATE_KEYS) {
    const v = next[key];
    if (typeof v === "string") next[key] = replace(v);
  }
  return next;
}
function buildPrometheusQueryBody(queries, range, opts = {}) {
  return {
    from: String(range.from),
    to: String(range.to),
    queries: queries.map((q) => ({
      ...normalizePromQuery(q),
      datasource: {
        type: "prometheus",
        uid: opts.uid ?? q.datasource?.uid ?? "prometheus"
      },
      maxDataPoints: opts.maxDataPoints ?? 1100,
      intervalMs: opts.intervalMs ?? 15e3
    }))
  };
}
function buildLokiQueryBody(queries, range, opts = {}) {
  return {
    from: String(range.from),
    to: String(range.to),
    queries: queries.map((q) => ({
      ...normalizeLokiQuery(q),
      datasource: {
        type: "loki",
        uid: opts.uid ?? q.datasource?.uid ?? "loki"
      },
      maxDataPoints: opts.maxDataPoints ?? 1100,
      intervalMs: opts.intervalMs ?? 1e3
    }))
  };
}
function buildSqlQueryBody(type, queries, range, opts = {}) {
  return {
    from: String(range.from),
    to: String(range.to),
    queries: queries.map((q) => ({
      refId: q.refId,
      rawSql: String(q.rawSql ?? "SELECT 1"),
      format: Number(q.format ?? 1),
      rawQuery: true,
      datasource: { type, uid: opts.uid ?? type }
    }))
  };
}
function buildCloudWatchQueryBody(queries, range, opts = {}) {
  return {
    from: String(range.from),
    to: String(range.to),
    queries: queries.map((q) => ({
      refId: q.refId,
      queryMode: q.queryMode ?? "Metrics",
      region: q.region ?? "default",
      namespace: q.namespace ?? "AWS/EC2",
      metricName: q.metricName ?? "CPUUtilization",
      statistic: q.statistic ?? "Average",
      dimensions: q.dimensions ?? {},
      expression: q.expression ?? "",
      datasource: { type: "cloudwatch", uid: opts.uid ?? "cloudwatch" }
    }))
  };
}
function buildInfluxQueryBody(queries, range, opts = {}) {
  return {
    from: String(range.from),
    to: String(range.to),
    queries: queries.map((q) => ({
      refId: q.refId,
      query: String(q.query ?? ""),
      rawQuery: true,
      resultFormat: q.resultFormat ?? "time_series",
      policy: q.policy ?? "default",
      datasource: { type: "influxdb", uid: opts.uid ?? "influxdb" }
    }))
  };
}
function buildGraphiteQueryBody(queries, range, opts = {}) {
  return {
    from: String(range.from),
    to: String(range.to),
    queries: queries.map((q) => ({
      refId: q.refId,
      target: String(q.target ?? ""),
      textEditor: q.textEditor !== false,
      datasource: { type: "graphite", uid: opts.uid ?? "graphite" }
    }))
  };
}
function buildJaegerQueryBody(queries, range, opts = {}) {
  return {
    from: String(range.from),
    to: String(range.to),
    queries: queries.map((q) => ({
      refId: q.refId,
      query: String(q.query ?? q.service ?? ""),
      service: q.service,
      operation: q.operation,
      datasource: { type: "jaeger", uid: opts.uid ?? "jaeger" }
    }))
  };
}
function buildPyroscopeQueryBody(queries, range, opts = {}) {
  return {
    from: String(range.from),
    to: String(range.to),
    queries: queries.map((q) => ({
      refId: q.refId,
      profileTypeId: q.profileTypeId ?? "process_cpu:cpu:nanoseconds:cpu:nanoseconds",
      labelSelector: q.labelSelector ?? "{}",
      query: String(q.query ?? ""),
      groupBy: q.groupBy ?? [],
      datasource: {
        type: "grafana-pyroscope-datasource",
        uid: opts.uid ?? "pyroscope"
      }
    }))
  };
}
function buildTestDataQueryBody(queries, range, opts = {}) {
  return {
    from: String(range.from),
    to: String(range.to),
    queries: queries.map((q) => ({
      refId: q.refId,
      scenarioId: q.scenarioId ?? "random_walk",
      alias: q.alias ?? "",
      datasource: {
        type: "grafana-testdata-datasource",
        uid: opts.uid ?? "testdata"
      }
    }))
  };
}
function buildQueryBodyForType(type, queries, range, opts = {}) {
  switch (type) {
    case "prometheus":
      return buildPrometheusQueryBody(queries, range, opts);
    case "loki":
      return buildLokiQueryBody(queries, range, opts);
    case "mysql":
    case "mssql":
    case "grafana-postgresql-datasource":
      return buildSqlQueryBody(type, queries, range, opts);
    case "cloudwatch":
      return buildCloudWatchQueryBody(queries, range, opts);
    case "influxdb":
      return buildInfluxQueryBody(queries, range, opts);
    case "graphite":
      return buildGraphiteQueryBody(queries, range, opts);
    case "jaeger":
      return buildJaegerQueryBody(queries, range, opts);
    case "grafana-pyroscope-datasource":
      return buildPyroscopeQueryBody(queries, range, opts);
    case "grafana-testdata-datasource":
      return buildTestDataQueryBody(queries, range, opts);
    default:
      return {
        from: String(range.from),
        to: String(range.to),
        queries: queries.map((q) => ({
          ...q,
          datasource: { type, uid: opts.uid ?? type }
        }))
      };
  }
}
const index = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
  __proto__: null,
  DATASOURCE_IDS,
  DS_TYPE_LABELS,
  buildQueryBodyForType,
  catalogCoversDatasourceIds,
  computeStepMs,
  createBuiltinDataSourceApi,
  createPrometheusDataSource,
  createSignozDataSource: createSignozDataSource$1,
  defaultQueryForType,
  dsTypeBadge,
  dsTypeLabel,
  ensureDatasourceCatalogEntryRegistered,
  formatDurationProm,
  formatPromLegend,
  frameFingerprint,
  getBuiltinDatasourceCatalogEntry,
  hasPrometheusDataSourceFactory,
  hasSignozDataSourceFactory,
  interpolatePromMacros,
  interpolateQuery,
  isValidPromql,
  listBuiltinDatasourceCatalog,
  mapPrometheusResponse,
  normalizeDataFrames,
  normalizeDsType,
  parseDurationMs: parseDurationMs$1,
  parsePromqlToAst,
  queryFieldFamily,
  registerPrometheusDataSourceFactory,
  registerSignozDataSourceFactory,
  resetPrometheusDataSourceFactory,
  resetSignozDataSourceFactory,
  sanitizePromqlForLezer,
  switchQueryDatasource,
  wireResponseToDataFrames
}, Symbol.toStringTag, { value: "Module" }));
let registered = false;
let heavyRegistered = false;
let heavyPromise = null;
function registerBuiltinPlugins() {
  if (registered) return;
  registerLiveDashboardBuilders(LIVE_DASHBOARD_BUILDERS);
  registered = true;
}
function isBuiltinPluginsRegistered() {
  return registered;
}
async function registerHeavyPlugins() {
  if (heavyRegistered) return;
  if (heavyPromise) return heavyPromise;
  heavyPromise = (async () => {
    const [{ registerGeomapPanel: registerGeomapPanel2 }, { ensureDatasourceCatalogEntryRegistered: ensureDatasourceCatalogEntryRegistered2 }] = await Promise.all([
      Promise.resolve().then(() => register$2),
      Promise.resolve().then(() => index)
    ]);
    await Promise.all([
      registerGeomapPanel2(),
      ensureDatasourceCatalogEntryRegistered2(
        "alexanderzobnin-zabbix-datasource"
      ),
      ensureDatasourceCatalogEntryRegistered2("signoz")
    ]);
    heavyRegistered = true;
  })();
  return heavyPromise;
}
function isHeavyPluginsRegistered() {
  return heavyRegistered;
}
const __vite_import_meta_env__$1 = { "BASE_URL": "/", "DEV": false, "MODE": "production", "PROD": true, "SSR": false };
const ZABBIX_TYPE = "alexanderzobnin-zabbix-datasource";
const SIGNOZ_TYPE = "signoz";
function defaultObservabilityDataSources(_env = {}) {
  return [];
}
function nonEmpty(v) {
  if (v == null) return void 0;
  const s = String(v).trim();
  return s.length ? s : void 0;
}
function firstEnv(env, keys) {
  for (const k of keys) {
    const v = nonEmpty(env[k]);
    if (v) return v;
  }
  return void 0;
}
function resolveSignozSessionFromEnv(env) {
  return {
    url: firstEnv(env, ["VITE_SIGNOZ_NATIVE_URL", "VITE_SIGNOZ_URL"]),
    token: firstEnv(env, [
      "VITE_SIGNOZ_NATIVE_TOKEN",
      "VITE_SIGNOZ_TOKEN",
      "SIGNOZ_TOKEN"
    ]),
    refreshToken: firstEnv(env, [
      "VITE_SIGNOZ_NATIVE_REFRESH_TOKEN",
      "VITE_SIGNOZ_REFRESH_TOKEN",
      "SIGNOZ_REFRESH_TOKEN"
    ]),
    email: firstEnv(env, ["VITE_SIGNOZ_EMAIL", "SIGNOZ_EMAIL"]),
    password: firstEnv(env, ["VITE_SIGNOZ_PASSWORD", "SIGNOZ_PASSWORD"]),
    orgID: firstEnv(env, ["VITE_SIGNOZ_ORG_ID", "SIGNOZ_ORG_ID"])
  };
}
function readEnv() {
  try {
    return { ...__vite_import_meta_env__$1 || {} };
  } catch {
    return {};
  }
}
function readWindowInjection() {
  if (typeof window === "undefined") return null;
  const w = window;
  const inj = w.__GRAFANA_VUE_DATASOURCES__;
  if (!Array.isArray(inj) || !inj.length) return null;
  return inj;
}
function mergeObservabilityDataSourceInput(prev, next) {
  if (!prev) {
    return {
      ...next,
      jsonData: next.jsonData ? { ...next.jsonData } : void 0
    };
  }
  const merged = {
    ...prev,
    ...Object.fromEntries(
      Object.entries(next).filter(
        ([key, v]) => key !== "jsonData" && v !== void 0 && v !== ""
      )
    ),
    uid: next.uid || prev.uid,
    jsonData: {
      ...prev.jsonData || {},
      ...next.jsonData || {}
    }
  };
  if (!Object.keys(merged.jsonData || {}).length && !prev.jsonData && !next.jsonData) {
    delete merged.jsonData;
  }
  return merged;
}
function mergeObservabilityDataSourceInputsByUid(...layers) {
  const byUid2 = /* @__PURE__ */ new Map();
  for (const layer of layers) {
    if (!layer?.length) continue;
    for (const row of layer) {
      if (!row?.uid) {
        throw new Error("datasource uid is required");
      }
      byUid2.set(row.uid, mergeObservabilityDataSourceInput(byUid2.get(row.uid), row));
    }
  }
  return [...byUid2.values()];
}
function buildEnvOverlay(env) {
  const envOverlay = [];
  if (nonEmpty(env.VITE_ZABBIX_URL_3) || nonEmpty(env.VITE_ZABBIX_TOKEN_3)) {
    const z3patch = {
      type: ZABBIX_TYPE,
      url: nonEmpty(env.VITE_ZABBIX_URL_3),
      token: nonEmpty(env.VITE_ZABBIX_TOKEN_3),
      credentialMode: "apiKey"
    };
    envOverlay.push({ uid: "zabbix-3", name: "Zabbix 50.3", ...z3patch });
    envOverlay.push({ uid: "zabbix", name: "Zabbix", ...z3patch });
  }
  if (nonEmpty(env.VITE_ZABBIX_URL_14) || nonEmpty(env.VITE_ZABBIX_TOKEN_14)) {
    envOverlay.push({
      uid: "zabbix-14",
      name: "Zabbix 50.14",
      type: ZABBIX_TYPE,
      url: nonEmpty(env.VITE_ZABBIX_URL_14),
      token: nonEmpty(env.VITE_ZABBIX_TOKEN_14),
      credentialMode: "apiKey"
    });
  }
  {
    const sn = resolveSignozSessionFromEnv(env);
    if (sn.url || sn.token || sn.refreshToken || sn.email || sn.password) {
      envOverlay.push({
        uid: "signoz",
        name: "SigNoz",
        type: SIGNOZ_TYPE,
        url: sn.url,
        profile: "signoz-v5",
        token: sn.token,
        refreshToken: sn.refreshToken,
        email: sn.email,
        password: sn.password,
        orgID: sn.orgID,
        credentialMode: sn.token ? "bearer" : "proxy"
      });
    }
  }
  return envOverlay;
}
function resolveObservabilityDataSources(opts = {}) {
  const env = opts.env ?? readEnv();
  const defaults2 = opts.defaults ?? defaultObservabilityDataSources(env);
  const datasources2 = opts.datasources ?? [];
  const windowInjection = opts.windowInjection !== void 0 ? opts.windowInjection : readWindowInjection();
  if (windowInjection?.length) {
    const seen = /* @__PURE__ */ new Set();
    for (const row of windowInjection) {
      if (!row?.uid) {
        throw new Error("datasource uid is required in window injection");
      }
      if (seen.has(row.uid)) {
        throw new Error(`duplicate uid in window injection: ${row.uid}`);
      }
      seen.add(row.uid);
    }
  }
  const inputs = mergeObservabilityDataSourceInputsByUid(
    defaults2,
    datasources2,
    buildEnvOverlay(env),
    windowInjection
  );
  const defaultsMarked = inputs.filter((i) => i.default || i.isDefault);
  if (defaultsMarked.length > 1) {
    throw new Error(
      `DATASOURCE_DEFAULT_CONFLICT: ${defaultsMarked.map((d) => d.uid).join(",")}`
    );
  }
  const settings = [];
  const credentials = [];
  for (const input of inputs) {
    const jsonData = { ...input.jsonData || {} };
    if (input.profile) {
      jsonData.apiProfile = input.profile;
    }
    if (input.credentialMode) {
      jsonData.credentialMode = input.credentialMode;
    }
    const explicitMode = jsonData.dataMode;
    if (explicitMode === "fixture" || explicitMode === "live") {
      jsonData.dataMode = explicitMode;
    } else if (input.token || input.password || input.refreshToken || nonEmpty(input.url)) {
      jsonData.dataMode = "live";
    } else {
      jsonData.dataMode = "fixture";
    }
    for (const k of Object.keys(jsonData)) {
      if (/token|password|secret|apiKey|authorization/i.test(k)) {
        delete jsonData[k];
      }
    }
    settings.push({
      uid: input.uid,
      name: input.name,
      type: input.type,
      url: input.url,
      access: "proxy",
      isDefault: !!(input.default || input.isDefault),
      jsonData,
      source: "runtime"
    });
    const mode2 = input.credentialMode || (input.token ? "apiKey" : "none");
    if (mode2 === "proxy" || mode2 === "none") {
      continue;
    }
    if (input.token) {
      const canSession = Boolean(input.refreshToken) || Boolean(input.email && input.password);
      if (canSession) {
        credentials.push({
          uid: input.uid,
          credential: {
            kind: "session",
            value: input.token,
            refreshToken: input.refreshToken,
            email: input.email,
            password: input.password,
            orgID: input.orgID,
            rememberPassword: Boolean(input.password)
          }
        });
      } else if (mode2 === "bearer" || mode2 === "token") {
        credentials.push({
          uid: input.uid,
          credential: { kind: "bearer", value: input.token }
        });
      } else if (mode2 === "apiKey") {
        credentials.push({
          uid: input.uid,
          credential: {
            kind: "apiKey",
            value: input.token,
            headerName: input.apiKeyHeader
          }
        });
      } else {
        credentials.push({
          uid: input.uid,
          credential: { kind: "apiKey", value: input.token }
        });
      }
    } else if (input.username || input.password) {
      credentials.push({
        uid: input.uid,
        credential: {
          kind: "basic",
          username: input.username || "",
          password: input.password || ""
        }
      });
    }
  }
  return { settings, credentials };
}
function bootstrapObservabilityDataSources(resolved) {
  const r = resolved ?? resolveObservabilityDataSources();
  configureRuntimeDataSourceSettings(r.settings);
  for (const { uid, credential } of r.credentials) {
    setRuntimeCredential(uid, credential);
    if (uid === "zabbix-3") setRuntimeCredential("zabbix", credential);
    if (uid === "signoz" || uid === "signoz-native" || uid === "signoz-argus") {
      setRuntimeCredential("signoz", credential);
      setRuntimeCredential("signoz-native", credential);
      setRuntimeCredential("signoz-argus", credential);
    }
  }
  if (typeof console !== "undefined") {
    const signoz = r.settings.find((s) => s.uid === "signoz");
    const z3 = r.settings.find((s) => s.uid === "zabbix-3");
    console.info(
      `[grafana-vue] observability datasources: ${r.settings.length}` + (z3?.url ? ` zabbix=${z3.url}` : "") + (signoz?.url ? ` signoz=${signoz.url}` : "") + (r.credentials.length ? ` credentials=${r.credentials.length}` : "")
    );
  }
  return r;
}
const __vite_import_meta_env__ = { "BASE_URL": "/", "DEV": false, "MODE": "production", "PROD": true, "SSR": false };
function resolveBackendBootSelection(input) {
  const params = new URLSearchParams(input.search ?? "");
  const env = input.env ?? {};
  const g = input.globals ?? {};
  const envMode = env.VITE_BACKEND_MODE || g.__GRAFANA_VUE_BACKEND_MODE__;
  const grafanaUrl = env.VITE_GRAFANA_URL || env.VITE_GRAFANA_API_URL || g.__GRAFANA_VUE_GRAFANA_URL__;
  const hasToken = !!(env.VITE_GRAFANA_TOKEN || env.VITE_GRAFANA_API_TOKEN || g.__GRAFANA_VUE_AUTH_TOKEN__);
  const wantLive = params.get("backend") === "live" || envMode === "live" || !!grafanaUrl || hasToken;
  if (!wantLive) {
    return { mode: "offline" };
  }
  const requireAuth = params.get("requireAuth") === "0" || params.get("requireAuth") === "false" ? false : !!(grafanaUrl || hasToken || params.get("requireAuth") === "1");
  return {
    mode: "live",
    baseUrl: grafanaUrl || "",
    requireAuth
  };
}
function bootstrapGrafanaVue(options = {}) {
  registerBuiltinPlugins();
  void registerHeavyPlugins().catch((err) => {
    if (typeof console !== "undefined") {
      console.error("[grafana-vue] heavy plugin registration failed", err);
    }
  });
  const injected = typeof window !== "undefined" ? window.grafanaBootData : void 0;
  setBootData(injected ?? createDefaultBootData());
  initTheme();
  bootBackendMode();
  bootObservabilityDataSources(options);
}
function bootObservabilityDataSources(options) {
  try {
    const hasCallerDatasources = (options.datasources?.length ?? 0) > 0;
    if (!hasCallerDatasources && listRuntimeDataSourceSettings().length > 0) {
      return;
    }
    bootstrapObservabilityDataSources(
      resolveObservabilityDataSources({
        datasources: options.datasources,
        env: options.env,
        windowInjection: options.windowInjection
      })
    );
  } catch (err) {
    if (typeof console !== "undefined") {
      console.error(
        "[grafana-vue] observability datasource bootstrap failed",
        err
      );
    }
  }
}
function bootBackendMode() {
  const env = __vite_import_meta_env__ ?? {};
  const globals = typeof globalThis !== "undefined" ? globalThis : {};
  const selection = resolveBackendBootSelection({
    search: typeof location !== "undefined" ? location.search : "",
    env,
    globals
  });
  if (selection.mode === "live") {
    configureBackendSrv({
      mode: "live",
      baseUrl: selection.baseUrl,
      requireAuth: selection.requireAuth
    });
  }
  if (typeof console !== "undefined") {
    console.info(
      `[grafana-vue] backend mode: ${getBackendMode()}${selection.mode === "live" && selection.baseUrl ? " grafana=" + selection.baseUrl : ""}`
    );
  }
}
const BUILTIN_GAZETTEER = {
  shanghai: { lat: 31.23, lon: 121.47 },
  beijing: { lat: 39.9, lon: 116.4 },
  shenzhen: { lat: 22.54, lon: 114.06 },
  hangzhou: { lat: 30.27, lon: 120.15 },
  guangzhou: { lat: 23.13, lon: 113.26 },
  chengdu: { lat: 30.57, lon: 104.07 },
  wuhan: { lat: 30.59, lon: 114.31 },
  nanjing: { lat: 32.06, lon: 118.8 },
  "new york": { lat: 40.71, lon: -74.01 },
  london: { lat: 51.51, lon: -0.13 },
  tokyo: { lat: 35.68, lon: 139.69 },
  paris: { lat: 48.86, lon: 2.35 },
  singapore: { lat: 1.35, lon: 103.82 },
  sydney: { lat: -33.87, lon: 151.21 },
  "san francisco": { lat: 37.77, lon: -122.42 }
};
function resolveGazetteerEntry(key, custom) {
  if (!key) return null;
  const k = String(key).trim().toLowerCase();
  if (custom && custom[k]) return custom[k];
  if (BUILTIN_GAZETTEER[k]) return BUILTIN_GAZETTEER[k];
  for (const [name, pt] of Object.entries(custom ?? {})) {
    if (name.includes(k) || k.includes(name)) return pt;
  }
  for (const [name, pt] of Object.entries(BUILTIN_GAZETTEER)) {
    if (name.includes(k) || k.includes(name)) return pt;
  }
  return null;
}
function parseGazetteerJson(raw) {
  if (!raw) return void 0;
  if (typeof raw === "object" && !Array.isArray(raw)) {
    const out = {};
    for (const [k, v] of Object.entries(raw)) {
      if (v && typeof v === "object" && Number.isFinite(Number(v.lat)) && Number.isFinite(Number(v.lon))) {
        out[String(k).toLowerCase()] = {
          lat: Number(v.lat),
          lon: Number(v.lon)
        };
      }
    }
    return out;
  }
  if (typeof raw === "string") {
    try {
      return parseGazetteerJson(JSON.parse(raw));
    } catch {
      return void 0;
    }
  }
  return void 0;
}
const BASE32 = "0123456789bcdefghjkmnpqrstuvwxyz";
function decodeGeohash(hash) {
  if (!hash || typeof hash !== "string") return null;
  const h = hash.toLowerCase().trim();
  if (!h.length) return null;
  let even = true;
  let latMin = -90;
  let latMax = 90;
  let lonMin = -180;
  let lonMax = 180;
  for (const ch of h) {
    const idx = BASE32.indexOf(ch);
    if (idx < 0) return null;
    for (let bit = 4; bit >= 0; bit--) {
      const bitVal = idx >> bit & 1;
      if (even) {
        const mid = (lonMin + lonMax) / 2;
        if (bitVal) lonMin = mid;
        else lonMax = mid;
      } else {
        const mid = (latMin + latMax) / 2;
        if (bitVal) latMin = mid;
        else latMax = mid;
      }
      even = !even;
    }
  }
  return { lat: (latMin + latMax) / 2, lon: (lonMin + lonMax) / 2 };
}
function findField(frame, names, fallbacks) {
  if (names) {
    for (const n of names) {
      if (!n) continue;
      const exact = frame.fields.find((f) => f.name === n);
      if (exact) return exact;
      const ci = frame.fields.find(
        (f) => f.name.toLowerCase() === n.toLowerCase()
      );
      if (ci) return ci;
    }
  }
  for (const re of fallbacks) {
    const f = frame.fields.find((fld) => re.test(fld.name));
    if (f) return f;
  }
  return void 0;
}
function resolveLocationPoints(frame, location2, layerMeta) {
  if (!frame?.fields?.length) return [];
  const mode2 = String(location2?.mode ?? "auto").toLowerCase();
  const valField = frame.fields.find(
    (f) => f.type === "number" && !/lat|lon|lng|x|y/i.test(f.name)
  ) ?? frame.fields.find((f) => f.type === "number");
  const labelField = findField(frame, void 0, [
    /name|label|city|host|service/i
  ]);
  if (mode2 === "geohash") {
    const gh = findField(
      frame,
      location2?.geohash ? [location2.geohash] : void 0,
      [/geohash|geo_hash/i]
    );
    if (!gh) return [];
    const out = [];
    for (let i = 0; i < gh.values.length; i++) {
      const decoded = decodeGeohash(String(gh.values[i] ?? ""));
      if (!decoded) continue;
      out.push({
        lon: decoded.lon,
        lat: decoded.lat,
        value: Number(valField?.values[i] ?? 1) || 1,
        label: labelField ? String(labelField.values[i] ?? "") : String(gh.values[i]),
        layerName: layerMeta?.name,
        layerType: layerMeta?.type
      });
    }
    return out;
  }
  if (mode2 === "lookup") {
    const lookupField = findField(
      frame,
      location2?.lookup ? [location2.lookup] : void 0,
      [/name|city|host|location|place|label|key/i]
    );
    if (!lookupField) return [];
    const custom = parseGazetteerJson(location2?.gazetteer);
    const out = [];
    for (let i = 0; i < lookupField.values.length; i++) {
      const key = String(lookupField.values[i] ?? "");
      const pt = resolveGazetteerEntry(key, custom);
      if (!pt) continue;
      out.push({
        lon: pt.lon,
        lat: pt.lat,
        value: Number(valField?.values[i] ?? 1) || 1,
        label: key,
        layerName: layerMeta?.name,
        layerType: layerMeta?.type
      });
    }
    return out;
  }
  if (mode2 === "coords" || mode2 === "auto") {
    const lat = findField(
      frame,
      location2?.latitude ? [location2.latitude] : void 0,
      mode2 === "coords" ? [/^lat(itude)?$/i, /lat/i] : [/lat/i, /^y$/i]
    ) ?? (mode2 === "auto" ? frame.fields.find((f) => f.name.toLowerCase() === "y") : void 0);
    const lon = findField(
      frame,
      location2?.longitude ? [location2.longitude] : void 0,
      mode2 === "coords" ? [/^lon(gitude)?$|^lng$/i, /lon|lng/i] : [/lon|lng/i, /^x$/i]
    ) ?? (mode2 === "auto" ? frame.fields.find((f) => f.name.toLowerCase() === "x") : void 0);
    if (lat && lon) {
      return lat.values.map((la, i) => ({
        lon: Number(lon.values[i]),
        lat: Number(la),
        value: Number(valField?.values[i] ?? 1) || 1,
        label: labelField ? String(labelField.values[i] ?? "") : `${Number(la).toFixed(2)},${Number(lon.values[i]).toFixed(2)}`,
        layerName: layerMeta?.name,
        layerType: layerMeta?.type
      }));
    }
    if (mode2 === "auto") {
      const gh = findField(
        frame,
        location2?.geohash ? [location2.geohash] : void 0,
        [/geohash/i]
      );
      if (gh) {
        return resolveLocationPoints(
          frame,
          { ...location2, mode: "geohash" },
          layerMeta
        );
      }
      const lookupField = findField(
        frame,
        location2?.lookup ? [location2.lookup] : void 0,
        [/name|city|host|location|place/i]
      );
      if (lookupField) {
        return resolveLocationPoints(
          frame,
          { ...location2, mode: "lookup" },
          layerMeta
        );
      }
    }
  }
  return [];
}
function matchGeomapFrameFilter(frame, filter2) {
  if (filter2 == null || filter2 === "") return true;
  if (typeof filter2 === "string") {
    const needle = filter2.trim();
    if (!needle) return true;
    const ref2 = String(frame.refId ?? "");
    const name = String(frame.name ?? "");
    if (needle.includes("|")) {
      const parts = needle.split("|").map((s) => s.trim()).filter(Boolean);
      return parts.includes(ref2) || parts.includes(name);
    }
    return ref2 === needle || name === needle;
  }
  if (typeof filter2 === "object") {
    const f = filter2;
    const id = String(f.id || "byRefId");
    const pattern = String(f.options ?? "");
    if (id === "byName" || id === "byFrameName") {
      return String(frame.name ?? "") === pattern;
    }
    return String(frame.refId ?? "") === pattern;
  }
  return true;
}
function framesForLayer(frames, layer, panelFilterData) {
  const filter2 = layer.filterData ?? panelFilterData;
  if (filter2 == null || filter2 === "") return frames;
  const filtered = frames.filter((fr) => matchGeomapFrameFilter(fr, filter2));
  return filtered.length ? filtered : frames;
}
function resolveAllLayerPoints(series, layers, panelFilterData) {
  const data = dataLayers(layers);
  const frames = series?.length ? series : [];
  return data.map((layer, idx) => {
    const scoped = framesForLayer(frames, layer, panelFilterData);
    const frame = scoped[Math.min(idx, Math.max(0, scoped.length - 1))] ?? scoped[0];
    const points = resolveLocationPoints(frame, layer.location, {
      name: layer.name,
      type: String(layer.type)
    });
    return { layer, points };
  });
}
function normalizeGeomapLayers(options = {}) {
  const raw = options.layers;
  if (Array.isArray(raw) && raw.length) {
    const layers = raw.map((l, i) => normalizeLayer(l, i));
    if (!layers.some((l) => l.type === "basemap")) {
      const basemapType2 = typeof options.basemap === "string" ? options.basemap : String(options.basemap?.type ?? "default");
      layers.unshift({
        type: "basemap",
        name: "底图",
        config: {
          basemapType: basemapType2 === "default" ? "carto" : basemapType2,
          theme: "auto",
          showLabels: true,
          ...options.basemap?.config ?? {}
        }
      });
    }
    return layers;
  }
  const basemapTypeRaw = typeof options.basemap === "string" ? options.basemap : String(options.basemap?.type ?? "default");
  const basemapType = basemapTypeRaw === "default" || !basemapTypeRaw ? "carto" : basemapTypeRaw;
  const dataLayer = {
    type: String(options.type ?? "markers"),
    name: "Layer 1",
    opacity: options.opacity != null ? Number(options.opacity) : 1,
    config: options.config ?? {},
    tooltip: true,
    location: { mode: "auto" }
  };
  const basemap = {
    type: "basemap",
    name: "底图",
    config: {
      basemapType,
      theme: "auto",
      showLabels: true,
      ...options.basemap?.config ?? {}
    }
  };
  return [basemap, dataLayer];
}
function normalizeLayer(raw, index2) {
  if (!raw || typeof raw !== "object") {
    return {
      type: "markers",
      name: `图层 ${index2 + 1}`,
      location: { mode: "auto" }
    };
  }
  const l = raw;
  const loc = l.location ?? { mode: "auto" };
  return {
    type: String(l.type ?? "markers"),
    name: typeof l.name === "string" ? l.name : `图层 ${index2 + 1}`,
    opacity: l.opacity == null ? 1 : Number(l.opacity),
    tooltip: l.tooltip !== false,
    location: {
      mode: loc.mode ?? "auto",
      latitude: loc.latitude,
      longitude: loc.longitude,
      geohash: loc.geohash,
      lookup: loc.lookup,
      gazetteer: loc.gazetteer
    },
    config: l.config ?? {},
    filterData: l.filterData
  };
}
function dataLayers(layers) {
  return layers.filter((l) => l.type !== "basemap");
}
function basemapLayer(layers) {
  return layers.find((l) => l.type === "basemap");
}
function serializeLayersIntoOptions(options, layers) {
  const base = basemapLayer(layers);
  const data = dataLayers(layers);
  const primary = data[0];
  return {
    ...options,
    layers,
    basemap: {
      type: String(
        base?.config?.basemapType ?? options.basemap?.type ?? "osm"
      ),
      config: base?.config ?? {}
    },
    type: primary?.type ?? options.type ?? "markers",
    opacity: primary?.opacity ?? options.opacity ?? 1,
    config: {
      ...options.config ?? {},
      ...primary?.config ?? {}
    }
  };
}
let shared = null;
const listeners = /* @__PURE__ */ new Set();
function getSharedMapView() {
  return shared ? { ...shared } : null;
}
function setSharedMapView(patch) {
  const next = {
    lat: Number(patch.lat ?? shared?.lat ?? 20),
    lon: Number(patch.lon ?? shared?.lon ?? 0),
    zoom: Number(patch.zoom ?? shared?.zoom ?? 2),
    updatedAt: Date.now()
  };
  shared = next;
  for (const l of listeners) l({ ...next });
  return next;
}
function subscribeSharedMapView(fn) {
  listeners.add(fn);
  return () => listeners.delete(fn);
}
const _hoisted_1$$ = ["data-zoom", "data-lat", "data-lon", "data-view-shared", "data-view-dashboard-variable", "data-view-dashboard-variable-name", "data-view-dashboard-variable-enabled", "data-mouse-wheel-zoom", "data-show-scale", "data-show-debug", "data-show-zoom", "data-show-measure", "data-show-attribution", "data-measure-mode", "data-measure-active", "data-marker-radius", "data-marker-color", "data-show-labels", "data-opacity", "data-basemap", "data-tiles-ready", "data-tooltip-mode", "data-layer-count", "data-data-layer-type", "data-data-layer-count", "data-geojson-layers", "data-heatmap-layers", "data-location-modes", "data-layer-names", "data-point-count", "data-demo", "data-config-show-legend", "data-config-crop", "data-config-shadow", "data-config-sun", "data-config-arrow", "data-config-access-token", "data-access-token-applied", "data-tile-url-has-token", "data-config-night-color", "data-config-id-field", "data-config-data-style", "data-config-edge-style", "data-config-kind", "data-config-rules", "data-config-server", "data-config-blur", "data-config-min-zoom", "data-config-max-zoom", "data-config-style", "data-config-theme", "data-config-url", "data-config-src", "data-config-border", "data-config-weight", "data-config-color", "data-config-attribution", "data-type", "data-filter-data", "data-layer-tooltip", "data-view-id", "data-view-no-repeat"];
const _hoisted_2$M = {
  key: 1,
  class: "geomap__legend",
  "data-testid": "geomap-legend"
};
const _hoisted_3$E = {
  key: 2,
  class: "geomap__fallback",
  "data-testid": "geomap-fallback"
};
const _hoisted_4$v = {
  viewBox: "0 0 100 90",
  class: "map",
  preserveAspectRatio: "none",
  role: "img",
  "aria-label": "地理地图回退"
};
const _hoisted_5$q = {
  stroke: "rgba(255,255,255,0.06)",
  "stroke-width": "0.3"
};
const _hoisted_6$m = ["y1", "y2"];
const _hoisted_7$i = ["x1", "x2"];
const _hoisted_8$c = ["cx", "cy", "r", "fill"];
const _hoisted_9$b = ["x", "y"];
const _hoisted_10$9 = {
  key: 3,
  class: "geomap__tooltip",
  "data-testid": "geomap-tooltip"
};
const _hoisted_11$8 = {
  key: 4,
  class: "geomap__debug",
  "data-testid": "geomap-debug"
};
const _hoisted_12$7 = {
  key: 5,
  class: "geomap__measure",
  "data-testid": "geomap-measure"
};
const _hoisted_13$7 = {
  key: 0,
  "data-testid": "geomap-measure-value"
};
const _hoisted_14$7 = {
  key: 6,
  class: "geomap__demo-badge",
  "data-testid": "geomap-demo-badge"
};
const _sfc_main$14 = /* @__PURE__ */ defineComponent({
  __name: "GeomapRenderer",
  props: {
    data: {},
    width: {},
    height: {},
    options: {},
    replaceVariables: { type: Function }
  },
  setup(__props) {
    let ol = null;
    async function ensureOl() {
      if (!ol) {
        ol = await Promise.resolve().then(() => olApi);
      }
      return ol;
    }
    const props = __props;
    const opts = computed(() => props.options ?? {});
    const layers = computed(() => normalizeGeomapLayers(props.options ?? {}));
    const dataLayerList = computed(() => dataLayers(layers.value));
    const geoJsonLayerCount = computed(
      () => dataLayerList.value.filter((l) => String(l.type) === "geojson").length
    );
    const heatmapLayerCount = computed(
      () => dataLayerList.value.filter((l) => String(l.type) === "heatmap").length
    );
    const baseLayerCfg = computed(() => basemapLayer(layers.value));
    const host = ref(null);
    const tilesReady = ref(false);
    const fallback = ref(false);
    const hoverLabel = ref(null);
    const measureActive = ref(false);
    const measureMode = ref("length");
    const measureText = ref(null);
    let map = null;
    let baseLayer = null;
    const dataVectorLayers = [];
    let measureSource = null;
    let measureLayer = null;
    let drawInteraction = null;
    let unsubShared = null;
    const basemapType = computed(() => {
      const base = baseLayerCfg.value;
      if (base?.config?.basemapType) {
        const t = String(base.config.basemapType);
        return t === "default" ? "carto" : t;
      }
      const b = opts.value.basemap;
      if (typeof b === "string" && b) return b === "default" ? "carto" : b;
      if (b && typeof b === "object" && b.type) {
        const t = String(b.type);
        return t === "default" || !t ? "carto" : t;
      }
      return "carto";
    });
    const dataLayerType = computed(
      () => String(dataLayerList.value[0]?.type ?? opts.value.type ?? "markers")
    );
    const markerRadius = computed(
      () => Number(
        dataLayerList.value[0]?.config?.radius ?? opts.value.config?.radius ?? 6
      )
    );
    const markerColor = computed(
      () => String(
        dataLayerList.value[0]?.config?.color ?? opts.value.config?.color ?? "rgba(61, 113, 217, 0.75)"
      )
    );
    const markerBorder = computed(
      () => String(opts.value.config?.border ?? "#8ab8ff")
    );
    const layerOpacity = computed(() => {
      const o = dataLayerList.value[0]?.opacity ?? opts.value.opacity;
      return o == null || o === "" ? 1 : Math.max(0, Math.min(1, Number(o)));
    });
    const showLabels = computed(
      () => Boolean(
        opts.value.config?.showLabels ?? dataLayerList.value[0]?.config?.showLabels
      )
    );
    const tooltipMode = computed(
      () => String(opts.value.tooltip?.mode ?? "details")
    );
    const showMeasure = computed(() => Boolean(opts.value.controls?.showMeasure));
    const panelConfig = computed(() => opts.value.config ?? {});
    const legendEnabled = computed(() => panelConfig.value.showLegend === true);
    const configCrop = computed(() => panelConfig.value.crop === true);
    const configShadow = computed(() => panelConfig.value.shadow === true);
    const configSun = computed(() => panelConfig.value.sun === true);
    const configArrow = computed(() => {
      const a = panelConfig.value.arrow;
      if (a === true || a === "true") return true;
      if (typeof a === "string" && a && a !== "false") return true;
      return a === true;
    });
    const accessToken = computed(
      () => String(panelConfig.value.accessToken ?? opts.value.accessToken ?? "")
    );
    const nightColor = computed(
      () => String(panelConfig.value.nightColor ?? "rgba(0,0,40,0.35)")
    );
    const idField = computed(
      () => String(panelConfig.value.idField ?? dataLayerList.value[0]?.config?.idField ?? "")
    );
    const dataStyle = computed(
      () => String(panelConfig.value.dataStyle ?? dataLayerList.value[0]?.config?.dataStyle ?? "")
    );
    const edgeStyle = computed(
      () => String(panelConfig.value.edgeStyle ?? dataLayerList.value[0]?.config?.edgeStyle ?? "")
    );
    const layerKind = computed(
      () => String(panelConfig.value.kind ?? dataLayerList.value[0]?.config?.kind ?? dataLayerType.value)
    );
    const layerTooltip = computed(
      () => String(opts.value["layer-tooltip"] ?? opts.value.layerTooltip ?? tooltipMode.value)
    );
    const rulesCount = computed(() => {
      const r = panelConfig.value.rules ?? dataLayerList.value[0]?.config?.rules;
      return Array.isArray(r) ? r.length : r ? 1 : 0;
    });
    const configServer = computed(
      () => String(panelConfig.value.server ?? dataLayerList.value[0]?.config?.server ?? "")
    );
    const configBlur = computed(
      () => Number(
        panelConfig.value.blur ?? dataLayerList.value[0]?.config?.blur ?? 0
      )
    );
    const configMinZoom = computed(
      () => String(panelConfig.value.minZoom ?? opts.value.view?.minZoom ?? "")
    );
    const configMaxZoom = computed(
      () => String(panelConfig.value.maxZoom ?? opts.value.view?.maxZoom ?? "")
    );
    const configStyle = computed(
      () => String(panelConfig.value.style ?? dataLayerList.value[0]?.config?.style ?? "")
    );
    const configTheme = computed(
      () => String(
        panelConfig.value.theme ?? baseLayerCfg.value?.config?.theme ?? opts.value.basemap?.config?.theme ?? ""
      )
    );
    const configUrl = computed(
      () => String(
        panelConfig.value.url ?? baseLayerCfg.value?.config?.url ?? opts.value.basemap?.config?.url ?? ""
      )
    );
    const configSrc = computed(() => {
      const s = panelConfig.value.src ?? panelConfig.value.geojson ?? dataLayerList.value[0]?.config?.src ?? dataLayerList.value[0]?.config?.geojson;
      return s == null || s === "" ? "" : "set";
    });
    const configWeight = computed(
      () => Number(
        panelConfig.value.weight ?? dataLayerList.value[0]?.config?.weight ?? 1
      )
    );
    const configAttribution = computed(
      () => String(
        panelConfig.value.attribution ?? opts.value.basemap?.config?.attribution ?? baseLayerCfg.value?.config?.attribution ?? ""
      )
    );
    const viewNoRepeat = computed(() => Boolean(opts.value.view?.noRepeat));
    const viewDashboardVariable = computed(
      () => String(opts.value.view?.dashboardVariable ?? "")
    );
    const viewDashboardVariableName = computed(
      () => String(opts.value.view?.dashboardVariableName ?? "")
    );
    const panelLayerType = computed(
      () => String(opts.value.type ?? dataLayerType.value ?? "")
    );
    const filterDataKey = computed(() => {
      const fd = opts.value.filterData ?? dataLayerList.value[0]?.filterData ?? null;
      if (fd == null || fd === "") return "";
      if (typeof fd === "string") return fd;
      if (typeof fd === "object") {
        const o = fd;
        return String(o.options ?? o.id ?? "set");
      }
      return String(fd);
    });
    const usingDemoData = computed(() => false);
    const layerPoints = computed(() => {
      const series = props.data?.series ?? [];
      return resolveAllLayerPoints(series, layers.value, opts.value.filterData);
    });
    const geoPoints = computed(() => layerPoints.value.flatMap((lp) => lp.points));
    const locationModes = computed(
      () => dataLayerList.value.map((l) => String(l.location?.mode ?? "auto")).join(",")
    );
    function resolveAccessTokenUrl(url, token) {
      if (!url) return url;
      const tok = String(token ?? "").trim();
      if (!tok) return url;
      let out = url.replace(/\{access_token\}/gi, encodeURIComponent(tok)).replace(/\{accessToken\}/g, encodeURIComponent(tok));
      if (/mapbox\.com|mapbox:\/\//i.test(out) && !/[?&]access_token=/i.test(out)) {
        out += (out.includes("?") ? "&" : "?") + `access_token=${encodeURIComponent(tok)}`;
      }
      return out;
    }
    const tileUrlResolved = computed(() => {
      const cfg = {
        ...opts.value.config ?? {},
        ...opts.value.basemap?.config ?? {},
        ...baseLayerCfg.value?.config ?? {}
      };
      const raw = String(
        cfg.url || opts.value.config?.url || ""
      );
      return resolveAccessTokenUrl(raw, accessToken.value);
    });
    function createBaseSource(type) {
      if (!ol) throw new Error("OpenLayers not loaded");
      if (type === "none") return null;
      if (type === "osm") {
        return new ol.OSM({ wrapX: !viewNoRepeat.value });
      }
      const cfg = {
        ...opts.value.config ?? {},
        ...opts.value.basemap?.config ?? {},
        ...baseLayerCfg.value?.config ?? {}
      };
      if (type === "xyz" || type === "xyztiles") {
        const rawUrl = String(
          cfg.url || opts.value.config?.url || "https://tile.openstreetmap.org/{z}/{x}/{y}.png"
        );
        const url = resolveAccessTokenUrl(rawUrl, accessToken.value);
        return new ol.XYZ({
          url,
          attributions: cfg.attribution || void 0,
          wrapX: !viewNoRepeat.value
        });
      }
      let theme = String(cfg.theme ?? "auto");
      if (!theme || theme === "auto") theme = "dark";
      const showLabels2 = cfg.showLabels !== false;
      const style = `${theme}${showLabels2 ? "_all" : "_nolabels"}`;
      const scale = typeof window !== "undefined" && window.devicePixelRatio > 1 ? "@2x" : "";
      return new ol.XYZ({
        url: `https://{1-4}.basemaps.cartocdn.com/${style}/{z}/{x}/{y}${scale}.png`,
        wrapX: !viewNoRepeat.value,
        attributions: configAttribution.value || '<a href="https://carto.com/attribution/">©CARTO</a> <a href="https://www.openstreetmap.org/copyright">©OpenStreetMap</a> contributors'
      });
    }
    const LAYER_PALETTE = [
      "rgba(61, 113, 217, 0.75)",
      "rgba(220, 80, 80, 0.75)",
      "rgba(70, 180, 100, 0.75)",
      "rgba(240, 180, 40, 0.75)",
      "rgba(160, 90, 200, 0.75)"
    ];
    function styleForLayer(layer, value, label, index2) {
      const cfg = layer.config ?? {};
      const baseR = Number(cfg.radius ?? markerRadius.value);
      const color = String(
        cfg.color ?? LAYER_PALETTE[index2 % LAYER_PALETTE.length]
      );
      const border = String(cfg.border ?? markerBorder.value);
      const blur = Number(cfg.blur ?? (layer.type === "heatmap" ? 8 : 0));
      const weight = Number(cfg.weight ?? opts.value.config?.weight ?? 1);
      const radius = baseR + Math.min(10, Math.abs(value) / 20);
      layer.opacity == null ? 1 : Math.max(0, Math.min(1, Number(layer.opacity)));
      const fillColor = color.includes("rgba") ? color : color;
      const shadowOn = cfg.shadow === true || cfg.shadow == null && panelConfig.value.shadow === true;
      const images = [];
      if (shadowOn) {
        images.push(
          new ol.Style({
            image: new ol.CircleStyle({
              radius: radius + blur + 3,
              fill: new ol.Fill({ color: "rgba(0,0,0,0.35)" })
            })
          })
        );
      }
      images.push(
        new ol.Style({
          image: new ol.CircleStyle({
            radius: radius + blur,
            fill: new ol.Fill({ color: fillColor }),
            stroke: new ol.Stroke({ color: border, width: weight })
          })
          // route layers also draw larger stroke when connected later
        })
      );
      const arrowOn = cfg.arrow === true || cfg.arrow === "true" || cfg.arrow == null && (panelConfig.value.arrow === true || panelConfig.value.arrow === "true");
      if (arrowOn) {
        images.push(
          new ol.Style({
            text: new ol.TextStyle({
              text: "➤",
              font: "12px sans-serif",
              fill: new ol.Fill({ color: border }),
              offsetY: 0
            })
          })
        );
      }
      const labelsOn = Boolean(cfg.showLabels ?? showLabels.value);
      if (labelsOn && label) {
        images.push(
          new ol.Style({
            text: new ol.TextStyle({
              text: label,
              offsetY: -(radius + 8),
              fill: new ol.Fill({ color: "#e8e9ea" }),
              stroke: new ol.Stroke({ color: "#000", width: 2 }),
              font: "11px sans-serif"
            })
          })
        );
      }
      return images;
    }
    function clearDataLayers() {
      if (!map) return;
      for (const vl of dataVectorLayers) {
        map.removeLayer(vl);
      }
      dataVectorLayers.length = 0;
    }
    function parseGeoJsonObject(raw) {
      if (!raw) return null;
      if (typeof raw === "object") return raw;
      if (typeof raw === "string") {
        try {
          return JSON.parse(raw);
        } catch {
          return null;
        }
      }
      return null;
    }
    function loadGeoJsonFeatures(layer) {
      const cfg = layer.config ?? {};
      const obj = parseGeoJsonObject(cfg.geojson ?? cfg.src ?? cfg.data);
      if (!obj) return [];
      try {
        const format = new ol.GeoJSON();
        return format.readFeatures(obj, {
          dataProjection: "EPSG:4326",
          featureProjection: "EPSG:3857"
        });
      } catch {
        return [];
      }
    }
    function syncMultiLayerFeatures() {
      if (!map) return;
      clearDataLayers();
      layerPoints.value.forEach(({ layer, points }, index2) => {
        const source = new ol.VectorSource();
        const isRoute = layer.type === "route";
        const isGeoJson = layer.type === "geojson";
        const coords = [];
        let geoJsonFeatureCount = 0;
        if (isGeoJson) {
          const feats = loadGeoJsonFeatures(layer);
          geoJsonFeatureCount = feats.length;
          const color = String(
            layer.config?.color ?? LAYER_PALETTE[index2 % LAYER_PALETTE.length]
          );
          for (const f of feats) {
            f.setStyle(
              new ol.Style({
                stroke: new ol.Stroke({
                  color,
                  width: Number(layer.config?.weight ?? 2)
                }),
                fill: new ol.Fill({
                  color: color.includes("rgba") ? color : color + "55"
                }),
                image: new ol.CircleStyle({
                  radius: Number(layer.config?.radius ?? 5),
                  fill: new ol.Fill({ color })
                })
              })
            );
            source.addFeature(f);
          }
        }
        for (const p of points) {
          if (isGeoJson && geoJsonFeatureCount) break;
          if (!Number.isFinite(p.lon) || !Number.isFinite(p.lat)) continue;
          const c = ol.fromLonLat([p.lon, p.lat]);
          coords.push(c);
          const feature = new ol.Feature({
            geometry: new ol.Point(c),
            label: p.label,
            value: p.value,
            layerName: layer.name
          });
          feature.setStyle(styleForLayer(layer, p.value, p.label, index2));
          source.addFeature(feature);
        }
        if (isRoute && coords.length >= 2) {
          const line = new ol.Feature({
            geometry: new ol.LineString(coords)
          });
          const color = String(
            layer.config?.color ?? LAYER_PALETTE[index2 % LAYER_PALETTE.length]
          );
          line.setStyle(
            new ol.Style({
              stroke: new ol.Stroke({
                color,
                width: Number(layer.config?.weight ?? 3)
              })
            })
          );
          source.addFeature(line);
        }
        const opacity = layer.opacity == null ? 1 : Math.max(0, Math.min(1, Number(layer.opacity)));
        let vl;
        if (layer.type === "heatmap") {
          vl = new ol.HeatmapLayer({
            source,
            blur: Number(layer.config?.blur ?? 15),
            radius: Number(layer.config?.radius ?? 8),
            opacity,
            weight: (feature) => {
              const v = Number(feature.get("value") ?? 1);
              return Number.isFinite(v) ? Math.max(0.05, Math.min(1, Math.abs(v) / 100)) : 0.5;
            },
            properties: { name: layer.name, type: layer.type }
          });
        } else {
          vl = new ol.VectorLayer({
            source,
            opacity,
            properties: {
              name: layer.name,
              type: layer.type,
              geoJsonFeatures: geoJsonFeatureCount
            }
          });
        }
        map.addLayer(vl);
        dataVectorLayers.push(vl);
      });
      applyView();
    }
    function resolveViewNum(raw, fallback2) {
      if (raw == null || raw === "") return fallback2;
      let s = String(raw);
      if (props.replaceVariables) {
        try {
          s = props.replaceVariables(s);
        } catch {
        }
      }
      const n = Number(s);
      return Number.isFinite(n) ? n : fallback2;
    }
    function wireSharedView() {
      if (unsubShared) {
        unsubShared();
        unsubShared = null;
      }
      if (!map) return;
      if (!opts.value.view?.shared) return;
      unsubShared = subscribeSharedMapView((sv) => {
        if (!map) return;
        const view = map.getView();
        const cur = view.getCenter();
        const curZoom = view.getZoom() ?? 2;
        const [lon, lat] = cur ? ol.toLonLat(cur) : [sv.lon, sv.lat];
        if (Math.abs(lat - sv.lat) < 1e-6 && Math.abs(lon - sv.lon) < 1e-6 && Math.abs(curZoom - sv.zoom) < 1e-6) {
          return;
        }
        view.setCenter(ol.fromLonLat([sv.lon, sv.lat]));
        view.setZoom(sv.zoom);
      });
      map.on("moveend", () => {
        if (!opts.value.view?.shared || !map) return;
        const view = map.getView();
        const c = view.getCenter();
        if (!c) return;
        const [lon, lat] = ol.toLonLat(c);
        setSharedMapView({ lat, lon, zoom: view.getZoom() ?? 2 });
      });
    }
    const MAP_CENTER_PRESETS = {
      zero: { lat: 0, lon: 0, zoom: 1 },
      coords: {},
      // use view.lat/lon/zoom
      fit: { fit: true, zoom: 15 },
      "north-america": { lat: 40, lon: -100, zoom: 4 },
      "south-america": { lat: -20, lon: -60, zoom: 3 },
      europe: { lat: 46, lon: 14, zoom: 4 },
      africa: { lat: 0, lon: 30, zoom: 3 },
      "west-asia": { lat: 26, lon: 53, zoom: 4 },
      "s-asia": { lat: 19.5, lon: 80, zoom: 4 },
      "se-asia": { lat: 10, lon: 106, zoom: 4 },
      "e-asia": { lat: 33, lon: 120, zoom: 4 },
      australia: { lat: -25, lon: 135, zoom: 4 },
      oceania: { lat: -10, lon: -140, zoom: 3 }
    };
    const resolvedMapView = computed(() => {
      const rawId = opts.value.view?.id;
      const hasCoords = opts.value.view?.lat != null || opts.value.view?.lon != null || opts.value.view?.center != null;
      const viewId = String(
        rawId ?? (hasCoords ? "coords" : "zero")
      );
      const preset = MAP_CENTER_PRESETS[viewId] ?? MAP_CENTER_PRESETS.coords;
      let zoom = resolveViewNum(
        opts.value.view?.zoom ?? preset?.zoom,
        preset?.zoom ?? 1
      );
      let lat = resolveViewNum(
        opts.value.view?.lat ?? opts.value.view?.center?.[1] ?? preset?.lat,
        preset?.lat ?? 0
      );
      let lon = resolveViewNum(
        opts.value.view?.lon ?? opts.value.view?.center?.[0] ?? preset?.lon,
        preset?.lon ?? 0
      );
      if (preset && preset.lat != null && viewId !== "coords" && viewId !== "fit" && viewId !== "zero") {
        lat = preset.lat;
        lon = preset.lon ?? 0;
        if (preset.zoom != null && opts.value.view?.zoom == null) zoom = preset.zoom;
      }
      if (viewId === "zero") {
        lat = 0;
        lon = 0;
        zoom = resolveViewNum(opts.value.view?.zoom, preset?.zoom ?? 1);
      }
      return { id: viewId, lat, lon, zoom, fit: viewId === "fit" || !!preset?.fit };
    });
    function fitViewToData(view, maxZoom) {
      const coords = geoPoints.value.filter((p) => Number.isFinite(p.lon) && Number.isFinite(p.lat)).map((p) => ol.fromLonLat([p.lon, p.lat]));
      if (!coords.length) {
        view.setCenter(ol.fromLonLat([0, 0]));
        view.setZoom(1);
        return;
      }
      if (coords.length === 1) {
        view.setCenter(coords[0]);
        view.setZoom(Math.min(maxZoom, 8));
        return;
      }
      let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
      for (const c of coords) {
        minX = Math.min(minX, c[0]);
        minY = Math.min(minY, c[1]);
        maxX = Math.max(maxX, c[0]);
        maxY = Math.max(maxY, c[1]);
      }
      const extent = [minX, minY, maxX, maxY];
      try {
        view.fit(extent, { padding: [40, 40, 40, 40], maxZoom, duration: 0 });
      } catch {
        const cx = (minX + maxX) / 2;
        const cy = (minY + maxY) / 2;
        view.setCenter([cx, cy]);
        view.setZoom(Math.min(maxZoom, 4));
      }
    }
    function applyView() {
      if (!map) return;
      const view = map.getView();
      const rv = resolvedMapView.value;
      const viewId = rv.id;
      const preset = MAP_CENTER_PRESETS[viewId] ?? MAP_CENTER_PRESETS.coords;
      let zoom = rv.zoom;
      let lat = rv.lat;
      let lon = rv.lon;
      const shared2 = Boolean(opts.value.view?.shared);
      if (shared2 && viewId !== "fit") {
        const sv = getSharedMapView();
        if (sv) {
          lat = sv.lat;
          lon = sv.lon;
          zoom = sv.zoom;
        } else {
          setSharedMapView({ lat, lon, zoom });
        }
      }
      if (viewId === "fit" || preset?.fit) {
        fitViewToData(view, zoom || 15);
      } else if (Number.isFinite(lat) && Number.isFinite(lon)) {
        view.setCenter(ol.fromLonLat([lon, lat]));
        view.setZoom(zoom);
        if (shared2) setSharedMapView({ lat, lon, zoom });
      } else if (geoPoints.value.length) {
        fitViewToData(view, Math.max(zoom, 4));
      }
      const minZ = opts.value.config?.minZoom;
      const maxZ = opts.value.config?.maxZoom;
      if (minZ != null && minZ !== "") view.setMinZoom(Number(minZ));
      if (maxZ != null && maxZ !== "") view.setMaxZoom(Number(maxZ));
    }
    function applyControls() {
      if (!map) return;
      const c = opts.value.controls ?? {};
      const controls = map.getControls();
      controls.clear();
      if (c.showZoom !== false) controls.push(new ol.Zoom());
      if (c.showScale) controls.push(new ol.ScaleLine());
      if (c.showAttribution !== false)
        controls.push(new ol.Attribution({ collapsible: true, collapsed: true }));
      try {
        const interactions = map.getInteractions().getArray();
        for (const it of interactions) {
          if (String(it.constructor.name).toLowerCase().includes("mousewheel")) {
            it.setActive(c.mouseWheelZoom !== false);
          }
        }
      } catch {
      }
      if (!c.showMeasure) {
        stopMeasure();
      }
    }
    function applyBasemap() {
      if (!map) return;
      const type = basemapType.value;
      const src = createBaseSource(type);
      if (baseLayer) {
        map.removeLayer(baseLayer);
        baseLayer = null;
      }
      if (src) {
        baseLayer = new ol.TileLayer({ source: src });
        map.getLayers().insertAt(0, baseLayer);
      }
    }
    function formatLength(line) {
      const len = ol.getLength(line);
      if (len > 1e3) return `${(len / 1e3).toFixed(2)} km`;
      return `${len.toFixed(0)} m`;
    }
    function formatArea(poly) {
      const area = ol.getArea(poly);
      if (area > 1e6) return `${(area / 1e6).toFixed(2)} km²`;
      return `${area.toFixed(0)} m²`;
    }
    function stopMeasure() {
      measureActive.value = false;
      measureText.value = null;
      if (map && drawInteraction) {
        map.removeInteraction(drawInteraction);
        drawInteraction = null;
      }
      if (map && measureLayer) {
        map.removeLayer(measureLayer);
        measureLayer = null;
      }
      measureSource = null;
    }
    function startMeasure(mode2 = measureMode.value) {
      if (!map) return;
      stopMeasure();
      measureMode.value = mode2;
      measureActive.value = true;
      measureSource = new ol.VectorSource();
      measureLayer = new ol.VectorLayer({
        source: measureSource,
        style: new ol.Style({
          stroke: new ol.Stroke({ color: "#f5a623", width: 2, lineDash: [6, 4] }),
          fill: new ol.Fill({ color: "rgba(245, 166, 35, 0.15)" }),
          image: new ol.CircleStyle({
            radius: 4,
            fill: new ol.Fill({ color: "#f5a623" })
          })
        })
      });
      map.addLayer(measureLayer);
      drawInteraction = new ol.Draw({
        source: measureSource,
        type: mode2 === "area" ? "Polygon" : "LineString"
      });
      drawInteraction.on("drawend", (evt) => {
        const geom = evt.feature.getGeometry();
        if (mode2 === "area" && geom instanceof ol.Polygon) {
          measureText.value = formatArea(geom);
        } else if (geom instanceof ol.LineString) {
          measureText.value = formatLength(geom);
        }
      });
      map.addInteraction(drawInteraction);
    }
    function toggleMeasure(mode2 = "length") {
      if (measureActive.value && measureMode.value === mode2) stopMeasure();
      else startMeasure(mode2);
    }
    function buildMap() {
      if (!host.value) return;
      try {
        const c = opts.value.controls ?? {};
        const controls = ol.defaultControls({
          zoom: c.showZoom !== false,
          attribution: false,
          // add Attribution manually collapsed
          rotate: false
        });
        if (c.showAttribution !== false) {
          controls.push(
            new ol.Attribution({ collapsible: true, collapsed: true })
          );
        }
        if (c.showScale) controls.push(new ol.ScaleLine());
        baseLayer = null;
        const src = createBaseSource(basemapType.value);
        const mapLayers = [];
        if (src) {
          baseLayer = new ol.TileLayer({ source: src });
          mapLayers.push(baseLayer);
        }
        map = new ol.Map({
          target: host.value,
          layers: mapLayers,
          view: new ol.View({
            center: ol.fromLonLat([
              Number(opts.value.view?.lon ?? opts.value.view?.center?.[0] ?? 0),
              Number(opts.value.view?.lat ?? opts.value.view?.center?.[1] ?? 0)
            ]),
            zoom: Number(opts.value.view?.zoom ?? 1)
          }),
          controls
        });
        map.on("pointermove", (evt) => {
          if (tooltipMode.value === "none" || measureActive.value) {
            hoverLabel.value = null;
            return;
          }
          const feature = map.forEachFeatureAtPixel(evt.pixel, (f) => f);
          if (feature && feature.get("label") != null) {
            const layerName = feature.get("layerName");
            const val = feature.get("value");
            hoverLabel.value = layerName ? `${layerName}: ${feature.get("label")}${val != null ? ` (${val})` : ""}` : String(feature.get("label"));
          } else {
            hoverLabel.value = null;
          }
        });
        syncMultiLayerFeatures();
        wireSharedView();
        applyControls();
        fallback.value = false;
        requestAnimationFrame(() => {
          map?.updateSize();
          applyView();
        });
        setTimeout(() => {
          map?.updateSize();
          applyView();
        }, 50);
        tilesReady.value = false;
        if (baseLayer) {
          const src2 = baseLayer.getSource?.();
          if (src2 && typeof src2.on === "function") {
            let pending = 0;
            const mark = () => {
              if (pending <= 0) tilesReady.value = true;
            };
            src2.on("tileloadstart", () => {
              pending += 1;
              tilesReady.value = false;
            });
            src2.on("tileloadend", () => {
              pending = Math.max(0, pending - 1);
              mark();
            });
            src2.on("tileloaderror", () => {
              pending = Math.max(0, pending - 1);
              mark();
            });
            setTimeout(() => {
              if (pending === 0) tilesReady.value = true;
            }, 1500);
            setTimeout(() => {
              tilesReady.value = true;
            }, 2500);
          } else {
            tilesReady.value = true;
          }
        } else {
          tilesReady.value = true;
        }
      } catch {
        fallback.value = true;
        map = null;
        tilesReady.value = true;
      }
    }
    function resize() {
      map?.updateSize();
    }
    function destroyMap() {
      stopMeasure();
      clearDataLayers();
      if (map) {
        map.setTarget(void 0);
        map = null;
      }
      baseLayer = null;
    }
    onMounted(() => {
      void (async () => {
        try {
          await ensureOl();
          buildMap();
          resize();
        } catch (e) {
          fallback.value = true;
          if (typeof console !== "undefined")
            console.error("[geomap] OpenLayers load failed", e);
        }
      })();
    });
    onBeforeUnmount(() => {
      if (unsubShared) {
        unsubShared();
        unsubShared = null;
      }
      destroyMap();
    });
    watch(
      () => [props.width, props.height],
      () => resize()
    );
    watch(
      () => props.options,
      () => {
        void (async () => {
          await ensureOl();
          if (!map) {
            buildMap();
            return;
          }
          applyBasemap();
          applyControls();
          syncMultiLayerFeatures();
          wireSharedView();
          applyView();
        })();
      },
      { deep: true }
    );
    watch(
      () => props.data,
      () => {
        if (!ol || !map) return;
        syncMultiLayerFeatures();
      },
      { deep: true }
    );
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", {
        class: normalizeClass(["geomap", { "geomap--crop": configCrop.value, "geomap--sun": configSun.value }]),
        "data-testid": "panel-geomap",
        "data-zoom": String(resolvedMapView.value.zoom),
        "data-lat": String(resolvedMapView.value.lat),
        "data-lon": String(resolvedMapView.value.lon),
        "data-view-shared": String(Boolean(opts.value.view?.shared)),
        "data-view-dashboard-variable": viewDashboardVariable.value || viewDashboardVariableName.value,
        "data-view-dashboard-variable-name": viewDashboardVariableName.value,
        "data-view-dashboard-variable-enabled": String(Boolean(viewDashboardVariable.value || viewDashboardVariableName.value)),
        "data-mouse-wheel-zoom": String(opts.value.controls?.mouseWheelZoom !== false),
        "data-show-scale": String(Boolean(opts.value.controls?.showScale)),
        "data-show-debug": String(Boolean(opts.value.controls?.showDebug)),
        "data-show-zoom": String(opts.value.controls?.showZoom !== false),
        "data-show-measure": String(Boolean(opts.value.controls?.showMeasure)),
        "data-show-attribution": String(opts.value.controls?.showAttribution !== false),
        "data-measure-mode": measureMode.value,
        "data-measure-active": String(measureActive.value),
        "data-marker-radius": String(markerRadius.value),
        "data-marker-color": String(markerColor.value),
        "data-show-labels": String(showLabels.value),
        "data-opacity": String(layerOpacity.value),
        "data-basemap": basemapType.value,
        "data-tiles-ready": tilesReady.value ? "1" : "0",
        "data-tooltip-mode": tooltipMode.value,
        "data-layer-count": String(layers.value.length),
        "data-data-layer-type": dataLayerType.value,
        "data-data-layer-count": String(dataLayerList.value.length),
        "data-geojson-layers": String(geoJsonLayerCount.value),
        "data-heatmap-layers": String(heatmapLayerCount.value),
        "data-location-modes": locationModes.value,
        "data-layer-names": layers.value.map((l) => l.name || l.type).join(","),
        "data-point-count": String(geoPoints.value.length),
        "data-demo": String(usingDemoData.value),
        "data-config-show-legend": String(legendEnabled.value),
        "data-config-crop": String(configCrop.value),
        "data-config-shadow": String(configShadow.value),
        "data-config-sun": String(configSun.value),
        "data-config-arrow": String(configArrow.value),
        "data-config-access-token": accessToken.value ? "set" : "",
        "data-access-token-applied": accessToken.value && tileUrlResolved.value.includes(encodeURIComponent(accessToken.value)) ? "1" : accessToken.value && tileUrlResolved.value.includes(accessToken.value) ? "1" : "",
        "data-tile-url-has-token": tileUrlResolved.value && (tileUrlResolved.value.includes("access_token") || !!accessToken.value && tileUrlResolved.value.includes(encodeURIComponent(accessToken.value))) ? "1" : "",
        "data-config-night-color": nightColor.value,
        "data-config-id-field": idField.value,
        "data-config-data-style": dataStyle.value,
        "data-config-edge-style": edgeStyle.value,
        "data-config-kind": layerKind.value,
        "data-config-rules": String(rulesCount.value),
        "data-config-server": configServer.value,
        "data-config-blur": String(configBlur.value),
        "data-config-min-zoom": configMinZoom.value,
        "data-config-max-zoom": configMaxZoom.value,
        "data-config-style": configStyle.value,
        "data-config-theme": configTheme.value,
        "data-config-url": configUrl.value ? "set" : "",
        "data-config-src": configSrc.value,
        "data-config-border": markerBorder.value,
        "data-config-weight": String(configWeight.value),
        "data-config-color": markerColor.value,
        "data-config-attribution": configAttribution.value,
        "data-type": panelLayerType.value,
        "data-filter-data": filterDataKey.value,
        "data-layer-tooltip": layerTooltip.value,
        "data-view-id": String(resolvedMapView.value.id),
        "data-view-no-repeat": String(viewNoRepeat.value)
      }, [
        withDirectives(createElementVNode(
          "div",
          {
            ref_key: "host",
            ref: host,
            class: "geomap__map",
            role: "img",
            "aria-label": "地理地图"
          },
          null,
          512
          /* NEED_PATCH */
        ), [
          [vShow, !fallback.value]
        ]),
        configSun.value && !fallback.value ? (openBlock(), createElementBlock(
          "div",
          {
            key: 0,
            class: "geomap__sun",
            "data-testid": "geomap-sun",
            style: normalizeStyle({ background: nightColor.value })
          },
          null,
          4
          /* STYLE */
        )) : createCommentVNode("v-if", true),
        legendEnabled.value && dataLayerList.value.length ? (openBlock(), createElementBlock("ul", _hoisted_2$M, [
          (openBlock(true), createElementBlock(
            Fragment,
            null,
            renderList(dataLayerList.value, (l, i) => {
              return openBlock(), createElementBlock("li", { key: i }, [
                createElementVNode(
                  "i",
                  {
                    style: normalizeStyle({
                      background: String(l.config?.color || LAYER_PALETTE[i % LAYER_PALETTE.length])
                    })
                  },
                  null,
                  4
                  /* STYLE */
                ),
                createTextVNode(
                  " " + toDisplayString(l.name || l.type || "图层 " + (i + 1)),
                  1
                  /* TEXT */
                )
              ]);
            }),
            128
            /* KEYED_FRAGMENT */
          ))
        ])) : createCommentVNode("v-if", true),
        fallback.value ? (openBlock(), createElementBlock("div", _hoisted_3$E, [
          (openBlock(), createElementBlock("svg", _hoisted_4$v, [
            _cache[2] || (_cache[2] = createElementVNode(
              "defs",
              null,
              [
                createElementVNode("linearGradient", {
                  id: "ocean",
                  x1: "0",
                  y1: "0",
                  x2: "0",
                  y2: "1"
                }, [
                  createElementVNode("stop", {
                    offset: "0%",
                    "stop-color": "#0d2137"
                  }),
                  createElementVNode("stop", {
                    offset: "100%",
                    "stop-color": "#0b1a2a"
                  })
                ])
              ],
              -1
              /* CACHED */
            )),
            _cache[3] || (_cache[3] = createElementVNode(
              "rect",
              {
                x: "0",
                y: "0",
                width: "100",
                height: "90",
                fill: "url(#ocean)"
              },
              null,
              -1
              /* CACHED */
            )),
            createCommentVNode(" simple lat/lon grid "),
            createElementVNode("g", _hoisted_5$q, [
              (openBlock(), createElementBlock(
                Fragment,
                null,
                renderList(5, (g) => {
                  return createElementVNode("line", {
                    key: "h" + g,
                    x1: "0",
                    y1: g * 15,
                    x2: "100",
                    y2: g * 15
                  }, null, 8, _hoisted_6$m);
                }),
                64
                /* STABLE_FRAGMENT */
              )),
              (openBlock(), createElementBlock(
                Fragment,
                null,
                renderList(6, (g) => {
                  return createElementVNode("line", {
                    key: "v" + g,
                    x1: g * 14.28,
                    y1: "0",
                    x2: g * 14.28,
                    y2: "90"
                  }, null, 8, _hoisted_7$i);
                }),
                64
                /* STABLE_FRAGMENT */
              ))
            ]),
            (openBlock(true), createElementBlock(
              Fragment,
              null,
              renderList(geoPoints.value, (p, i) => {
                return openBlock(), createElementBlock("g", { key: i }, [
                  createElementVNode("circle", {
                    cx: (p.lon + 180) / 360 * 100,
                    cy: (90 - p.lat) / 180 * 90,
                    r: Math.max(1.2, markerRadius.value / 2),
                    fill: markerColor.value,
                    stroke: "rgba(255,255,255,0.35)",
                    "stroke-width": "0.3"
                  }, null, 8, _hoisted_8$c),
                  showLabels.value && p.label ? (openBlock(), createElementBlock("text", {
                    key: 0,
                    x: (p.lon + 180) / 360 * 100,
                    y: (90 - p.lat) / 180 * 90 - (markerRadius.value / 2 + 1.5),
                    "text-anchor": "middle",
                    "font-size": "2.8",
                    fill: "var(--grafana-text)"
                  }, toDisplayString(p.label), 9, _hoisted_9$b)) : createCommentVNode("v-if", true)
                ]);
              }),
              128
              /* KEYED_FRAGMENT */
            ))
          ])),
          _cache[4] || (_cache[4] = createElementVNode(
            "div",
            { class: "geomap__fallback-hint" },
            "地图引擎不可用 · 使用 SVG 回退",
            -1
            /* CACHED */
          ))
        ])) : createCommentVNode("v-if", true),
        hoverLabel.value && tooltipMode.value !== "none" ? (openBlock(), createElementBlock(
          "div",
          _hoisted_10$9,
          toDisplayString(hoverLabel.value),
          1
          /* TEXT */
        )) : createCommentVNode("v-if", true),
        opts.value.controls?.showDebug ? (openBlock(), createElementBlock(
          "div",
          _hoisted_11$8,
          " z=" + toDisplayString(opts.value.view?.zoom ?? 2) + " · " + toDisplayString(basemapType.value) + " · " + toDisplayString(geoPoints.value.length) + " pts · 层 " + toDisplayString(dataLayerList.value.length),
          1
          /* TEXT */
        )) : createCommentVNode("v-if", true),
        showMeasure.value ? (openBlock(), createElementBlock("div", _hoisted_12$7, [
          createElementVNode(
            "button",
            {
              type: "button",
              "data-testid": "geomap-measure-toggle",
              onClick: _cache[0] || (_cache[0] = ($event) => toggleMeasure("length"))
            },
            toDisplayString(measureActive.value && measureMode.value === "length" ? "结束测距" : "测距"),
            1
            /* TEXT */
          ),
          createElementVNode(
            "button",
            {
              type: "button",
              "data-testid": "geomap-measure-area",
              onClick: _cache[1] || (_cache[1] = ($event) => toggleMeasure("area"))
            },
            toDisplayString(measureActive.value && measureMode.value === "area" ? "结束测面" : "测面积"),
            1
            /* TEXT */
          ),
          measureText.value ? (openBlock(), createElementBlock(
            "span",
            _hoisted_13$7,
            toDisplayString(measureText.value),
            1
            /* TEXT */
          )) : createCommentVNode("v-if", true)
        ])) : createCommentVNode("v-if", true),
        usingDemoData.value ? (openBlock(), createElementBlock("div", _hoisted_14$7, " 演示数据 ")) : createCommentVNode("v-if", true),
        createCommentVNode(" Grafana has no footer meta strip; keep data attrs on root for tests ")
      ], 10, _hoisted_1$$);
    };
  }
});
const GeomapRenderer = /* @__PURE__ */ _export_sfc(_sfc_main$14, [["__scopeId", "data-v-d4291708"]]);
const _sfc_main$13 = /* @__PURE__ */ defineComponent({
  __name: "Panel",
  props: {
    id: {},
    data: {},
    options: {},
    fieldConfig: {},
    width: {},
    height: {},
    timeRange: {},
    replaceVariables: { type: Function },
    title: {},
    transparent: { type: Boolean },
    editable: { type: Boolean }
  },
  setup(__props) {
    return (_ctx, _cache) => {
      return openBlock(), createBlock(GeomapRenderer, {
        data: __props.data,
        options: __props.options,
        "field-config": __props.fieldConfig,
        "replace-variables": __props.replaceVariables,
        width: __props.width,
        height: __props.height
      }, null, 8, ["data", "options", "field-config", "replace-variables", "width", "height"]);
    };
  }
});
const _hoisted_1$_ = {
  class: "geomap-layers-editor",
  "data-testid": "geomap-layers-editor"
};
const _hoisted_2$L = { class: "head" };
const _hoisted_3$D = ["data-testid"];
const _hoisted_4$u = { class: "layer-head" };
const _hoisted_5$p = { class: "row" };
const _hoisted_6$l = { class: "row" };
const _hoisted_7$h = {
  key: 0,
  class: "row"
};
const _hoisted_8$b = { class: "row" };
const _hoisted_9$a = {
  key: 0,
  class: "row cols"
};
const _hoisted_10$8 = {
  key: 1,
  class: "row"
};
const _hoisted_11$7 = {
  key: 2,
  class: "row cols"
};
const _hoisted_12$6 = {
  key: 3,
  class: "row"
};
const _hoisted_13$6 = { class: "row cols" };
const _hoisted_14$6 = { class: "switch-row" };
const _sfc_main$12 = /* @__PURE__ */ defineComponent({
  __name: "GeomapLayersEditor",
  props: {
    options: {},
    onChange: { type: Function }
  },
  setup(__props) {
    const props = __props;
    const layers = computed(() => normalizeGeomapLayers(props.options ?? {}));
    const typeOptions = [
      { label: "底图", value: "basemap" },
      { label: "标记", value: "markers" },
      { label: "热力", value: "heatmap" },
      { label: "路径", value: "route" },
      { label: "GeoJSON", value: "geojson" },
      { label: "照片", value: "photos" }
    ];
    const locationModes = [
      { label: "自动", value: "auto" },
      { label: "坐标字段", value: "coords" },
      { label: "Geohash", value: "geohash" },
      { label: "查找表", value: "lookup" }
    ];
    const basemapTypes = [
      { label: "OpenStreetMap", value: "osm" },
      { label: "XYZ 瓦片", value: "xyz" },
      { label: "无底图", value: "none" }
    ];
    function commit(next) {
      props.onChange(serializeLayersIntoOptions(props.options ?? {}, next));
    }
    function updateLayer(index2, patch) {
      const next = layers.value.map(
        (l, i) => i === index2 ? { ...l, ...patch } : l
      );
      commit(next);
    }
    function updateLocation(index2, patch) {
      const layer = layers.value[index2];
      updateLayer(index2, { location: { ...layer.location ?? {}, ...patch } });
    }
    function updateConfig(index2, patch) {
      const layer = layers.value[index2];
      updateLayer(index2, { config: { ...layer.config ?? {}, ...patch } });
    }
    function addLayer() {
      commit([
        ...layers.value,
        {
          type: "markers",
          name: `数据层 ${layers.value.length}`,
          opacity: 1,
          tooltip: true,
          location: { mode: "auto" },
          config: { radius: 6 }
        }
      ]);
    }
    function removeLayer(index2) {
      if (layers.value.length <= 1) return;
      commit(layers.value.filter((_, i) => i !== index2));
    }
    function moveLayer(index2, dir) {
      const j = index2 + dir;
      if (j < 0 || j >= layers.value.length) return;
      const next = [...layers.value];
      const tmp = next[index2];
      next[index2] = next[j];
      next[j] = tmp;
      commit(next);
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$_, [
        createElementVNode("div", _hoisted_2$L, [
          _cache[1] || (_cache[1] = createElementVNode(
            "strong",
            null,
            "图层",
            -1
            /* CACHED */
          )),
          createVNode(unref(Button), {
            size: "small",
            type: "primary",
            "data-testid": "geomap-add-layer",
            onClick: addLayer
          }, {
            default: withCtx(() => [..._cache[0] || (_cache[0] = [
              createTextVNode(
                "添加图层",
                -1
                /* CACHED */
              )
            ])]),
            _: 1
            /* STABLE */
          })
        ]),
        (openBlock(true), createElementBlock(
          Fragment,
          null,
          renderList(layers.value, (layer, i) => {
            return openBlock(), createElementBlock("div", {
              key: i,
              class: "layer-card",
              "data-testid": `geomap-layer-${i}`
            }, [
              createElementVNode("div", _hoisted_4$u, [
                createVNode(unref(Input), {
                  value: layer.name,
                  placeholder: "图层名称",
                  "data-testid": "geomap-layer-name",
                  "onUpdate:value": ($event) => updateLayer(i, { name: $event })
                }, null, 8, ["value", "onUpdate:value"]),
                createVNode(unref(Select), {
                  style: { "width": "120px" },
                  value: layer.type,
                  options: typeOptions,
                  "data-testid": "geomap-layer-type",
                  "onUpdate:value": ($event) => updateLayer(i, { type: String($event) })
                }, null, 8, ["value", "onUpdate:value"]),
                createVNode(unref(Button), {
                  size: "small",
                  disabled: i === 0,
                  onClick: ($event) => moveLayer(i, -1)
                }, {
                  default: withCtx(() => [..._cache[2] || (_cache[2] = [
                    createTextVNode(
                      "↑",
                      -1
                      /* CACHED */
                    )
                  ])]),
                  _: 1
                  /* STABLE */
                }, 8, ["disabled", "onClick"]),
                createVNode(unref(Button), {
                  size: "small",
                  disabled: i === layers.value.length - 1,
                  onClick: ($event) => moveLayer(i, 1)
                }, {
                  default: withCtx(() => [..._cache[3] || (_cache[3] = [
                    createTextVNode(
                      "↓",
                      -1
                      /* CACHED */
                    )
                  ])]),
                  _: 1
                  /* STABLE */
                }, 8, ["disabled", "onClick"]),
                createVNode(unref(Button), {
                  size: "small",
                  danger: "",
                  disabled: layers.value.length <= 1,
                  onClick: ($event) => removeLayer(i)
                }, {
                  default: withCtx(() => [..._cache[4] || (_cache[4] = [
                    createTextVNode(
                      "删除",
                      -1
                      /* CACHED */
                    )
                  ])]),
                  _: 1
                  /* STABLE */
                }, 8, ["disabled", "onClick"])
              ]),
              createElementVNode("div", _hoisted_5$p, [
                _cache[5] || (_cache[5] = createElementVNode(
                  "label",
                  null,
                  "不透明度",
                  -1
                  /* CACHED */
                )),
                createVNode(unref(InputNumber), {
                  min: 0,
                  max: 1,
                  step: 0.1,
                  value: layer.opacity ?? 1,
                  "data-testid": "geomap-layer-opacity",
                  "onUpdate:value": ($event) => updateLayer(i, { opacity: Number($event ?? 1) })
                }, null, 8, ["value", "onUpdate:value"]),
                _cache[6] || (_cache[6] = createElementVNode(
                  "label",
                  null,
                  "提示",
                  -1
                  /* CACHED */
                )),
                createVNode(unref(Switch), {
                  checked: layer.tooltip !== false,
                  "onUpdate:checked": (v) => updateLayer(i, { tooltip: v === true || v === "true" })
                }, null, 8, ["checked", "onUpdate:checked"])
              ]),
              layer.type === "basemap" ? (openBlock(), createElementBlock(
                Fragment,
                { key: 0 },
                [
                  createElementVNode("div", _hoisted_6$l, [
                    _cache[7] || (_cache[7] = createElementVNode(
                      "label",
                      null,
                      "底图类型",
                      -1
                      /* CACHED */
                    )),
                    createVNode(unref(Select), {
                      style: { "width": "160px" },
                      value: String(layer.config?.basemapType ?? "osm"),
                      options: basemapTypes,
                      "data-testid": "geomap-basemap-type",
                      "onUpdate:value": ($event) => updateConfig(i, { basemapType: $event })
                    }, null, 8, ["value", "onUpdate:value"])
                  ]),
                  String(layer.config?.basemapType) === "xyz" ? (openBlock(), createElementBlock("div", _hoisted_7$h, [
                    _cache[8] || (_cache[8] = createElementVNode(
                      "label",
                      null,
                      "XYZ URL",
                      -1
                      /* CACHED */
                    )),
                    createVNode(unref(Input), {
                      value: String(layer.config?.url ?? ""),
                      placeholder: "https://…/{z}/{x}/{y}.png",
                      "onUpdate:value": ($event) => updateConfig(i, { url: $event })
                    }, null, 8, ["value", "onUpdate:value"])
                  ])) : createCommentVNode("v-if", true)
                ],
                64
                /* STABLE_FRAGMENT */
              )) : (openBlock(), createElementBlock(
                Fragment,
                { key: 1 },
                [
                  createElementVNode("div", _hoisted_8$b, [
                    _cache[9] || (_cache[9] = createElementVNode(
                      "label",
                      null,
                      "位置模式",
                      -1
                      /* CACHED */
                    )),
                    createVNode(unref(Select), {
                      style: { "width": "140px" },
                      value: String(layer.location?.mode ?? "auto"),
                      options: locationModes,
                      "data-testid": "geomap-location-mode",
                      "onUpdate:value": ($event) => updateLocation(i, { mode: $event })
                    }, null, 8, ["value", "onUpdate:value"])
                  ]),
                  String(layer.location?.mode) === "coords" ? (openBlock(), createElementBlock("div", _hoisted_9$a, [
                    createElementVNode("div", null, [
                      _cache[10] || (_cache[10] = createElementVNode(
                        "label",
                        null,
                        "纬度字段",
                        -1
                        /* CACHED */
                      )),
                      createVNode(unref(Input), {
                        value: String(layer.location?.latitude ?? ""),
                        placeholder: "纬度 lat",
                        "data-testid": "geomap-lat-field",
                        "onUpdate:value": ($event) => updateLocation(i, { latitude: $event })
                      }, null, 8, ["value", "onUpdate:value"])
                    ]),
                    createElementVNode("div", null, [
                      _cache[11] || (_cache[11] = createElementVNode(
                        "label",
                        null,
                        "经度字段",
                        -1
                        /* CACHED */
                      )),
                      createVNode(unref(Input), {
                        value: String(layer.location?.longitude ?? ""),
                        placeholder: "经度 lon",
                        "data-testid": "geomap-lon-field",
                        "onUpdate:value": ($event) => updateLocation(i, { longitude: $event })
                      }, null, 8, ["value", "onUpdate:value"])
                    ])
                  ])) : createCommentVNode("v-if", true),
                  String(layer.location?.mode) === "geohash" ? (openBlock(), createElementBlock("div", _hoisted_10$8, [
                    _cache[12] || (_cache[12] = createElementVNode(
                      "label",
                      null,
                      "Geohash 字段",
                      -1
                      /* CACHED */
                    )),
                    createVNode(unref(Input), {
                      value: String(layer.location?.geohash ?? ""),
                      placeholder: "geohash 字段",
                      "data-testid": "geomap-geohash-field",
                      "onUpdate:value": ($event) => updateLocation(i, { geohash: $event })
                    }, null, 8, ["value", "onUpdate:value"])
                  ])) : createCommentVNode("v-if", true),
                  String(layer.location?.mode) === "lookup" ? (openBlock(), createElementBlock("div", _hoisted_11$7, [
                    createElementVNode("div", null, [
                      _cache[13] || (_cache[13] = createElementVNode(
                        "label",
                        null,
                        "查找字段",
                        -1
                        /* CACHED */
                      )),
                      createVNode(unref(Input), {
                        value: String(layer.location?.lookup ?? ""),
                        placeholder: "城市 / 站点",
                        "data-testid": "geomap-lookup-field",
                        "onUpdate:value": ($event) => updateLocation(i, { lookup: $event })
                      }, null, 8, ["value", "onUpdate:value"])
                    ]),
                    createElementVNode("div", null, [
                      _cache[14] || (_cache[14] = createElementVNode(
                        "label",
                        null,
                        "地名表 (JSON)",
                        -1
                        /* CACHED */
                      )),
                      createVNode(unref(Input), {
                        value: String(layer.location?.gazetteer ?? ""),
                        placeholder: '{"hq":{"lat":1,"lon":2}}',
                        "data-testid": "geomap-gazetteer-field",
                        "onUpdate:value": ($event) => updateLocation(i, { gazetteer: $event })
                      }, null, 8, ["value", "onUpdate:value"])
                    ])
                  ])) : createCommentVNode("v-if", true),
                  String(layer.type) === "geojson" ? (openBlock(), createElementBlock("div", _hoisted_12$6, [
                    _cache[15] || (_cache[15] = createElementVNode(
                      "label",
                      null,
                      "GeoJSON（内联 JSON）",
                      -1
                      /* CACHED */
                    )),
                    createVNode(unref(Input), {
                      value: String(layer.config?.geojson ?? layer.config?.src ?? ""),
                      placeholder: '{"type":"FeatureCollection","features":[]}',
                      "data-testid": "geomap-geojson-src",
                      "onUpdate:value": ($event) => updateConfig(i, { geojson: $event })
                    }, null, 8, ["value", "onUpdate:value"])
                  ])) : createCommentVNode("v-if", true),
                  createElementVNode("div", _hoisted_13$6, [
                    createElementVNode("div", null, [
                      _cache[16] || (_cache[16] = createElementVNode(
                        "label",
                        null,
                        "半径",
                        -1
                        /* CACHED */
                      )),
                      createVNode(unref(InputNumber), {
                        min: 1,
                        max: 40,
                        value: Number(layer.config?.radius ?? 6),
                        "onUpdate:value": ($event) => updateConfig(i, { radius: Number($event ?? 6) })
                      }, null, 8, ["value", "onUpdate:value"])
                    ]),
                    createElementVNode("div", null, [
                      _cache[17] || (_cache[17] = createElementVNode(
                        "label",
                        null,
                        "颜色",
                        -1
                        /* CACHED */
                      )),
                      createVNode(unref(Input), {
                        value: String(layer.config?.color ?? ""),
                        placeholder: "var(--grafana-primary)",
                        "onUpdate:value": ($event) => updateConfig(i, { color: $event })
                      }, null, 8, ["value", "onUpdate:value"])
                    ]),
                    createElementVNode("div", _hoisted_14$6, [
                      _cache[18] || (_cache[18] = createElementVNode(
                        "label",
                        null,
                        "显示标签",
                        -1
                        /* CACHED */
                      )),
                      createVNode(unref(Switch), {
                        checked: Boolean(layer.config?.showLabels),
                        "onUpdate:checked": (v) => updateConfig(i, { showLabels: v === true || v === "true" })
                      }, null, 8, ["checked", "onUpdate:checked"])
                    ])
                  ])
                ],
                64
                /* STABLE_FRAGMENT */
              ))
            ], 8, _hoisted_3$D);
          }),
          128
          /* KEYED_FRAGMENT */
        ))
      ]);
    };
  }
});
const GeomapLayersEditor = /* @__PURE__ */ _export_sfc(_sfc_main$12, [["__scopeId", "data-v-d7bf9066"]]);
const plugin$4 = new VuePanelPlugin(
  {
    id: "geomap",
    name: "地理地图",
    description: "OpenLayers 地理可视化",
    state: "stable",
    skipDataQuery: false
  },
  _sfc_main$13
).setNoPadding().setPanelOptions((builder) => {
  const catMap = ["地图视图"];
  const catCtrl = ["地图控件"];
  const catTip = ["提示"];
  const catLayer = ["图层"];
  const catStyle = ["图层 / 样式"];
  builder.addCustom(
    {
      id: "view",
      path: "view",
      name: "初始视图",
      category: catMap,
      description: "面板首次加载时显示的位置",
      editor: "custom",
      // UI is the expanded view.id/lat/lon/zoom editors; hide composite shell
      showIf: () => false
    },
    {
      id: "zero",
      lat: 0,
      lon: 0,
      zoom: 1,
      allLayers: true,
      noRepeat: false
    }
  ).addSelect(
    {
      id: "view.id",
      path: "view.id",
      name: "视图中心",
      category: catMap,
      description: "面板首次加载时的地图中心",
      settings: {
        options: [
          { label: "零点 (0,0)", value: "zero" },
          { label: "坐标", value: "coords" },
          { label: "适应数据", value: "fit" }
        ]
      }
    },
    "zero"
  ).addNumber(
    {
      id: "view.lat",
      path: "view.lat",
      name: "纬度",
      category: catMap,
      settings: { min: -90, max: 90, step: 1e-6 },
      showIf: (c) => (c.view?.id ?? "zero") === "coords"
    },
    0
  ).addNumber(
    {
      id: "view.lon",
      path: "view.lon",
      name: "经度",
      category: catMap,
      settings: { min: -180, max: 180, step: 1e-6 },
      showIf: (c) => (c.view?.id ?? "zero") === "coords"
    },
    0
  ).addNumber(
    {
      id: "view.zoom",
      path: "view.zoom",
      name: "缩放",
      category: catMap,
      settings: { min: 1, max: 18, step: 0.01 }
    },
    1
  ).addSelect(
    {
      id: "basemap.type",
      path: "basemap.type",
      name: "底图类型",
      category: ["底图图层"],
      settings: {
        options: [
          { label: "OpenStreetMap", value: "osm" },
          { label: "XYZ 瓦片", value: "xyz" },
          { label: "Carto", value: "carto" },
          { label: "无底图", value: "none" }
        ]
      }
    },
    "carto"
  ).addBoolean(
    {
      id: "view.shared",
      path: "view.shared",
      name: "共享视图",
      category: catMap
    },
    false
  ).addBoolean(
    {
      id: "view.noRepeat",
      path: "view.noRepeat",
      name: "不重复地图",
      category: catMap
    },
    false
  ).addBoolean(
    {
      id: "view.dashboardVariable",
      path: "view.dashboardVariable",
      name: "同步到仪表盘变量",
      category: catMap
    },
    false
  ).addBoolean(
    {
      id: "controls.showZoom",
      path: "controls.showZoom",
      name: "显示缩放",
      category: catCtrl
    },
    true
  ).addBoolean(
    {
      id: "controls.mouseWheelZoom",
      path: "controls.mouseWheelZoom",
      name: "鼠标滚轮缩放",
      category: catCtrl
    },
    true
  ).addBoolean(
    {
      id: "controls.showAttribution",
      path: "controls.showAttribution",
      name: "显示归属",
      category: catCtrl
    },
    true
  ).addBoolean(
    {
      id: "controls.showScale",
      path: "controls.showScale",
      name: "显示比例尺",
      category: catCtrl
    },
    false
  ).addBoolean(
    {
      id: "controls.showMeasure",
      path: "controls.showMeasure",
      name: "显示测量",
      category: catCtrl
    },
    false
  ).addBoolean(
    {
      id: "controls.showDebug",
      path: "controls.showDebug",
      name: "显示调试",
      category: catCtrl
    },
    false
  ).addBoolean(
    {
      id: "config.showLabels",
      path: "config.showLabels",
      name: "显示标签",
      category: catStyle
    },
    false
  ).addBoolean(
    {
      id: "config.showLegend",
      path: "config.showLegend",
      name: "显示图例",
      category: catStyle
    },
    false
  ).addBoolean(
    {
      id: "config.crop",
      path: "config.crop",
      name: "裁剪",
      category: catStyle
    },
    true
  ).addBoolean(
    {
      id: "config.shadow",
      path: "config.shadow",
      name: "阴影",
      category: catStyle
    },
    false
  ).addBoolean(
    {
      id: "config.sun",
      path: "config.sun",
      name: "太阳",
      category: catStyle
    },
    false
  ).addText(
    {
      id: "view.dashboardVariableName",
      path: "view.dashboardVariableName",
      name: "变量名",
      category: catMap,
      showIf: (c) => !!c.view?.dashboardVariable
    },
    void 0
  ).addRadio(
    {
      id: "tooltip.mode",
      path: "tooltip.mode",
      name: "提示",
      category: catTip,
      settings: {
        options: [
          { label: "无", value: "none", description: "点击显示" },
          { label: "详情", value: "details", description: "悬停显示" }
        ]
      }
    },
    "details"
  ).addSelect(
    {
      id: "type",
      path: "type",
      name: "图层类型",
      category: catLayer,
      settings: {
        options: [
          { label: "标记", value: "markers" },
          { label: "热力", value: "heatmap" },
          { label: "GeoJSON", value: "geojson" },
          { label: "路径", value: "route" },
          { label: "照片", value: "photos" },
          { label: "网络", value: "network" },
          { label: "昼夜", value: "dayNight" },
          { label: "底图", value: "basemap" }
        ]
      }
    },
    "markers"
  ).addNumber(
    {
      id: "opacity",
      path: "opacity",
      name: "不透明度",
      category: catLayer,
      settings: { min: 0, max: 1, step: 0.05 }
    },
    1
  ).addText(
    {
      id: "filterData",
      path: "filterData",
      name: "数据过滤",
      category: catLayer
    },
    void 0
  ).addCustom({
    id: "layer-tooltip",
    path: "layer-tooltip",
    name: "图层提示",
    category: catLayer,
    editor: "text"
  }).addText(
    {
      id: "config.accessToken",
      path: "config.accessToken",
      name: "访问令牌",
      category: catStyle
    },
    void 0
  ).addSelect(
    {
      id: "config.arrow",
      path: "config.arrow",
      name: "箭头",
      category: catStyle,
      settings: {
        options: [
          { label: "无", value: "none" },
          { label: "正向", value: "forward" },
          { label: "反向", value: "reverse" },
          { label: "双向", value: "both" }
        ]
      }
    },
    void 0
  ).addText(
    {
      id: "config.attribution",
      path: "config.attribution",
      name: "版权归属",
      category: catStyle
    },
    void 0
  ).addNumber(
    {
      id: "config.blur",
      path: "config.blur",
      name: "模糊",
      category: catStyle
    },
    void 0
  ).addText(
    {
      id: "config.border",
      path: "config.border",
      name: "边框色",
      category: catStyle
    },
    void 0
  ).addColor(
    {
      id: "config.color",
      path: "config.color",
      name: "颜色",
      category: catStyle
    },
    void 0
  ).addText(
    {
      id: "config.dataStyle",
      path: "config.dataStyle",
      name: "数据样式",
      category: catStyle
    },
    void 0
  ).addText(
    {
      id: "config.edgeStyle",
      path: "config.edgeStyle",
      name: "边样式",
      category: catStyle
    },
    void 0
  ).addText(
    {
      id: "config.idField",
      path: "config.idField",
      name: "ID 字段",
      category: catStyle
    },
    void 0
  ).addSelect(
    {
      id: "config.kind",
      path: "config.kind",
      name: "形状",
      category: catStyle,
      settings: {
        options: [
          { label: "方", value: "square" },
          { label: "圆", value: "circle" },
          { label: "标记", value: "marker" }
        ]
      }
    },
    void 0
  ).addNumber(
    {
      id: "config.maxZoom",
      path: "config.maxZoom",
      name: "最大缩放",
      category: catStyle
    },
    void 0
  ).addNumber(
    {
      id: "config.minZoom",
      path: "config.minZoom",
      name: "最小缩放",
      category: catStyle
    },
    void 0
  ).addColor(
    {
      id: "config.nightColor",
      path: "config.nightColor",
      name: "夜间颜色",
      category: catStyle
    },
    void 0
  ).addNumber(
    {
      id: "config.radius",
      path: "config.radius",
      name: "半径",
      category: catStyle
    },
    void 0
  ).addText(
    {
      id: "config.rules",
      path: "config.rules",
      name: "规则",
      category: catStyle
    },
    void 0
  ).addSelect(
    {
      id: "config.server",
      path: "config.server",
      name: "底图服务",
      category: catStyle,
      settings: {
        options: [
          { label: "街道", value: "streets" },
          { label: "卫星", value: "satellite" },
          { label: "地形", value: "topo" },
          { label: "海洋", value: "ocean" }
        ]
      }
    },
    void 0
  ).addSelect(
    {
      id: "config.show",
      path: "config.show",
      name: "显示",
      category: catStyle,
      settings: {
        options: [
          { label: "夜", value: "night" },
          { label: "昼", value: "day" },
          { label: "两者", value: "both" }
        ]
      }
    },
    void 0
  ).addText(
    {
      id: "config.src",
      path: "config.src",
      name: "图片源",
      category: catStyle
    },
    void 0
  ).addText(
    {
      id: "config.style",
      path: "config.style",
      name: "样式",
      category: catStyle
    },
    void 0
  ).addSelect(
    {
      id: "config.theme",
      path: "config.theme",
      name: "主题",
      category: catStyle,
      settings: {
        options: [
          { label: "自动", value: "auto" },
          { label: "亮", value: "light" },
          { label: "暗", value: "dark" }
        ]
      }
    },
    void 0
  ).addText(
    {
      id: "config.url",
      path: "config.url",
      name: "URL",
      category: catStyle
    },
    void 0
  ).addNumber(
    {
      id: "config.weight",
      path: "config.weight",
      name: "权重",
      category: catStyle
    },
    void 0
  );
}).setRuntimeConsumedPaths([
  "view.id",
  "view.lat",
  "view.lon",
  "view.zoom",
  "view.shared",
  "view.noRepeat",
  "view.dashboardVariable",
  "view.dashboardVariableName",
  "basemap.type",
  "config.accessToken",
  "config.arrow",
  "config.attribution",
  "config.blur",
  "config.border",
  "config.color",
  "config.crop",
  "config.dataStyle",
  "config.edgeStyle",
  "config.idField",
  "config.kind",
  "config.maxZoom",
  "config.minZoom",
  "config.nightColor",
  "config.radius",
  "config.rules",
  "config.server",
  "config.shadow",
  "config.show",
  "config.showLabels",
  "config.showLegend",
  "config.src",
  "config.style",
  "config.sun",
  "config.theme",
  "config.url",
  "config.weight",
  "controls.mouseWheelZoom",
  "controls.showAttribution",
  "controls.showDebug",
  "controls.showMeasure",
  "controls.showScale",
  "controls.showZoom",
  "filterData",
  "layer-tooltip",
  "opacity",
  "tooltip.mode",
  "type",
  "view",
  "view.dashboardVariable",
  "view.dashboardVariableName",
  "view.noRepeat",
  "view.shared"
]).setOptionsEditor(GeomapLayersEditor).register();
const module$5 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
  __proto__: null,
  plugin: plugin$4
}, Symbol.toStringTag, { value: "Module" }));
async function registerZabbixPlugin() {
  const [panelMod, dsMod] = await Promise.all([
    Promise.resolve().then(() => module$4),
    Promise.resolve().then(() => module$3)
  ]);
  if (dsMod.plugin) {
    registerDataSourcePlugin(dsMod.plugin);
  }
  if (panelMod.plugin) {
    registerPanelPlugin(panelMod.plugin);
  }
}
const register$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
  __proto__: null,
  registerZabbixPlugin
}, Symbol.toStringTag, { value: "Module" }));
async function registerSigNozPlugin() {
  const [panelMod, dsMod] = await Promise.all([
    Promise.resolve().then(() => module$2),
    Promise.resolve().then(() => module$1)
  ]);
  if (dsMod.plugin) {
    registerDataSourcePlugin(dsMod.plugin);
  }
  if (panelMod.plugin) {
    registerPanelPlugin(panelMod.plugin);
  }
}
const register = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
  __proto__: null,
  registerSigNozPlugin
}, Symbol.toStringTag, { value: "Module" }));
const olApi = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
  __proto__: null,
  Attribution,
  CircleStyle: Circle,
  Draw,
  Feature,
  Fill,
  GeoJSON,
  HeatmapLayer: Heatmap,
  LineString,
  Map: Map$1,
  OSM,
  Point,
  Polygon,
  ScaleLine,
  Stroke,
  Style,
  TextStyle: Text,
  TileLayer: Tile,
  VectorLayer: Vector,
  VectorSource: Vector$1,
  View,
  XYZ,
  Zoom,
  defaultControls: defaults,
  fromLonLat,
  getArea,
  getLength,
  toLonLat
}, Symbol.toStringTag, { value: "Module" }));
const CURRENT_SCHEMA_VERSION = 8;
const DEFAULT_SEVERITY = [
  { priority: 0, severity: "未分类", color: "rgb(108, 108, 108)", show: true },
  { priority: 1, severity: "信息", color: "rgb(120, 158, 183)", show: true },
  { priority: 2, severity: "警告", color: "rgb(175, 180, 36)", show: true },
  { priority: 3, severity: "一般严重", color: "rgb(255, 137, 30)", show: true },
  { priority: 4, severity: "严重", color: "rgb(255, 101, 72)", show: true },
  { priority: 5, severity: "灾难", color: "rgb(215, 0, 0)", show: true }
];
const DEFAULT_PROBLEMS_OPTIONS = {
  schemaVersion: 8,
  layout: "table",
  hostField: true,
  hostTechNameField: false,
  hostGroups: false,
  hostProxy: false,
  showTags: true,
  statusField: true,
  statusIcon: false,
  severityField: true,
  ackField: true,
  ageField: false,
  opdataField: false,
  descriptionField: true,
  descriptionAtNewLine: false,
  showDatasourceName: false,
  hostsInMaintenance: true,
  showTriggers: "all triggers",
  sortProblems: "lastchange",
  fontSize: "100%",
  pageSize: 10,
  problemTimeline: true,
  highlightBackground: false,
  highlightNewEvents: false,
  highlightNewerThan: "1h",
  customLastChangeFormat: false,
  lastChangeFormat: "",
  resizedColumns: [],
  allowDangerousHTML: false,
  triggerSeverity: DEFAULT_SEVERITY.map((s) => ({ ...s })),
  okEventColor: "rgb(56, 189, 113)",
  ackEventColor: "rgb(56, 219, 156)",
  markAckEvents: false,
  customTagColumns: "",
  allowAcknowledge: false,
  allowUnacknowledge: false,
  allowClose: false,
  allowChangeSeverity: false,
  allowSuppress: false,
  allowUnsuppress: false,
  allowExecuteScripts: false,
  showDetails: true
};
function deepClone$3(v) {
  try {
    return structuredClone(v);
  } catch {
    return JSON.parse(JSON.stringify(v));
  }
}
function nextRefId(targets) {
  const used = new Set(targets.map((t) => t.refId).filter(Boolean));
  for (let i = 0; i < 26; i++) {
    const id = String.fromCharCode(65 + i);
    if (!used.has(id)) return id;
  }
  return `Q${targets.length + 1}`;
}
function getDefaultTarget(targets = []) {
  return {
    group: { filter: "" },
    host: { filter: "" },
    application: { filter: "" },
    trigger: { filter: "" },
    tags: { filter: "" },
    proxy: { filter: "" },
    refId: nextRefId(targets)
  };
}
function isEmptyTarget(target) {
  return !target || !(target.group && target.host && target.application && target.trigger);
}
function isInvalidTarget(target, targetKey) {
  return Boolean(target && target.refId === "A" && targetKey === "0");
}
function isDefaultTarget(target) {
  return !target?.group?.filter && !target?.host?.filter && !target?.application?.filter && !target?.trigger?.filter && !target?.queryType;
}
function isEmptyTargets(targets) {
  if (!targets) return true;
  if (Array.isArray(targets)) {
    return targets.length === 0 || targets.length === 1 && (!targets[0] || Object.keys(targets[0]).length === 0);
  }
  return false;
}
function datasourceKey(ds2) {
  if (ds2 == null || ds2 === "") return "default";
  if (typeof ds2 === "string") {
    if (ds2 === "[object Object]") return "default";
    return ds2;
  }
  if (typeof ds2 === "object") {
    const o = ds2;
    if (typeof o.uid === "string" && o.uid && o.uid !== "[object Object]")
      return o.uid;
    if (typeof o.type === "string" && o.type) return o.type;
  }
  return "default";
}
function isEmptyPanel(panel2) {
  return !panel2.datasource && !panel2.datasources && !panel2.triggers && isEmptyTargets(panel2.targets);
}
function isDefaultPanel(panel2) {
  return Array.isArray(panel2.targets) && panel2.targets.length === 1 && isDefaultTarget(panel2.targets[0]);
}
function migrateShowEvents(panel2) {
  if (panel2.showEvents?.value === 1) return "problems";
  if (panel2.showEvents?.value === 0 || Array.isArray(panel2.showEvents?.value) && panel2.showEvents.value.length > 1) {
    return "history";
  }
  return "problems";
}
function migrateTargetOptions(panel2) {
  let acknowledged = 2;
  if (panel2.showTriggers === "acknowledged") acknowledged = 1;
  else if (panel2.showTriggers === "unacknowledged") acknowledged = 0;
  let limit = 1001;
  if (panel2.limit && panel2.limit !== 100) limit = panel2.limit;
  return {
    hostsInMaintenance: panel2.hostsInMaintenance,
    sortProblems: panel2.sortTriggersBy?.value === "priority" ? "priority" : "default",
    minSeverity: 0,
    acknowledged,
    limit
  };
}
function migrateProblemsPanelOptions(input = {}) {
  const src = { ...input };
  if (src.schema != null && src.schemaVersion == null)
    src.schemaVersion = src.schema;
  if (src.showTimeline != null && src.problemTimeline == null)
    src.problemTimeline = src.showTimeline;
  const next = {
    ...DEFAULT_PROBLEMS_OPTIONS,
    ...src,
    triggerSeverity: Array.isArray(src.triggerSeverity) && src.triggerSeverity.length ? src.triggerSeverity : DEFAULT_PROBLEMS_OPTIONS.triggerSeverity.map((s) => ({ ...s })),
    resizedColumns: Array.isArray(src.resizedColumns) ? src.resizedColumns : []
  };
  next.schemaVersion = 8;
  if (next.layout !== "list") next.layout = "table";
  if (!["default", "lastchange", "priority"].includes(next.sortProblems))
    next.sortProblems = "lastchange";
  if (!Number.isFinite(Number(next.pageSize)) || Number(next.pageSize) <= 0)
    next.pageSize = 10;
  return next;
}
function migrateProblemsPanel(input) {
  const panel2 = deepClone$3(input);
  if (isDefaultPanel(panel2)) {
    panel2.options = migrateProblemsPanelOptions(
      panel2.options || {}
    );
    return panel2;
  }
  if (isEmptyPanel(panel2)) {
    delete panel2.targets;
    panel2.options = migrateProblemsPanelOptions(
      panel2.options || {}
    );
    return panel2;
  }
  const schemaVersion = Number(panel2.schemaVersion || 1);
  if (schemaVersion < 2) {
    const hasModernArrayTargets = Array.isArray(panel2.targets);
    if (!hasModernArrayTargets) {
      const triggers = panel2.triggers;
      const dsList = Array.isArray(panel2.datasources) ? panel2.datasources : panel2.datasource != null ? [panel2.datasource] : [];
      panel2.datasources = dsList;
      panel2.targets = {};
      const key = datasourceKey(dsList[0]);
      panel2.targets[key] = triggers;
      delete panel2.triggers;
      delete panel2.datasource;
    } else {
      delete panel2.triggers;
    }
  }
  if (schemaVersion < 3) {
    delete panel2.lastChangeField;
    delete panel2.infoField;
    delete panel2.scroll;
    delete panel2.hideHostsInMaintenance;
  }
  if (schemaVersion < 5) {
    if (panel2.targets && typeof panel2.targets === "object" && !Array.isArray(panel2.targets)) {
      for (const key of Object.keys(panel2.targets)) {
        const t = panel2.targets[key];
        panel2.targets[key] = { ...getDefaultTarget(), ...t };
      }
    } else if (Array.isArray(panel2.targets)) {
      panel2.targets = panel2.targets.map((t) => ({
        ...getDefaultTarget(panel2.targets),
        ...t
      }));
    }
  }
  if (schemaVersion < 6) {
    if (panel2.showEvents?.value === "1") {
      panel2.showEvents.value = 1;
    }
  }
  if (schemaVersion < 7) {
    const updated = [];
    if (panel2.targets && typeof panel2.targets === "object" && !Array.isArray(panel2.targets)) {
      for (const targetKey of Object.keys(panel2.targets)) {
        const target = panel2.targets[targetKey];
        if (!isEmptyTarget(target) && !isInvalidTarget(target, targetKey)) {
          const dsRef = target.datasource ?? (targetKey === "[object Object]" ? void 0 : targetKey);
          updated.push({
            ...target,
            datasource: dsRef ?? datasourceKey(targetKey)
          });
        }
      }
    } else if (Array.isArray(panel2.targets)) {
      updated.push(...panel2.targets);
    }
    for (const target of updated) {
      if (!target.refId) target.refId = nextRefId(updated);
    }
    panel2.targets = updated;
    delete panel2.datasources;
  }
  if (schemaVersion < 8) {
    const targets = Array.isArray(panel2.targets) ? panel2.targets : [];
    if (targets.length === 1) {
      if (targets[0].datasource) {
        panel2.datasource = targets[0].datasource;
        delete targets[0].datasource;
      }
    } else if (targets.length > 1) {
      panel2.datasource = "-- Mixed --";
    }
    for (const target of targets) {
      target.queryType = 5;
      target.showProblems = migrateShowEvents(panel2);
      target.options = {
        ...target.options || {},
        ...migrateTargetOptions(panel2)
      };
      if (!target.tags) target.tags = { filter: "" };
    }
    panel2.targets = targets;
    panel2.sortProblems = panel2.sortTriggersBy?.value === "priority" ? "priority" : "lastchange";
    delete panel2.showEvents;
    delete panel2.showTriggers;
    delete panel2.hostsInMaintenance;
    delete panel2.sortTriggersBy;
  }
  if (panel2.datasource === "[object Object]" || panel2.datasource && typeof panel2.datasource === "object" && typeof panel2.datasource.uid === "object") {
    const fromTarget = Array.isArray(panel2.targets) ? panel2.targets[0]?.datasource : void 0;
    const key = datasourceKey(fromTarget ?? panel2.datasource);
    panel2.datasource = {
      uid: key === "default" ? "zabbix" : key,
      type: "alexanderzobnin-zabbix-datasource"
    };
  }
  panel2.schemaVersion = CURRENT_SCHEMA_VERSION;
  const optionsInput = {
    ...panel2.options || {},
    sortProblems: panel2.sortProblems ?? panel2.options?.sortProblems
  };
  panel2.options = migrateProblemsPanelOptions(
    optionsInput
  );
  return panel2;
}
function col$1(frame, name) {
  return frame.fields.find((f) => f.name === name)?.values || [];
}
function parseJsonArray(raw) {
  if (Array.isArray(raw)) return raw;
  if (typeof raw === "string") {
    try {
      const v = JSON.parse(raw || "[]");
      return Array.isArray(v) ? v : [];
    } catch {
      return [];
    }
  }
  if (raw && typeof raw === "object") return [raw];
  return [];
}
function toMs$2(v) {
  const n = Number(v ?? 0);
  if (!Number.isFinite(n) || n <= 0) return 0;
  return n < 1e12 ? n * 1e3 : n;
}
function hostsOf(raw) {
  return parseJsonArray(raw).map((h) => ({
    hostid: String(h.hostid ?? h.id ?? ""),
    name: String(h.name ?? h.host ?? ""),
    host: String(h.host ?? h.name ?? "")
  }));
}
function groupsOf(raw) {
  return parseJsonArray(raw).map(
    (g) => typeof g === "string" ? g : String(g.name ?? g.groupid ?? "")
  );
}
function acksOf(raw) {
  return parseJsonArray(raw).map((a) => ({
    acknowledgeid: String(a.acknowledgeid ?? ""),
    clock: toMs$2(a.clock),
    user: String(a.user ?? a.username ?? a.alias ?? ""),
    message: String(a.message ?? ""),
    action: Number(a.action ?? 0)
  }));
}
function itemsOf(raw) {
  return parseJsonArray(raw).map((i) => ({
    itemid: String(i.itemid ?? ""),
    name: String(i.name ?? ""),
    key_: String(i.key_ ?? i.key ?? ""),
    lastvalue: i.lastvalue != null ? String(i.lastvalue) : void 0,
    value_type: i.value_type != null ? String(i.value_type) : void 0
  }));
}
function metaOf(frame) {
  const meta2 = frame.meta || {};
  return {
    uid: String(meta2.datasourceUid || meta2.uid || ""),
    name: String(meta2.datasourceName || meta2.name || "")
  };
}
function framesToProblemViewModels(frames = [], options) {
  const notices = [];
  const problems = [];
  for (const frame of frames) {
    const meta2 = metaOf(frame);
    const n = frame.length || col$1(frame, "eventid").length || 0;
    for (let i = 0; i < n; i++) {
      const get = (name) => col$1(frame, name)[i];
      const eventid = String(get("eventid") ?? "");
      if (!eventid) {
        notices.push("已过滤缺少 eventid 的问题行");
        continue;
      }
      const ackRaw = get("acknowledged");
      const acknowledged = ackRaw === true || ackRaw === 1 || String(ackRaw) === "1";
      problems.push({
        eventid,
        objectid: String(get("objectid") ?? ""),
        name: String(get("name") ?? ""),
        severity: Number(get("severity") ?? 0),
        clock: toMs$2(get("clock")),
        acknowledged,
        status: String(get("status") ?? "problem"),
        hosts: hostsOf(get("hosts")),
        groups: groupsOf(get("groups")),
        tags: parseJsonArray(get("tags")).map(
          (t) => typeof t === "string" ? { tag: t, value: "" } : { tag: String(t.tag ?? ""), value: String(t.value ?? "") }
        ),
        acknowledges: acksOf(get("acknowledges")),
        alerts: parseJsonArray(get("alerts")),
        events: parseJsonArray(get("events")),
        items: itemsOf(get("items")),
        description: String(get("description") ?? ""),
        opdata: String(get("opdata") ?? ""),
        expression: String(get("expression") ?? ""),
        datasourceUid: meta2.uid,
        datasourceName: meta2.name,
        manual_close: (() => {
          const v = get("manual_close");
          return v == null || v === "" ? void 0 : String(v);
        })(),
        suppressed: (() => {
          const v = get("suppressed");
          return v === true || v === 1 || String(v) === "1";
        })(),
        suppression: parseJsonArray(
          get("suppression_data") ?? get("suppression")
        ),
        historicalItemValue: (() => {
          const v = get("historicalItemValue");
          return v == null || v === "" ? null : String(v);
        })(),
        hostInMaintenance: (() => {
          const v = get("hostInMaintenance") ?? get("maintenance_status");
          return v === true || v === 1 || String(v) === "1";
        })(),
        url: (() => {
          const v = get("url");
          return v == null || v === "" ? void 0 : String(v);
        })(),
        type: (() => {
          const v = get("type");
          return v == null || v === "" ? void 0 : String(v);
        })(),
        correlation_mode: (() => {
          const v = get("correlation_mode");
          return v == null || v === "" ? void 0 : String(v);
        })(),
        correlation_tag: (() => {
          const v = get("correlation_tag");
          return v == null || v === "" ? void 0 : String(v);
        })(),
        state: (() => {
          const v = get("state");
          return v == null || v === "" ? void 0 : String(v);
        })(),
        error: (() => {
          const v = get("error");
          return v == null || v === "" ? void 0 : String(v);
        })(),
        proxy: (() => {
          const v = get("proxy") ?? get("proxy_host") ?? get("proxy_name");
          return v == null || v === "" ? void 0 : String(v);
        })()
      });
    }
  }
  const sort = options?.sortProblems || "lastchange";
  if (sort === "priority") {
    problems.sort(
      (a, b) => b.severity - a.severity || b.clock - a.clock || a.eventid.localeCompare(b.eventid)
    );
  } else if (sort === "lastchange") {
    problems.sort(
      (a, b) => b.clock - a.clock || a.eventid.localeCompare(b.eventid)
    );
  } else {
    problems.sort((a, b) => a.eventid.localeCompare(b.eventid));
  }
  return { problems, notices: [...new Set(notices)] };
}
function problemsFromPanelData(data, options) {
  return framesToProblemViewModels(data?.series || [], options);
}
const _hoisted_1$Z = ["data-status", "data-ack"];
const _sfc_main$11 = /* @__PURE__ */ defineComponent({
  __name: "ProblemStatus",
  props: {
    status: {},
    acknowledged: { type: Boolean },
    markAck: { type: Boolean },
    ackColor: {},
    okColor: {}
  },
  setup(__props) {
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("span", {
        class: "status",
        "data-status": __props.status,
        "data-ack": String(__props.acknowledged),
        "data-testid": "problem-status",
        style: normalizeStyle(
          __props.acknowledged && __props.markAck ? { color: __props.ackColor } : __props.status === "resolved" ? { color: __props.okColor } : void 0
        )
      }, toDisplayString(__props.status === "resolved" ? "已恢复" : __props.acknowledged ? "已确认" : "问题"), 13, _hoisted_1$Z);
    };
  }
});
const ProblemStatus = /* @__PURE__ */ _export_sfc(_sfc_main$11, [["__scopeId", "data-v-0240222c"]]);
const _hoisted_1$Y = ["data-testid"];
const _hoisted_2$K = ["href"];
const _hoisted_3$C = { key: 1 };
const _sfc_main$10 = /* @__PURE__ */ defineComponent({
  __name: "ProblemStatusBar",
  props: {
    problem: {},
    compact: { type: Boolean, default: false },
    markAck: { type: Boolean },
    ackColor: {},
    okColor: {}
  },
  setup(__props) {
    const props = __props;
    const icons = computed(() => {
      const p = props.problem;
      const out = [];
      if (p.hostInMaintenance)
        out.push({
          key: "maintenance",
          icon: "exclamation-triangle",
          title: "主机处于维护"
        });
      if (p.url)
        out.push({
          key: "url",
          icon: "share-alt",
          title: "触发器 URL",
          href: p.url
        });
      if (String(p.type) === "1")
        out.push({ key: "multi", icon: "copy", title: "多事件触发器" });
      if (String(p.correlation_mode) === "1") {
        out.push({
          key: "correlation",
          icon: "link",
          title: `关联关闭标签: ${p.correlation_tag || "—"}`
        });
      }
      if ((p.alerts || []).length)
        out.push({
          key: "alerts",
          icon: "bell",
          title: `告警动作 ${p.alerts.length}`
        });
      if (String(p.state) === "1")
        out.push({ key: "unknown", icon: "question", title: "状态未知" });
      if (p.error)
        out.push({ key: "error", icon: "times", title: `触发器错误: ${p.error}` });
      if (String(p.manual_close) === "1" || p.manual_close === true) {
        out.push({ key: "manual", icon: "check", title: "允许手动关闭" });
      }
      return out;
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock(
        "div",
        {
          class: normalizeClass(["status-bar", { compact: __props.compact }]),
          "data-testid": "problem-status-bar"
        },
        [
          !__props.compact ? (openBlock(), createBlock(ProblemStatus, {
            key: 0,
            status: __props.problem.status,
            acknowledged: __props.problem.acknowledged,
            "mark-ack": __props.markAck,
            "ack-color": __props.ackColor || "",
            "ok-color": __props.okColor || ""
          }, null, 8, ["status", "acknowledged", "mark-ack", "ack-color", "ok-color"])) : createCommentVNode("v-if", true),
          (openBlock(true), createElementBlock(
            Fragment,
            null,
            renderList(icons.value, (ic) => {
              return openBlock(), createElementBlock("span", {
                key: ic.key,
                class: "ic",
                "data-testid": `status-icon-${ic.key}`
              }, [
                createVNode(unref(_sfc_main$18), {
                  title: ic.title
                }, {
                  default: withCtx(() => [
                    ic.href ? (openBlock(), createElementBlock("a", {
                      key: 0,
                      href: ic.href,
                      target: "_blank",
                      rel: "noopener noreferrer",
                      onClick: _cache[0] || (_cache[0] = withModifiers(() => {
                      }, ["stop"]))
                    }, [
                      createVNode(unref(GIcon), {
                        name: ic.icon
                      }, null, 8, ["name"])
                    ], 8, _hoisted_2$K)) : (openBlock(), createElementBlock("span", _hoisted_3$C, [
                      createVNode(unref(GIcon), {
                        name: ic.icon
                      }, null, 8, ["name"])
                    ]))
                  ]),
                  _: 2
                  /* DYNAMIC */
                }, 1032, ["title"])
              ], 8, _hoisted_1$Y);
            }),
            128
            /* KEYED_FRAGMENT */
          ))
        ],
        2
        /* CLASS */
      );
    };
  }
});
const ProblemStatusBar = /* @__PURE__ */ _export_sfc(_sfc_main$10, [["__scopeId", "data-v-19115f34"]]);
function useColumnResize(getColumns, onChange) {
  const dragging = ref(null);
  let startX = 0;
  let startW = 0;
  let colId = "";
  function onMove(e) {
    if (!dragging.value) return;
    const dx = e.clientX - startX;
    const width2 = Math.max(48, startW + dx);
    const prev = getColumns().filter((c) => c.id !== colId);
    onChange([...prev, { id: colId, value: width2 }]);
  }
  function onUp() {
    dragging.value = null;
    window.removeEventListener("mousemove", onMove);
    window.removeEventListener("mouseup", onUp);
  }
  function startResize(id, currentWidth, e) {
    e.preventDefault();
    e.stopPropagation();
    colId = id;
    startX = e.clientX;
    startW = currentWidth;
    dragging.value = id;
    window.addEventListener("mousemove", onMove);
    window.addEventListener("mouseup", onUp);
  }
  onBeforeUnmount(() => {
    window.removeEventListener("mousemove", onMove);
    window.removeEventListener("mouseup", onUp);
  });
  return { dragging, startResize };
}
function widthFor(id, resized, fallback = 120) {
  const hit = (resized || []).find((c) => c.id === id);
  return hit?.value ?? fallback;
}
function buildColumns(o) {
  const cols = [
    { key: "time", title: "时间", sortable: true, width: 140 }
  ];
  if (o.severityField)
    cols.push({ key: "severity", title: "严重性", sortable: true, width: 90 });
  if (o.statusField)
    cols.push({ key: "status", title: "状态", sortable: true, width: 80 });
  if (o.statusIcon) cols.push({ key: "statusIcon", title: "图标", width: 96 });
  if (o.hostField)
    cols.push({ key: "host", title: "主机", sortable: true, width: 120 });
  if (o.hostTechNameField)
    cols.push({ key: "hostTechName", title: "技术名", width: 120 });
  if (o.hostGroups)
    cols.push({ key: "hostGroups", title: "主机组", width: 120 });
  if (o.hostProxy) cols.push({ key: "proxy", title: "代理", width: 100 });
  cols.push({ key: "problem", title: "问题", sortable: true, width: 220 });
  if (o.ageField)
    cols.push({ key: "age", title: "年龄", sortable: true, width: 72 });
  if (o.opdataField)
    cols.push({ key: "opdata", title: "运行数据", width: 120 });
  if (o.ackField) cols.push({ key: "ack", title: "确认", width: 80 });
  if (o.showTags) cols.push({ key: "tags", title: "标签", width: 140 });
  if (o.showDatasourceName)
    cols.push({ key: "datasource", title: "数据源", width: 100 });
  const custom = String(o.customTagColumns || "").split(",").map((s) => s.trim()).filter(Boolean);
  for (const tag of custom)
    cols.push({ key: `tag:${tag}`, title: tag, width: 100 });
  if (o.allowAcknowledge || o.allowUnacknowledge || o.allowClose || o.allowChangeSeverity || o.allowSuppress || o.allowUnsuppress || o.allowExecuteScripts) {
    cols.push({ key: "actions", title: "动作", width: 180 });
  }
  return cols;
}
const _hoisted_1$X = {
  class: "tbl",
  "data-testid": "problems-table"
};
const _hoisted_2$J = ["data-col", "onClick"];
const _hoisted_3$B = ["onMousedown"];
const _hoisted_4$t = ["data-testid", "onClick"];
const _hoisted_5$o = {
  key: 0,
  class: "sub"
};
const _hoisted_6$k = ["title"];
const _hoisted_7$g = ["onClick"];
const _hoisted_8$a = ["onClick"];
const _hoisted_9$9 = ["onClick"];
const _hoisted_10$7 = ["onClick"];
const _hoisted_11$6 = ["onClick"];
const _hoisted_12$5 = ["onClick"];
const _hoisted_13$5 = ["onClick"];
const _hoisted_14$5 = ["onClick"];
const _hoisted_15$5 = {
  class: "pager",
  "data-testid": "problems-pager"
};
const _hoisted_16$4 = ["disabled"];
const _hoisted_17$4 = ["disabled"];
const _hoisted_18$4 = ["value"];
const _hoisted_19$4 = ["value"];
const _sfc_main$$ = /* @__PURE__ */ defineComponent({
  __name: "ProblemsTable",
  props: {
    items: {},
    options: {}
  },
  emits: ["select", "acknowledge", "unacknowledge", "close", "severity", "suppress", "unsuppress", "script", "update:options", "tag-click"],
  setup(__props, { expose: __expose, emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const sortKey = ref("time");
    const sortDir = ref("desc");
    const page = ref(0);
    const severityMap = computed(() => {
      const m = /* @__PURE__ */ new Map();
      for (const s of props.options.triggerSeverity || []) m.set(s.priority, s);
      return m;
    });
    const columns = computed(() => buildColumns(props.options));
    const { startResize } = useColumnResize(
      () => props.options.resizedColumns || [],
      (next) => emit("update:options", { ...props.options, resizedColumns: next })
    );
    function colWidth(c) {
      return widthFor(String(c.key), props.options.resizedColumns, c.width || 120);
    }
    function sevStyle(n) {
      return {
        background: severityMap.value.get(n)?.color || "#999",
        color: "#fff"
      };
    }
    function hostLabel(p) {
      return p.hosts.map((h) => h.name || h.host).join(", ");
    }
    function hostTech(p) {
      return p.hosts.map((h) => h.host || h.name).join(", ");
    }
    function age(p) {
      if (!p.clock) return "";
      const sec = Math.max(0, Math.floor((Date.now() - p.clock) / 1e3));
      if (sec < 60) return `${sec}s`;
      if (sec < 3600) return `${Math.floor(sec / 60)}m`;
      if (sec < 86400) return `${Math.floor(sec / 3600)}h`;
      return `${Math.floor(sec / 86400)}d`;
    }
    function formatTime(p) {
      if (!p.clock) return "";
      if (props.options.customLastChangeFormat && props.options.lastChangeFormat) {
        const d = new Date(p.clock);
        const pad = (n) => String(n).padStart(2, "0");
        return props.options.lastChangeFormat.replace(/YYYY/g, String(d.getFullYear())).replace(/MM/g, pad(d.getMonth() + 1)).replace(/DD/g, pad(d.getDate())).replace(/HH/g, pad(d.getHours())).replace(/mm/g, pad(d.getMinutes())).replace(/ss/g, pad(d.getSeconds()));
      }
      return new Date(p.clock).toLocaleString();
    }
    function tagValue(p, tag) {
      return p.tags.find((t) => t.tag === tag)?.value || "";
    }
    function isNew(p) {
      if (!props.options.highlightNewEvents) return false;
      const thr = parseDurationMs2(props.options.highlightNewerThan || "1h");
      return Date.now() - p.clock <= thr;
    }
    function parseDurationMs2(s) {
      const m = String(s).trim().match(/^(\d+(?:\.\d+)?)(ms|s|m|h|d)?$/i);
      if (!m) return 36e5;
      const n = Number(m[1]);
      const u = (m[2] || "s").toLowerCase();
      if (u === "ms") return n;
      if (u === "s") return n * 1e3;
      if (u === "m") return n * 6e4;
      if (u === "h") return n * 36e5;
      if (u === "d") return n * 864e5;
      return n * 1e3;
    }
    const sorted = computed(() => {
      const list = [...props.items].filter(
        (p) => severityMap.value.get(p.severity)?.show !== false
      );
      const dir = sortDir.value === "asc" ? 1 : -1;
      const key = sortKey.value;
      list.sort((a, b) => {
        let cmp = 0;
        if (key === "severity") cmp = a.severity - b.severity;
        else if (key === "status")
          cmp = String(a.status).localeCompare(String(b.status));
        else if (key === "host") cmp = hostLabel(a).localeCompare(hostLabel(b));
        else if (key === "problem") cmp = a.name.localeCompare(b.name);
        else if (key === "age") cmp = a.clock - b.clock;
        else cmp = a.clock - b.clock;
        return cmp * dir || a.eventid.localeCompare(b.eventid);
      });
      return list;
    });
    const pageSize = computed(() => {
      const allowed = [5, 10, 20, 25, 50, 100];
      const n = Number(props.options.pageSize || 10);
      return allowed.includes(n) ? n : 10;
    });
    const pageCount = computed(
      () => Math.max(1, Math.ceil(sorted.value.length / pageSize.value))
    );
    const pageItems = computed(() => {
      const start = page.value * pageSize.value;
      return sorted.value.slice(start, start + pageSize.value);
    });
    function toggleSort(key, sortable) {
      if (!sortable) return;
      if (sortKey.value === key)
        sortDir.value = sortDir.value === "asc" ? "desc" : "asc";
      else {
        sortKey.value = key;
        sortDir.value = key === "time" || key === "severity" ? "desc" : "asc";
      }
    }
    function onTagClick(e, tag, value, problem) {
      emit("tag-click", { tag, value, ctrl: e.ctrlKey || e.metaKey, problem });
    }
    const anyAction = computed(
      () => props.options.allowAcknowledge || props.options.allowUnacknowledge || props.options.allowClose || props.options.allowChangeSeverity || props.options.allowSuppress || props.options.allowUnsuppress || props.options.allowExecuteScripts
    );
    const fontSize = computed(() => props.options.fontSize || "100%");
    __expose({ buildColumns, columns, pageItems, sorted, toggleSort });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock(
        "div",
        {
          class: "wrap",
          style: normalizeStyle({ fontSize: fontSize.value }),
          "data-testid": "problems-table-wrap"
        },
        [
          createElementVNode("table", _hoisted_1$X, [
            createElementVNode("thead", null, [
              createElementVNode("tr", null, [
                (openBlock(true), createElementBlock(
                  Fragment,
                  null,
                  renderList(columns.value, (c) => {
                    return openBlock(), createElementBlock("th", {
                      key: c.key,
                      "data-col": c.key,
                      style: normalizeStyle({ width: colWidth(c) + "px" }),
                      class: normalizeClass({ sortable: c.sortable }),
                      onClick: ($event) => toggleSort(String(c.key), c.sortable)
                    }, [
                      createElementVNode(
                        "span",
                        null,
                        toDisplayString(c.title),
                        1
                        /* TEXT */
                      ),
                      createElementVNode("span", {
                        class: "resizer",
                        "data-testid": "col-resizer",
                        onMousedown: withModifiers(($event) => unref(startResize)(String(c.key), colWidth(c), $event), ["stop"])
                      }, null, 40, _hoisted_3$B)
                    ], 14, _hoisted_2$J);
                  }),
                  128
                  /* KEYED_FRAGMENT */
                ))
              ])
            ]),
            createElementVNode("tbody", null, [
              (openBlock(true), createElementBlock(
                Fragment,
                null,
                renderList(pageItems.value, (p) => {
                  return openBlock(), createElementBlock("tr", {
                    key: p.eventid,
                    "data-testid": `problem-row-${p.eventid}`,
                    class: normalizeClass({
                      ack: p.acknowledged && __props.options.markAckEvents,
                      "is-new": isNew(p),
                      "hl-bg": __props.options.highlightBackground
                    }),
                    style: normalizeStyle(
                      __props.options.highlightBackground ? { background: sevStyle(p.severity).background + "22" } : void 0
                    ),
                    onClick: ($event) => emit("select", p)
                  }, [
                    (openBlock(true), createElementBlock(
                      Fragment,
                      null,
                      renderList(columns.value, (c) => {
                        return openBlock(), createElementBlock(
                          "td",
                          {
                            key: c.key,
                            style: normalizeStyle({ width: colWidth(c) + "px" })
                          },
                          [
                            c.key === "time" ? (openBlock(), createElementBlock(
                              Fragment,
                              { key: 0 },
                              [
                                createTextVNode(
                                  toDisplayString(formatTime(p)),
                                  1
                                  /* TEXT */
                                )
                              ],
                              64
                              /* STABLE_FRAGMENT */
                            )) : c.key === "severity" ? (openBlock(), createElementBlock(
                              "span",
                              {
                                key: 1,
                                class: "sev",
                                style: normalizeStyle(sevStyle(p.severity))
                              },
                              toDisplayString(severityMap.value.get(p.severity)?.severity || p.severity),
                              5
                              /* TEXT, STYLE */
                            )) : c.key === "status" ? (openBlock(), createBlock(ProblemStatus, {
                              key: 2,
                              status: p.status,
                              acknowledged: p.acknowledged,
                              "mark-ack": __props.options.markAckEvents,
                              "ack-color": __props.options.ackEventColor,
                              "ok-color": __props.options.okEventColor
                            }, null, 8, ["status", "acknowledged", "mark-ack", "ack-color", "ok-color"])) : c.key === "statusIcon" ? (openBlock(), createBlock(ProblemStatusBar, {
                              key: 3,
                              problem: p,
                              compact: ""
                            }, null, 8, ["problem"])) : c.key === "host" ? (openBlock(), createElementBlock(
                              Fragment,
                              { key: 4 },
                              [
                                createTextVNode(
                                  toDisplayString(hostLabel(p)),
                                  1
                                  /* TEXT */
                                )
                              ],
                              64
                              /* STABLE_FRAGMENT */
                            )) : c.key === "hostTechName" ? (openBlock(), createElementBlock(
                              Fragment,
                              { key: 5 },
                              [
                                createTextVNode(
                                  toDisplayString(hostTech(p)),
                                  1
                                  /* TEXT */
                                )
                              ],
                              64
                              /* STABLE_FRAGMENT */
                            )) : c.key === "hostGroups" ? (openBlock(), createElementBlock(
                              Fragment,
                              { key: 6 },
                              [
                                createTextVNode(
                                  toDisplayString(p.groups.join(", ")),
                                  1
                                  /* TEXT */
                                )
                              ],
                              64
                              /* STABLE_FRAGMENT */
                            )) : c.key === "proxy" ? (openBlock(), createElementBlock(
                              Fragment,
                              { key: 7 },
                              [
                                createTextVNode(
                                  toDisplayString(p.proxy || "—"),
                                  1
                                  /* TEXT */
                                )
                              ],
                              64
                              /* STABLE_FRAGMENT */
                            )) : c.key === "problem" ? (openBlock(), createElementBlock(
                              "div",
                              {
                                key: 8,
                                class: normalizeClass({ "desc-nl": __props.options.descriptionAtNewLine })
                              },
                              [
                                createElementVNode(
                                  "div",
                                  null,
                                  toDisplayString(p.name),
                                  1
                                  /* TEXT */
                                ),
                                __props.options.descriptionAtNewLine && p.description ? (openBlock(), createElementBlock(
                                  "div",
                                  _hoisted_5$o,
                                  toDisplayString(p.description),
                                  1
                                  /* TEXT */
                                )) : createCommentVNode("v-if", true)
                              ],
                              2
                              /* CLASS */
                            )) : c.key === "age" ? (openBlock(), createElementBlock(
                              Fragment,
                              { key: 9 },
                              [
                                createTextVNode(
                                  toDisplayString(age(p)),
                                  1
                                  /* TEXT */
                                )
                              ],
                              64
                              /* STABLE_FRAGMENT */
                            )) : c.key === "opdata" ? (openBlock(), createElementBlock(
                              Fragment,
                              { key: 10 },
                              [
                                createTextVNode(
                                  toDisplayString(p.opdata || p.historicalItemValue || "—"),
                                  1
                                  /* TEXT */
                                )
                              ],
                              64
                              /* STABLE_FRAGMENT */
                            )) : c.key === "ack" ? (openBlock(), createElementBlock("span", {
                              key: 11,
                              class: "ack-count",
                              title: p.acknowledges.map((a) => `${a.user}: ${a.message}`).join("\n"),
                              "data-testid": "ack-count"
                            }, toDisplayString(p.acknowledges.length), 9, _hoisted_6$k)) : c.key === "tags" ? (openBlock(true), createElementBlock(
                              Fragment,
                              { key: 12 },
                              renderList(p.tags, (t) => {
                                return openBlock(), createElementBlock("button", {
                                  key: t.tag + t.value,
                                  type: "button",
                                  class: "tag",
                                  onClick: withModifiers(($event) => onTagClick($event, t.tag, t.value, p), ["stop"])
                                }, toDisplayString(t.tag) + toDisplayString(t.value ? ":" + t.value : ""), 9, _hoisted_7$g);
                              }),
                              128
                              /* KEYED_FRAGMENT */
                            )) : c.key === "datasource" ? (openBlock(), createElementBlock(
                              Fragment,
                              { key: 13 },
                              [
                                createTextVNode(
                                  toDisplayString(p.datasourceName),
                                  1
                                  /* TEXT */
                                )
                              ],
                              64
                              /* STABLE_FRAGMENT */
                            )) : String(c.key).startsWith("tag:") ? (openBlock(), createElementBlock(
                              Fragment,
                              { key: 14 },
                              [
                                createTextVNode(
                                  toDisplayString(tagValue(p, String(c.key).slice(4))),
                                  1
                                  /* TEXT */
                                )
                              ],
                              64
                              /* STABLE_FRAGMENT */
                            )) : c.key === "actions" && anyAction.value ? (openBlock(), createElementBlock("div", {
                              key: 15,
                              class: "actions",
                              onClick: _cache[0] || (_cache[0] = withModifiers(() => {
                              }, ["stop"]))
                            }, [
                              __props.options.allowAcknowledge ? (openBlock(), createElementBlock("button", {
                                key: 0,
                                type: "button",
                                "data-testid": "action-ack",
                                onClick: ($event) => emit("acknowledge", p)
                              }, " 确认 ", 8, _hoisted_8$a)) : createCommentVNode("v-if", true),
                              __props.options.allowUnacknowledge ? (openBlock(), createElementBlock("button", {
                                key: 1,
                                type: "button",
                                "data-testid": "action-unack",
                                onClick: ($event) => emit("unacknowledge", p)
                              }, " 取消确认 ", 8, _hoisted_9$9)) : createCommentVNode("v-if", true),
                              __props.options.allowClose ? (openBlock(), createElementBlock("button", {
                                key: 2,
                                type: "button",
                                "data-testid": "action-close",
                                onClick: ($event) => emit("close", p)
                              }, " 关闭 ", 8, _hoisted_10$7)) : createCommentVNode("v-if", true),
                              __props.options.allowChangeSeverity ? (openBlock(), createElementBlock("button", {
                                key: 3,
                                type: "button",
                                "data-testid": "action-sev",
                                onClick: ($event) => emit("severity", p)
                              }, " 严重级别 ", 8, _hoisted_11$6)) : createCommentVNode("v-if", true),
                              __props.options.allowSuppress ? (openBlock(), createElementBlock("button", {
                                key: 4,
                                type: "button",
                                "data-testid": "action-suppress",
                                onClick: ($event) => emit("suppress", p)
                              }, " 抑制 ", 8, _hoisted_12$5)) : createCommentVNode("v-if", true),
                              __props.options.allowUnsuppress ? (openBlock(), createElementBlock("button", {
                                key: 5,
                                type: "button",
                                "data-testid": "action-unsuppress",
                                onClick: ($event) => emit("unsuppress", p)
                              }, " 取消抑制 ", 8, _hoisted_13$5)) : createCommentVNode("v-if", true),
                              __props.options.allowExecuteScripts ? (openBlock(), createElementBlock("button", {
                                key: 6,
                                type: "button",
                                "data-testid": "action-script",
                                onClick: ($event) => emit("script", p)
                              }, " 脚本 ", 8, _hoisted_14$5)) : createCommentVNode("v-if", true)
                            ])) : createCommentVNode("v-if", true)
                          ],
                          4
                          /* STYLE */
                        );
                      }),
                      128
                      /* KEYED_FRAGMENT */
                    ))
                  ], 14, _hoisted_4$t);
                }),
                128
                /* KEYED_FRAGMENT */
              ))
            ])
          ]),
          createElementVNode("div", _hoisted_15$5, [
            createElementVNode("button", {
              type: "button",
              disabled: page.value <= 0,
              onClick: _cache[1] || (_cache[1] = ($event) => page.value = Math.max(0, page.value - 1))
            }, " 上一页 ", 8, _hoisted_16$4),
            createElementVNode(
              "span",
              null,
              toDisplayString(page.value + 1) + " / " + toDisplayString(pageCount.value),
              1
              /* TEXT */
            ),
            createElementVNode("button", {
              type: "button",
              disabled: page.value + 1 >= pageCount.value,
              onClick: _cache[2] || (_cache[2] = ($event) => page.value = Math.min(pageCount.value - 1, page.value + 1))
            }, " 下一页 ", 8, _hoisted_17$4),
            createElementVNode("select", {
              value: pageSize.value,
              "data-testid": "problems-page-size",
              onChange: _cache[3] || (_cache[3] = ($event) => {
                emit("update:options", {
                  ...__props.options,
                  pageSize: Number($event.target.value)
                });
                page.value = 0;
              })
            }, [
              (openBlock(), createElementBlock(
                Fragment,
                null,
                renderList([5, 10, 20, 25, 50, 100], (n) => {
                  return createElementVNode("option", {
                    key: n,
                    value: n
                  }, toDisplayString(n), 9, _hoisted_19$4);
                }),
                64
                /* STABLE_FRAGMENT */
              ))
            ], 40, _hoisted_18$4)
          ])
        ],
        4
        /* STYLE */
      );
    };
  }
});
const ProblemsTable = /* @__PURE__ */ _export_sfc(_sfc_main$$, [["__scopeId", "data-v-b41be292"]]);
const _sfc_main$_ = /* @__PURE__ */ defineComponent({
  __name: "SeverityBadge",
  props: {
    severity: {},
    label: {},
    color: {}
  },
  setup(__props) {
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock(
        "span",
        {
          class: "sev",
          "data-testid": "severity-badge",
          style: normalizeStyle({ background: __props.color || "#999", color: "#fff" })
        },
        toDisplayString(__props.label ?? __props.severity),
        5
        /* TEXT, STYLE */
      );
    };
  }
});
const SeverityBadge = /* @__PURE__ */ _export_sfc(_sfc_main$_, [["__scopeId", "data-v-2244911d"]]);
const _hoisted_1$W = ["data-testid", "onClick"];
const _hoisted_2$I = { class: "name" };
const _hoisted_3$A = { class: "meta" };
const _hoisted_4$s = {
  key: 0,
  class: "maint",
  title: "维护中",
  "data-testid": "maintenance-icon"
};
const _hoisted_5$n = ["href"];
const _hoisted_6$j = {
  key: 2,
  class: "acks"
};
const _sfc_main$Z = /* @__PURE__ */ defineComponent({
  __name: "ProblemsList",
  props: {
    items: {},
    options: {}
  },
  emits: ["select"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    function colorFor(sev) {
      return props.options.triggerSeverity?.find((s) => s.priority === sev)?.color || "#999";
    }
    function labelFor(sev) {
      return props.options.triggerSeverity?.find((s) => s.priority === sev)?.severity || String(sev);
    }
    function isNew(p) {
      if (!props.options.highlightNewEvents) return false;
      const thr = parseDurationMs2(props.options.highlightNewerThan || "1h");
      return Date.now() - p.clock <= thr;
    }
    function parseDurationMs2(s) {
      const m = String(s).trim().match(/^(\d+(?:\.\d+)?)(ms|s|m|h|d)?$/i);
      if (!m) return 36e5;
      const n = Number(m[1]);
      const u = (m[2] || "s").toLowerCase();
      if (u === "ms") return n;
      if (u === "s") return n * 1e3;
      if (u === "m") return n * 6e4;
      if (u === "h") return n * 36e5;
      if (u === "d") return n * 864e5;
      return n * 1e3;
    }
    function cardStyle(p) {
      if (!props.options.highlightBackground) return void 0;
      return {
        background: colorFor(p.severity) + "22",
        borderColor: colorFor(p.severity)
      };
    }
    const fontSize = computed(() => props.options.fontSize || "100%");
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock(
        "ul",
        {
          class: "list",
          "data-testid": "problems-list",
          style: normalizeStyle({ fontSize: fontSize.value })
        },
        [
          (openBlock(true), createElementBlock(
            Fragment,
            null,
            renderList(__props.items, (p) => {
              return openBlock(), createElementBlock("li", {
                key: p.eventid,
                class: normalizeClass(["card", { blink: isNew(p), "hl-bg": __props.options.highlightBackground }]),
                style: normalizeStyle(cardStyle(p)),
                "data-testid": `problem-row-${p.eventid}`,
                onClick: ($event) => emit("select", p)
              }, [
                createElementVNode(
                  "span",
                  {
                    class: "sev-bar",
                    style: normalizeStyle({ background: colorFor(p.severity) }),
                    "aria-hidden": "true"
                  },
                  null,
                  4
                  /* STYLE */
                ),
                createVNode(SeverityBadge, {
                  severity: p.severity,
                  label: labelFor(p.severity),
                  color: colorFor(p.severity)
                }, null, 8, ["severity", "label", "color"]),
                createElementVNode(
                  "span",
                  _hoisted_2$I,
                  toDisplayString(p.name),
                  1
                  /* TEXT */
                ),
                createElementVNode(
                  "span",
                  _hoisted_3$A,
                  toDisplayString(p.hosts.map((h) => h.name || h.host).join(", ")),
                  1
                  /* TEXT */
                ),
                p.hostInMaintenance ? (openBlock(), createElementBlock("span", _hoisted_4$s, "🔧")) : createCommentVNode("v-if", true),
                p.url ? (openBlock(), createElementBlock("a", {
                  key: 1,
                  class: "url",
                  href: p.url,
                  target: "_blank",
                  rel: "noopener noreferrer",
                  "data-testid": "problem-url",
                  onClick: _cache[0] || (_cache[0] = withModifiers(() => {
                  }, ["stop"]))
                }, "外链", 8, _hoisted_5$n)) : createCommentVNode("v-if", true),
                p.acknowledges.length ? (openBlock(), createElementBlock(
                  "span",
                  _hoisted_6$j,
                  "确认 " + toDisplayString(p.acknowledges.length),
                  1
                  /* TEXT */
                )) : createCommentVNode("v-if", true)
              ], 14, _hoisted_1$W);
            }),
            128
            /* KEYED_FRAGMENT */
          ))
        ],
        4
        /* STYLE */
      );
    };
  }
});
const ProblemsList = /* @__PURE__ */ _export_sfc(_sfc_main$Z, [["__scopeId", "data-v-28b6c6e0"]]);
const ALLOWED_TAGS = /* @__PURE__ */ new Set([
  "b",
  "i",
  "em",
  "strong",
  "br",
  "p",
  "span",
  "code",
  "pre",
  "ul",
  "ol",
  "li"
]);
function sanitizeProblemHtml(input, allowDangerousHTML) {
  const raw = String(input || "");
  if (!raw) return "";
  let s = raw.replace(/<\s*(script|style)[^>]*>[\s\S]*?<\s*\/\s*\1\s*>/gi, "").replace(/\son\w+\s*=\s*("[^"]*"|'[^']*'|[^\s>]+)/gi, "").replace(/javascript:/gi, "");
  if (allowDangerousHTML) return s;
  s = s.replace(/<\/?([a-zA-Z0-9]+)(\s[^>]*)?>/g, (full, tag) => {
    const t = String(tag).toLowerCase();
    if (!ALLOWED_TAGS.has(t)) return "";
    if (full.startsWith("</")) return `</${t}>`;
    if (t === "br") return "<br/>";
    return `<${t}>`;
  });
  return s;
}
const _hoisted_1$V = {
  class: "tl-wrap",
  "data-testid": "problem-timeline",
  "aria-label": "问题时间线"
};
const _hoisted_2$H = ["viewBox"];
const _hoisted_3$z = ["x", "width", "fill", "data-testid"];
const _hoisted_4$r = ["cx", "fill"];
const _hoisted_5$m = {
  key: 1,
  class: "empty",
  "data-testid": "timeline-empty"
};
const width = 480;
const height = 36;
const _sfc_main$Y = /* @__PURE__ */ defineComponent({
  __name: "ProblemTimeline",
  props: {
    problem: {},
    timeRange: {},
    okColor: {},
    problemColor: {}
  },
  setup(__props, { expose: __expose }) {
    const props = __props;
    const ok2 = computed(() => props.okColor || "rgb(56,189,113)");
    const bad = computed(() => props.problemColor || "rgb(215,0,0)");
    const range = computed(() => {
      const from = props.timeRange?.from ?? props.problem.clock - 36e5;
      const to = props.timeRange?.to ?? Date.now();
      return { from, to: Math.max(to, from + 1) };
    });
    const points = computed(() => {
      const list = [...props.problem.events || []];
      if (!list.length) {
        list.push({
          clock: props.problem.clock / 1e3,
          value: 1,
          name: props.problem.name
        });
      }
      return list.map((e) => {
        const raw = Number(e.clock || 0);
        const clock = raw < 1e12 ? raw * 1e3 : raw;
        const value = Number(e.value ?? 1);
        return {
          clock,
          value,
          name: String(e.name || e.value_str || ""),
          isProblem: value === 1 || String(e.value) === "1"
        };
      }).filter((e) => Number.isFinite(e.clock)).sort((a, b) => a.clock - b.clock);
    });
    const segments = computed(() => {
      const { from, to } = range.value;
      const span = to - from;
      const pts = points.value;
      if (!pts.length) return [];
      const segs = [];
      for (let i = 0; i < pts.length; i++) {
        const start = Math.max(from, pts[i].clock);
        const end = i + 1 < pts.length ? Math.min(to, pts[i + 1].clock) : to;
        if (end <= start) continue;
        const x = (start - from) / span * width;
        const w = Math.max(2, (end - start) / span * width);
        const kind = pts[i].isProblem ? "problem" : "ok";
        const durMs = end - start;
        const dur = durMs < 6e4 ? `${Math.round(durMs / 1e3)}s` : durMs < 36e5 ? `${Math.round(durMs / 6e4)}m` : `${(durMs / 36e5).toFixed(1)}h`;
        segs.push({
          x,
          w,
          kind,
          title: `${kind === "problem" ? "PROBLEM" : "OK"} · ${dur} · ${pts[i].name || ""}`.trim()
        });
      }
      return segs;
    });
    const dots = computed(() => {
      const { from, to } = range.value;
      const span = to - from;
      return points.value.map((p) => ({
        x: (Math.min(to, Math.max(from, p.clock)) - from) / span * width,
        fill: p.isProblem ? bad.value : ok2.value,
        title: `${new Date(p.clock).toLocaleString()} · ${p.name || (p.isProblem ? "PROBLEM" : "OK")}`
      }));
    });
    __expose({ segments, dots, points });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$V, [
        segments.value.length ? (openBlock(), createElementBlock("svg", {
          key: 0,
          viewBox: `0 0 ${width} ${height}`,
          width: "100%",
          height,
          role: "img"
        }, [
          createElementVNode("rect", {
            x: "0",
            y: "10",
            width,
            height: "10",
            fill: "rgba(255,255,255,0.06)",
            rx: "2"
          }),
          (openBlock(true), createElementBlock(
            Fragment,
            null,
            renderList(segments.value, (s, i) => {
              return openBlock(), createElementBlock("rect", {
                key: "s" + i,
                x: s.x,
                y: "10",
                width: s.w,
                height: "10",
                fill: s.kind === "problem" ? bad.value : ok2.value,
                "data-testid": `timeline-seg-${s.kind}`
              }, [
                createElementVNode(
                  "title",
                  null,
                  toDisplayString(s.title),
                  1
                  /* TEXT */
                )
              ], 8, _hoisted_3$z);
            }),
            128
            /* KEYED_FRAGMENT */
          )),
          (openBlock(true), createElementBlock(
            Fragment,
            null,
            renderList(dots.value, (d, i) => {
              return openBlock(), createElementBlock("circle", {
                key: "d" + i,
                cx: d.x,
                cy: "15",
                r: "3.5",
                fill: d.fill,
                stroke: "#111",
                "stroke-width": "1",
                "data-testid": "timeline-dot"
              }, [
                createElementVNode(
                  "title",
                  null,
                  toDisplayString(d.title),
                  1
                  /* TEXT */
                )
              ], 8, _hoisted_4$r);
            }),
            128
            /* KEYED_FRAGMENT */
          ))
        ], 8, _hoisted_2$H)) : (openBlock(), createElementBlock("p", _hoisted_5$m, "无事件时间线"))
      ]);
    };
  }
});
const ProblemTimeline = /* @__PURE__ */ _export_sfc(_sfc_main$Y, [["__scopeId", "data-v-f4373cba"]]);
const _hoisted_1$U = {
  key: 0,
  class: "acks",
  "data-testid": "problem-acks"
};
const _hoisted_2$G = {
  key: 1,
  class: "empty",
  "data-testid": "problem-acks-empty"
};
const _sfc_main$X = /* @__PURE__ */ defineComponent({
  __name: "ProblemAcknowledges",
  props: {
    items: {}
  },
  setup(__props) {
    return (_ctx, _cache) => {
      return __props.items?.length ? (openBlock(), createElementBlock("ul", _hoisted_1$U, [
        (openBlock(true), createElementBlock(
          Fragment,
          null,
          renderList(__props.items, (a) => {
            return openBlock(), createElementBlock("li", {
              key: a.acknowledgeid || a.clock + a.user
            }, [
              createElementVNode(
                "time",
                null,
                toDisplayString(a.clock ? new Date(a.clock).toLocaleString() : ""),
                1
                /* TEXT */
              ),
              createElementVNode(
                "strong",
                null,
                toDisplayString(a.user || "用户"),
                1
                /* TEXT */
              ),
              createElementVNode(
                "span",
                null,
                toDisplayString(a.message),
                1
                /* TEXT */
              )
            ]);
          }),
          128
          /* KEYED_FRAGMENT */
        ))
      ])) : (openBlock(), createElementBlock("p", _hoisted_2$G, "暂无确认记录"));
    };
  }
});
const ProblemAcknowledges = /* @__PURE__ */ _export_sfc(_sfc_main$X, [["__scopeId", "data-v-83362a58"]]);
const _hoisted_1$T = {
  class: "tags",
  "data-testid": "tag-list"
};
const _sfc_main$W = /* @__PURE__ */ defineComponent({
  __name: "TagList",
  props: {
    tags: {}
  },
  setup(__props) {
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("span", _hoisted_1$T, [
        (openBlock(true), createElementBlock(
          Fragment,
          null,
          renderList(__props.tags, (t) => {
            return openBlock(), createElementBlock(
              "span",
              {
                key: t.tag + t.value,
                class: "tag"
              },
              toDisplayString(t.tag) + toDisplayString(t.value ? ":" + t.value : ""),
              1
              /* TEXT */
            );
          }),
          128
          /* KEYED_FRAGMENT */
        ))
      ]);
    };
  }
});
const TagList = /* @__PURE__ */ _export_sfc(_sfc_main$W, [["__scopeId", "data-v-33c2d20f"]]);
const _hoisted_1$S = {
  class: "details",
  "data-testid": "problem-details",
  role: "dialog",
  "aria-label": "问题详情"
};
const _hoisted_2$F = { "data-testid": "problem-eventid" };
const _hoisted_3$y = {
  key: 1,
  "data-testid": "problem-hosts"
};
const _hoisted_4$q = {
  key: 2,
  "data-testid": "problem-groups"
};
const _hoisted_5$l = {
  key: 3,
  "data-testid": "problem-tags"
};
const _hoisted_6$i = ["innerHTML"];
const _hoisted_7$f = {
  key: 5,
  "data-testid": "problem-opdata"
};
const _hoisted_8$9 = { "data-testid": "problem-expression" };
const _hoisted_9$8 = {
  key: 6,
  "data-testid": "problem-hist-value"
};
const _hoisted_10$6 = { "data-testid": "problem-manual-close" };
const _hoisted_11$5 = { "data-testid": "problem-suppressed" };
const _hoisted_12$4 = {
  "data-testid": "problem-items",
  class: "block"
};
const _hoisted_13$4 = {
  key: 0,
  class: "plain"
};
const _hoisted_14$4 = { key: 0 };
const _hoisted_15$4 = {
  key: 1,
  class: "empty"
};
const _hoisted_16$3 = {
  "data-testid": "problem-alerts",
  class: "block"
};
const _hoisted_17$3 = {
  key: 0,
  class: "plain"
};
const _hoisted_18$3 = {
  key: 1,
  class: "empty"
};
const _hoisted_19$3 = {
  "data-testid": "problem-events",
  class: "block"
};
const _hoisted_20$3 = {
  key: 0,
  class: "plain"
};
const _hoisted_21$2 = {
  key: 1,
  class: "empty"
};
const _hoisted_22$2 = {
  "data-testid": "problem-suppression",
  class: "block"
};
const _hoisted_23$1 = {
  key: 0,
  class: "plain"
};
const _hoisted_24$1 = { key: 0 };
const _hoisted_25$1 = {
  key: 1,
  class: "empty"
};
const _hoisted_26$1 = {
  class: "block",
  "data-testid": "problem-acks-section"
};
const _sfc_main$V = /* @__PURE__ */ defineComponent({
  __name: "ProblemDetails",
  props: {
    problem: {},
    options: {}
  },
  emits: ["close", "view-metrics"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    function onViewMetrics() {
      emit("view-metrics", props.problem);
    }
    const descHtml = computed(
      () => sanitizeProblemHtml(
        props.problem.description || props.problem.name,
        props.options.allowDangerousHTML
      )
    );
    const hostLabel = computed(
      () => props.problem.hosts.map((h) => h.name || h.host).filter(Boolean).join(", ")
    );
    const suppressionRows = computed(() => props.problem.suppression || []);
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("aside", _hoisted_1$S, [
        createElementVNode("header", null, [
          createElementVNode(
            "h4",
            null,
            toDisplayString(__props.problem.name),
            1
            /* TEXT */
          ),
          createElementVNode("button", {
            type: "button",
            "data-testid": "problem-details-close",
            onClick: _cache[0] || (_cache[0] = ($event) => emit("close"))
          }, " 关闭 ")
        ]),
        createVNode(ProblemStatusBar, {
          problem: __props.problem,
          "mark-ack": __props.options.markAckEvents,
          "ack-color": __props.options.ackEventColor,
          "ok-color": __props.options.okEventColor
        }, null, 8, ["problem", "mark-ack", "ack-color", "ok-color"]),
        __props.problem.items.length ? (openBlock(), createElementBlock("button", {
          key: 0,
          type: "button",
          "data-testid": "problem-view-metrics",
          onClick: onViewMetrics
        }, " 查看指标 ")) : createCommentVNode("v-if", true),
        createElementVNode(
          "p",
          _hoisted_2$F,
          "Event: " + toDisplayString(__props.problem.eventid),
          1
          /* TEXT */
        ),
        __props.options.hostField ? (openBlock(), createElementBlock(
          "p",
          _hoisted_3$y,
          " 主机: " + toDisplayString(hostLabel.value || "—"),
          1
          /* TEXT */
        )) : createCommentVNode("v-if", true),
        __props.options.hostGroups || __props.problem.groups.length ? (openBlock(), createElementBlock(
          "p",
          _hoisted_4$q,
          " 组: " + toDisplayString(__props.problem.groups.length ? __props.problem.groups.join(", ") : "—"),
          1
          /* TEXT */
        )) : createCommentVNode("v-if", true),
        __props.options.showTags || __props.problem.tags.length ? (openBlock(), createElementBlock("div", _hoisted_5$l, [
          _cache[1] || (_cache[1] = createTextVNode(
            " 标签: ",
            -1
            /* CACHED */
          )),
          createVNode(TagList, {
            tags: __props.problem.tags
          }, null, 8, ["tags"])
        ])) : createCommentVNode("v-if", true),
        __props.options.descriptionField ? (openBlock(), createElementBlock("div", {
          key: 4,
          class: "desc",
          "data-testid": "problem-description",
          innerHTML: descHtml.value
        }, null, 8, _hoisted_6$i)) : createCommentVNode("v-if", true),
        __props.options.opdataField || __props.problem.opdata ? (openBlock(), createElementBlock(
          "p",
          _hoisted_7$f,
          " 运维数据: " + toDisplayString(__props.problem.opdata || "—"),
          1
          /* TEXT */
        )) : createCommentVNode("v-if", true),
        createElementVNode(
          "p",
          _hoisted_8$9,
          " 表达式: " + toDisplayString(__props.problem.expression || "—"),
          1
          /* TEXT */
        ),
        __props.problem.historicalItemValue != null ? (openBlock(), createElementBlock(
          "p",
          _hoisted_9$8,
          " 历史值: " + toDisplayString(__props.problem.historicalItemValue),
          1
          /* TEXT */
        )) : createCommentVNode("v-if", true),
        createElementVNode(
          "p",
          _hoisted_10$6,
          " 手动关闭: " + toDisplayString(__props.problem.manual_close === "1" || __props.problem.manual_close === true ? "允许" : "否"),
          1
          /* TEXT */
        ),
        createElementVNode(
          "p",
          _hoisted_11$5,
          " 抑制: " + toDisplayString(__props.problem.suppressed ? "是" : "否"),
          1
          /* TEXT */
        ),
        createElementVNode("section", _hoisted_12$4, [
          createElementVNode(
            "h5",
            null,
            "监控项 (" + toDisplayString(__props.problem.items.length) + ")",
            1
            /* TEXT */
          ),
          __props.problem.items.length ? (openBlock(), createElementBlock("ul", _hoisted_13$4, [
            (openBlock(true), createElementBlock(
              Fragment,
              null,
              renderList(__props.problem.items, (it) => {
                return openBlock(), createElementBlock("li", {
                  key: it.itemid
                }, [
                  createElementVNode(
                    "strong",
                    null,
                    toDisplayString(it.name || it.key_),
                    1
                    /* TEXT */
                  ),
                  createElementVNode(
                    "code",
                    null,
                    toDisplayString(it.key_),
                    1
                    /* TEXT */
                  ),
                  it.lastvalue != null ? (openBlock(), createElementBlock(
                    "span",
                    _hoisted_14$4,
                    "= " + toDisplayString(it.lastvalue),
                    1
                    /* TEXT */
                  )) : createCommentVNode("v-if", true)
                ]);
              }),
              128
              /* KEYED_FRAGMENT */
            ))
          ])) : (openBlock(), createElementBlock("p", _hoisted_15$4, "无关联监控项"))
        ]),
        createElementVNode("section", _hoisted_16$3, [
          createElementVNode(
            "h5",
            null,
            "告警 (" + toDisplayString(__props.problem.alerts.length) + ")",
            1
            /* TEXT */
          ),
          __props.problem.alerts.length ? (openBlock(), createElementBlock("ul", _hoisted_17$3, [
            (openBlock(true), createElementBlock(
              Fragment,
              null,
              renderList(__props.problem.alerts, (a, i) => {
                return openBlock(), createElementBlock(
                  "li",
                  { key: i },
                  toDisplayString(String(
                    a.alertid || a.subject || a.message || JSON.stringify(a)
                  )),
                  1
                  /* TEXT */
                );
              }),
              128
              /* KEYED_FRAGMENT */
            ))
          ])) : (openBlock(), createElementBlock("p", _hoisted_18$3, "无告警记录"))
        ]),
        createElementVNode("section", _hoisted_19$3, [
          createElementVNode(
            "h5",
            null,
            "事件 (" + toDisplayString(__props.problem.events.length) + ")",
            1
            /* TEXT */
          ),
          __props.problem.events.length ? (openBlock(), createElementBlock("ul", _hoisted_20$3, [
            (openBlock(true), createElementBlock(
              Fragment,
              null,
              renderList(__props.problem.events, (e, i) => {
                return openBlock(), createElementBlock("li", { key: i }, [
                  createElementVNode(
                    "time",
                    null,
                    toDisplayString(e.clock ? new Date(
                      Number(e.clock) < 1e12 ? Number(e.clock) * 1e3 : Number(e.clock)
                    ).toLocaleString() : ""),
                    1
                    /* TEXT */
                  ),
                  createTextVNode(
                    " " + toDisplayString(String(
                      e.name || e.value_str || e.eventid || ""
                    )),
                    1
                    /* TEXT */
                  )
                ]);
              }),
              128
              /* KEYED_FRAGMENT */
            ))
          ])) : (openBlock(), createElementBlock("p", _hoisted_21$2, "无额外事件列表"))
        ]),
        createElementVNode("section", _hoisted_22$2, [
          createElementVNode(
            "h5",
            null,
            "抑制明细 (" + toDisplayString(suppressionRows.value.length) + ")",
            1
            /* TEXT */
          ),
          suppressionRows.value.length ? (openBlock(), createElementBlock("ul", _hoisted_23$1, [
            (openBlock(true), createElementBlock(
              Fragment,
              null,
              renderList(suppressionRows.value, (s, i) => {
                return openBlock(), createElementBlock("li", { key: i }, [
                  createTextVNode(
                    toDisplayString(String(
                      s.maintenanceid || s.userid || JSON.stringify(s)
                    )) + " ",
                    1
                    /* TEXT */
                  ),
                  s.suppress_until != null ? (openBlock(), createElementBlock(
                    "span",
                    _hoisted_24$1,
                    " until " + toDisplayString(s.suppress_until === 0 || s.suppress_until === "0" ? "无限期" : s.suppress_until),
                    1
                    /* TEXT */
                  )) : createCommentVNode("v-if", true)
                ]);
              }),
              128
              /* KEYED_FRAGMENT */
            ))
          ])) : (openBlock(), createElementBlock("p", _hoisted_25$1, "无抑制记录"))
        ]),
        __props.options.problemTimeline ? (openBlock(), createBlock(ProblemTimeline, {
          key: 7,
          problem: __props.problem
        }, null, 8, ["problem"])) : createCommentVNode("v-if", true),
        createElementVNode("section", _hoisted_26$1, [
          createElementVNode(
            "h5",
            null,
            "确认记录 (" + toDisplayString(__props.problem.acknowledges.length) + ")",
            1
            /* TEXT */
          ),
          createVNode(ProblemAcknowledges, {
            items: __props.problem.acknowledges
          }, null, 8, ["items"])
        ])
      ]);
    };
  }
});
const ProblemDetails = /* @__PURE__ */ _export_sfc(_sfc_main$V, [["__scopeId", "data-v-2b135c62"]]);
const ACK_ACTION = {
  CLOSE: 1,
  ACKNOWLEDGE: 2,
  ADD_MESSAGE: 4,
  CHANGE_SEVERITY: 8,
  UNACKNOWLEDGE: 16,
  SUPPRESS: 32,
  UNSUPPRESS: 64
};
function envLiveWrites(raw) {
  if (typeof raw === "boolean") return raw;
  if (raw != null)
    return String(raw) === "1" || String(raw).toLowerCase() === "true";
  if (typeof process !== "undefined" && process.env) {
    return process.env.ZABBIX_LIVE_WRITES === "1";
  }
  return false;
}
function panelAllows(action, panel2) {
  if (!panel2) return false;
  switch (action) {
    case "acknowledge":
    case "message":
      return Boolean(panel2.allowAcknowledge);
    case "unacknowledge":
      return Boolean(panel2.allowUnacknowledge);
    case "close":
      return Boolean(panel2.allowClose);
    case "changeSeverity":
      return Boolean(panel2.allowChangeSeverity);
    case "suppress":
      return Boolean(panel2.allowSuppress);
    case "unsuppress":
      return Boolean(panel2.allowUnsuppress);
    case "executeScript":
      return Boolean(panel2.allowExecuteScripts);
    default:
      return false;
  }
}
function evaluateWriteGate(action, gate = {}) {
  if (!panelAllows(action, gate.panel)) {
    return { allowed: false, reason: `面板未启用动作 ${action}` };
  }
  if (!gate.datasourceEnableWrites) {
    return { allowed: false, reason: "数据源未开启 enableWrites" };
  }
  if (!envLiveWrites(gate.liveWritesEnv)) {
    return { allowed: false, reason: "未设置 ZABBIX_LIVE_WRITES=1" };
  }
  if (gate.userCanWrite === false) {
    return { allowed: false, reason: "当前用户只读或无写权限" };
  }
  if (action === "close" && gate.eventManualClose === false) {
    return { allowed: false, reason: "事件/触发器不允许 manual_close" };
  }
  if (action === "executeScript") {
    if (!gate.hasScript && !gate.scriptid) {
      return { allowed: false, reason: "未选择脚本（禁止默认 scriptid=1）" };
    }
  }
  return { allowed: true };
}
function buildAcknowledgeMask(action, opts = {}) {
  let mask = 0;
  const payload = {};
  switch (action) {
    case "acknowledge":
      mask = ACK_ACTION.ACKNOWLEDGE;
      if (opts.message) mask |= ACK_ACTION.ADD_MESSAGE;
      break;
    case "message":
      mask = ACK_ACTION.ADD_MESSAGE;
      break;
    case "unacknowledge":
      mask = ACK_ACTION.UNACKNOWLEDGE;
      if (opts.message) mask |= ACK_ACTION.ADD_MESSAGE;
      break;
    case "close":
      mask = ACK_ACTION.CLOSE;
      if (opts.message) mask |= ACK_ACTION.ADD_MESSAGE;
      break;
    case "changeSeverity":
      mask = ACK_ACTION.CHANGE_SEVERITY;
      if (opts.message) mask |= ACK_ACTION.ADD_MESSAGE;
      payload.severity = Math.min(5, Math.max(0, Number(opts.severity ?? 0)));
      break;
    case "suppress":
      mask = ACK_ACTION.SUPPRESS;
      if (opts.message) mask |= ACK_ACTION.ADD_MESSAGE;
      payload.suppress_until = opts.suppressUntil != null ? Number(opts.suppressUntil) : 0;
      break;
    case "unsuppress":
      mask = ACK_ACTION.UNSUPPRESS;
      if (opts.message) mask |= ACK_ACTION.ADD_MESSAGE;
      break;
    default:
      throw new Error(`buildAcknowledgeMask does not support ${action}`);
  }
  if (action === "unacknowledge" && mask & ACK_ACTION.ACKNOWLEDGE) {
    throw new Error("unacknowledge must not include ACK bit");
  }
  if (action === "acknowledge" && mask & ACK_ACTION.CLOSE) {
    throw new Error("acknowledge must not include CLOSE bit");
  }
  if (action === "suppress" && payload.suppress_until === void 0) {
    throw new Error("suppress requires suppress_until");
  }
  if (action !== "suppress" && "suppress_until" in payload) {
    throw new Error("suppress_until only valid for suppress");
  }
  if (opts.message) payload.message = opts.message;
  payload.action = mask;
  return { action: mask, payload };
}
function resolveApi$1(preferredUid) {
  if (preferredUid) {
    const byUid2 = getRuntimeDataSource(String(preferredUid));
    if (byUid2?.mutate) return byUid2;
  }
  const all = listRuntimeDataSources();
  return all.find(
    (ds2) => ds2?.mutate && String(ds2.type || "").includes("zabbix")
  ) || all.find((ds2) => ds2?.mutate);
}
async function runProblemAction(problem, action, opts = {}) {
  const gate = evaluateWriteGate(action, {
    panel: opts.gate?.panel,
    datasourceEnableWrites: opts.gate?.datasourceEnableWrites,
    liveWritesEnv: opts.gate?.liveWritesEnv,
    userCanWrite: opts.gate?.userCanWrite,
    eventManualClose: opts.gate?.eventManualClose ?? (problem.manual_close === "1" || problem.manual_close === true || void 0),
    hasScript: opts.gate?.hasScript,
    scriptid: opts.scriptid
  });
  if (!gate.allowed) {
    return { status: "blocked", message: gate.reason, reason: gate.reason };
  }
  const api = resolveApi$1(problem.datasourceUid);
  if (!api?.mutate) return { status: "error", message: "当前数据源不支持动作" };
  if (action === "executeScript") {
    const scriptid = String(opts.scriptid || "").trim();
    if (!scriptid) {
      return {
        status: "blocked",
        reason: "scriptid 必填",
        message: "scriptid 必填"
      };
    }
    const hostid = problem.hosts[0]?.hostid;
    const res2 = await api.mutate({
      action: "zabbix.executeScript",
      payload: { scriptid, hostid, eventid: problem.eventid }
    });
    if (res2?.status === "success" && opts.reread) {
      try {
        await opts.reread(problem.eventid);
      } catch {
      }
    }
    return res2?.status === "success" ? { status: "success", message: res2.message, data: res2.data } : { status: "error", message: res2?.message || "动作失败" };
  }
  const built = buildAcknowledgeMask(action, {
    message: opts.message,
    severity: opts.severity ?? problem.severity,
    suppressUntil: opts.suppressUntil
  });
  const payload = {
    eventids: [problem.eventid],
    ...built.payload
  };
  if (!payload.message && opts.message) payload.message = opts.message;
  const res = await api.mutate({ action: "zabbix.acknowledge", payload });
  if (res?.status === "success" && opts.reread) {
    try {
      await opts.reread(problem.eventid);
    } catch {
    }
  }
  return res?.status === "success" ? { status: "success", message: res.message, data: res.data } : { status: "error", message: res?.message || "动作失败" };
}
const _hoisted_1$R = {
  key: 0,
  class: "modal",
  "data-testid": "ack-modal",
  role: "dialog"
};
const _hoisted_2$E = { class: "row" };
const _hoisted_3$x = { class: "row" };
const _hoisted_4$p = {
  key: 0,
  class: "sev-radios",
  "data-testid": "ack-modal-sev-radios"
};
const _hoisted_5$k = ["value", "data-testid"];
const _hoisted_6$h = {
  key: 1,
  class: "row"
};
const _hoisted_7$e = {
  key: 2,
  class: "hint",
  "data-testid": "ack-modal-close-blocked"
};
const _hoisted_8$8 = {
  class: "hint",
  "data-testid": "ack-modal-mask"
};
const _hoisted_9$7 = { key: 1 };
const _hoisted_10$5 = { key: 2 };
const _sfc_main$U = /* @__PURE__ */ defineComponent({
  __name: "AcknowledgeModal",
  props: {
    problem: {},
    open: { type: Boolean },
    mode: {}
  },
  emits: ["confirm", "cancel"],
  setup(__props, { expose: __expose, emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const message = ref("已确认");
    const severity = ref(3);
    const suppressUntil = ref(0);
    const doAck = ref(true);
    const doClose = ref(false);
    const doSev = ref(false);
    const canManualClose = computed(() => {
      const v = props.problem?.manual_close;
      return v === true || String(v) === "1";
    });
    const isComposite = computed(
      () => !props.mode || props.mode === "acknowledge" || props.mode === "composite"
    );
    watch(
      () => [props.open, props.problem?.eventid, props.mode],
      ([open]) => {
        if (!open) return;
        message.value = props.mode === "close" ? "关闭" : props.mode === "suppress" ? "抑制" : props.mode === "unacknowledge" ? "取消确认" : "已确认";
        severity.value = props.problem?.severity ?? 3;
        suppressUntil.value = 0;
        doAck.value = true;
        doClose.value = props.mode === "close";
        doSev.value = props.mode === "changeSeverity";
      }
    );
    function compositeMask() {
      let mask = ACK_ACTION.ADD_MESSAGE;
      if (doAck.value) mask |= ACK_ACTION.ACKNOWLEDGE;
      if (doClose.value && canManualClose.value) mask |= ACK_ACTION.CLOSE;
      if (doSev.value) mask |= ACK_ACTION.CHANGE_SEVERITY;
      return mask;
    }
    function onOk() {
      if (isComposite.value) {
        emit("confirm", {
          message: message.value,
          severity: doSev.value ? severity.value : void 0,
          actionMask: compositeMask(),
          acknowledge: doAck.value,
          close: doClose.value && canManualClose.value,
          changeSeverity: doSev.value
        });
        return;
      }
      emit("confirm", {
        message: message.value,
        severity: props.mode === "changeSeverity" ? severity.value : void 0,
        suppressUntil: props.mode === "suppress" ? suppressUntil.value : void 0
      });
    }
    __expose({ compositeMask, canManualClose });
    return (_ctx, _cache) => {
      return __props.open && __props.problem ? (openBlock(), createElementBlock("div", _hoisted_1$R, [
        createElementVNode(
          "p",
          null,
          toDisplayString(__props.mode === "close" ? "关闭" : __props.mode === "suppress" ? "抑制" : __props.mode === "unacknowledge" ? "取消确认" : __props.mode === "changeSeverity" ? "修改严重级别" : __props.mode === "unsuppress" ? "取消抑制" : "确认") + " 问题 " + toDisplayString(__props.problem.eventid) + "？ ",
          1
          /* TEXT */
        ),
        withDirectives(createElementVNode(
          "input",
          {
            "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => message.value = $event),
            "data-testid": "ack-modal-message",
            "aria-label": "动作备注"
          },
          null,
          512
          /* NEED_PATCH */
        ), [
          [vModelText, message.value]
        ]),
        isComposite.value ? (openBlock(), createElementBlock(
          Fragment,
          { key: 0 },
          [
            createElementVNode("label", _hoisted_2$E, [
              withDirectives(createElementVNode(
                "input",
                {
                  "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => doAck.value = $event),
                  type: "checkbox",
                  "data-testid": "ack-modal-do-ack"
                },
                null,
                512
                /* NEED_PATCH */
              ), [
                [vModelCheckbox, doAck.value]
              ]),
              _cache[8] || (_cache[8] = createTextVNode(
                " 确认问题 (Acknowledge) ",
                -1
                /* CACHED */
              ))
            ]),
            createElementVNode("label", _hoisted_3$x, [
              withDirectives(createElementVNode(
                "input",
                {
                  "onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => doSev.value = $event),
                  type: "checkbox",
                  "data-testid": "ack-modal-do-sev"
                },
                null,
                512
                /* NEED_PATCH */
              ), [
                [vModelCheckbox, doSev.value]
              ]),
              _cache[9] || (_cache[9] = createTextVNode(
                " 修改严重级别 ",
                -1
                /* CACHED */
              ))
            ]),
            doSev.value ? (openBlock(), createElementBlock("div", _hoisted_4$p, [
              (openBlock(), createElementBlock(
                Fragment,
                null,
                renderList([0, 1, 2, 3, 4, 5], (n) => {
                  return createElementVNode("label", {
                    key: n,
                    class: "row"
                  }, [
                    withDirectives(createElementVNode("input", {
                      "onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => severity.value = $event),
                      type: "radio",
                      value: n,
                      "data-testid": `ack-modal-sev-${n}`
                    }, null, 8, _hoisted_5$k), [
                      [
                        vModelRadio,
                        severity.value,
                        void 0,
                        { number: true }
                      ]
                    ]),
                    createTextVNode(
                      " " + toDisplayString(n),
                      1
                      /* TEXT */
                    )
                  ]);
                }),
                64
                /* STABLE_FRAGMENT */
              ))
            ])) : createCommentVNode("v-if", true),
            canManualClose.value ? (openBlock(), createElementBlock("label", _hoisted_6$h, [
              withDirectives(createElementVNode(
                "input",
                {
                  "onUpdate:modelValue": _cache[4] || (_cache[4] = ($event) => doClose.value = $event),
                  type: "checkbox",
                  "data-testid": "ack-modal-do-close"
                },
                null,
                512
                /* NEED_PATCH */
              ), [
                [vModelCheckbox, doClose.value]
              ]),
              _cache[10] || (_cache[10] = createTextVNode(
                " 关闭问题 ",
                -1
                /* CACHED */
              ))
            ])) : (openBlock(), createElementBlock("p", _hoisted_7$e, " 当前触发器不允许手动关闭 ")),
            createElementVNode(
              "p",
              _hoisted_8$8,
              " action mask = " + toDisplayString(compositeMask()),
              1
              /* TEXT */
            )
          ],
          64
          /* STABLE_FRAGMENT */
        )) : createCommentVNode("v-if", true),
        __props.mode === "changeSeverity" && !isComposite.value ? (openBlock(), createElementBlock("label", _hoisted_9$7, [
          _cache[11] || (_cache[11] = createTextVNode(
            " 严重级别 ",
            -1
            /* CACHED */
          )),
          withDirectives(createElementVNode(
            "input",
            {
              "onUpdate:modelValue": _cache[5] || (_cache[5] = ($event) => severity.value = $event),
              type: "number",
              min: "0",
              max: "5",
              "data-testid": "ack-modal-severity",
              "aria-label": "严重级别"
            },
            null,
            512
            /* NEED_PATCH */
          ), [
            [
              vModelText,
              severity.value,
              void 0,
              { number: true }
            ]
          ])
        ])) : createCommentVNode("v-if", true),
        __props.mode === "suppress" ? (openBlock(), createElementBlock("label", _hoisted_10$5, [
          _cache[12] || (_cache[12] = createTextVNode(
            " 抑制至 (unix，0=无限期) ",
            -1
            /* CACHED */
          )),
          withDirectives(createElementVNode(
            "input",
            {
              "onUpdate:modelValue": _cache[6] || (_cache[6] = ($event) => suppressUntil.value = $event),
              type: "number",
              min: "0",
              "data-testid": "ack-modal-suppress-until",
              "aria-label": "抑制截止时间"
            },
            null,
            512
            /* NEED_PATCH */
          ), [
            [
              vModelText,
              suppressUntil.value,
              void 0,
              { number: true }
            ]
          ])
        ])) : createCommentVNode("v-if", true),
        createElementVNode("button", {
          type: "button",
          "data-testid": "ack-modal-ok",
          onClick: onOk
        }, "确认"),
        createElementVNode("button", {
          type: "button",
          "data-testid": "ack-modal-cancel",
          onClick: _cache[7] || (_cache[7] = ($event) => emit("cancel"))
        }, " 取消 ")
      ])) : createCommentVNode("v-if", true);
    };
  }
});
const AcknowledgeModal = /* @__PURE__ */ _export_sfc(_sfc_main$U, [["__scopeId", "data-v-4f3b17fc"]]);
const _hoisted_1$Q = {
  key: 0,
  class: "modal",
  "data-testid": "script-modal",
  role: "dialog"
};
const _hoisted_2$D = {
  key: 0,
  "data-testid": "script-modal-loading"
};
const _hoisted_3$w = {
  key: 1,
  class: "err",
  "data-testid": "script-modal-error"
};
const _hoisted_4$o = ["value"];
const _hoisted_5$j = {
  key: 0,
  class: "empty",
  "data-testid": "script-modal-empty"
};
const _hoisted_6$g = {
  key: 1,
  class: "meta",
  "data-testid": "script-modal-meta"
};
const _hoisted_7$d = { key: 0 };
const _hoisted_8$7 = { class: "actions" };
const _hoisted_9$6 = ["disabled"];
const _sfc_main$T = /* @__PURE__ */ defineComponent({
  __name: "ExecuteScriptModal",
  props: {
    problem: {},
    open: { type: Boolean }
  },
  emits: ["confirm", "cancel"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const scripts = ref([]);
    const selectedId = ref("");
    const loading = ref(false);
    const loadError = ref("");
    const selected = computed(
      () => scripts.value.find((s) => s.scriptid === selectedId.value) || null
    );
    async function loadScripts() {
      scripts.value = [];
      selectedId.value = "";
      loadError.value = "";
      if (!props.problem) return;
      const api = getRuntimeDataSource(props.problem.datasourceUid);
      if (!api?.getMetadata) {
        loadError.value = "当前数据源无法加载脚本列表";
        return;
      }
      loading.value = true;
      try {
        const hostid = props.problem.hosts[0]?.hostid || "";
        const res = await api.getMetadata({
          type: "scripts",
          hostid,
          eventid: props.problem.eventid
        });
        const values = res?.values || [];
        scripts.value = values.map((s) => ({
          ...s,
          scriptid: String(s.scriptid ?? ""),
          name: String(s.name ?? s.scriptid ?? "")
        }));
        selectedId.value = "";
      } catch (e) {
        loadError.value = e?.message || "加载脚本失败";
      } finally {
        loading.value = false;
      }
    }
    watch(
      () => [props.open, props.problem?.eventid],
      ([open]) => {
        if (open && props.problem) void loadScripts();
      },
      { immediate: true }
    );
    function onConfirm() {
      const id = String(selectedId.value || "").trim();
      if (!id) return;
      emit("confirm", id);
    }
    return (_ctx, _cache) => {
      return __props.open && __props.problem ? (openBlock(), createElementBlock("div", _hoisted_1$Q, [
        createElementVNode(
          "p",
          null,
          "对 " + toDisplayString(__props.problem.hosts[0]?.name || __props.problem.eventid) + " 执行脚本",
          1
          /* TEXT */
        ),
        loading.value ? (openBlock(), createElementBlock("p", _hoisted_2$D, " 正在加载 script.get… ")) : loadError.value ? (openBlock(), createElementBlock(
          "p",
          _hoisted_3$w,
          toDisplayString(loadError.value),
          1
          /* TEXT */
        )) : (openBlock(), createElementBlock(
          Fragment,
          { key: 2 },
          [
            createElementVNode("label", null, [
              _cache[3] || (_cache[3] = createTextVNode(
                " 脚本 ",
                -1
                /* CACHED */
              )),
              withDirectives(createElementVNode(
                "select",
                {
                  "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => selectedId.value = $event),
                  "data-testid": "script-modal-select",
                  "aria-label": "选择脚本"
                },
                [
                  _cache[2] || (_cache[2] = createElementVNode(
                    "option",
                    { value: "" },
                    "请选择脚本",
                    -1
                    /* CACHED */
                  )),
                  (openBlock(true), createElementBlock(
                    Fragment,
                    null,
                    renderList(scripts.value, (s) => {
                      return openBlock(), createElementBlock("option", {
                        key: s.scriptid,
                        value: s.scriptid
                      }, toDisplayString(s.name) + " (" + toDisplayString(s.scriptid) + ") ", 9, _hoisted_4$o);
                    }),
                    128
                    /* KEYED_FRAGMENT */
                  ))
                ],
                512
                /* NEED_PATCH */
              ), [
                [vModelSelect, selectedId.value]
              ])
            ]),
            !scripts.value.length ? (openBlock(), createElementBlock("p", _hoisted_5$j, " 无可用脚本 ")) : createCommentVNode("v-if", true),
            selected.value ? (openBlock(), createElementBlock("dl", _hoisted_6$g, [
              createElementVNode("div", null, [
                _cache[4] || (_cache[4] = createElementVNode(
                  "dt",
                  null,
                  "确认",
                  -1
                  /* CACHED */
                )),
                createElementVNode(
                  "dd",
                  null,
                  toDisplayString(selected.value.confirmation || "—"),
                  1
                  /* TEXT */
                )
              ]),
              createElementVNode("div", null, [
                _cache[5] || (_cache[5] = createElementVNode(
                  "dt",
                  null,
                  "范围",
                  -1
                  /* CACHED */
                )),
                createElementVNode(
                  "dd",
                  null,
                  toDisplayString(selected.value.scope || "—"),
                  1
                  /* TEXT */
                )
              ]),
              createElementVNode("div", null, [
                _cache[6] || (_cache[6] = createElementVNode(
                  "dt",
                  null,
                  "访问",
                  -1
                  /* CACHED */
                )),
                createElementVNode(
                  "dd",
                  null,
                  toDisplayString(selected.value.host_access || "—"),
                  1
                  /* TEXT */
                )
              ]),
              selected.value.description ? (openBlock(), createElementBlock("div", _hoisted_7$d, [
                _cache[7] || (_cache[7] = createElementVNode(
                  "dt",
                  null,
                  "说明",
                  -1
                  /* CACHED */
                )),
                createElementVNode(
                  "dd",
                  null,
                  toDisplayString(selected.value.description),
                  1
                  /* TEXT */
                )
              ])) : createCommentVNode("v-if", true)
            ])) : createCommentVNode("v-if", true)
          ],
          64
          /* STABLE_FRAGMENT */
        )),
        createElementVNode("div", _hoisted_8$7, [
          createElementVNode("button", {
            type: "button",
            "data-testid": "script-modal-ok",
            disabled: !selectedId.value,
            onClick: onConfirm
          }, " 执行 ", 8, _hoisted_9$6),
          createElementVNode("button", {
            type: "button",
            "data-testid": "script-modal-cancel",
            onClick: _cache[1] || (_cache[1] = ($event) => emit("cancel"))
          }, " 取消 ")
        ])
      ])) : createCommentVNode("v-if", true);
    };
  }
});
const ExecuteScriptModal = /* @__PURE__ */ _export_sfc(_sfc_main$T, [["__scopeId", "data-v-7e46303a"]]);
const _hoisted_1$P = { class: "toolbar" };
const _hoisted_2$C = {
  key: 0,
  class: "error",
  role: "alert"
};
const _hoisted_3$v = {
  key: 1,
  class: "ok",
  role: "status"
};
const _hoisted_4$n = {
  key: 2,
  class: "empty",
  "data-testid": "problems-empty"
};
const _hoisted_5$i = {
  key: 5,
  class: "pager"
};
const _hoisted_6$f = ["disabled"];
const _hoisted_7$c = ["disabled"];
const _sfc_main$S = /* @__PURE__ */ defineComponent({
  __name: "ProblemsPanel",
  props: {
    id: {},
    data: {},
    options: {},
    fieldConfig: {},
    width: {},
    height: {},
    timeRange: {},
    replaceVariables: { type: Function },
    title: {},
    transparent: { type: Boolean }
  },
  setup(__props) {
    const props = __props;
    const options = computed(
      () => migrateProblemsPanelOptions(props.options || {})
    );
    const model = computed(
      () => problemsFromPanelData(props.data, options.value)
    );
    const problems = computed(() => model.value.problems);
    const notices = computed(() => model.value.notices);
    const page = ref(0);
    const selected = ref(null);
    const message = ref("");
    const actionError = ref("");
    const actionOk = ref("");
    const ackOpen = ref(false);
    const ackMode = ref("acknowledge");
    const ackTarget = ref(null);
    const scriptOpen = ref(false);
    const scriptTarget = ref(null);
    const pageSize = computed(() => options.value.pageSize || 10);
    const pageItems = computed(() => {
      const start = page.value * pageSize.value;
      return problems.value.slice(start, start + pageSize.value);
    });
    function dsEnableWrites(uid) {
      const ds2 = getRuntimeDataSource(uid);
      return Boolean(ds2?.enableWrites);
    }
    async function reread(eventid, uid) {
      const ds2 = getRuntimeDataSource(uid);
      if (!ds2?.getMetadata) return;
      await ds2.getMetadata({ type: "problemDetail", eventid });
    }
    function openAck(p, mode2) {
      ackTarget.value = p;
      ackMode.value = mode2;
      ackOpen.value = true;
    }
    function openScript(p) {
      if (!options.value.allowExecuteScripts) return;
      scriptTarget.value = p;
      scriptOpen.value = true;
    }
    async function execute(p, action, opts = {}) {
      actionError.value = "";
      actionOk.value = "";
      const res = await runProblemAction(p, action, {
        message: opts.message ?? message.value,
        severity: opts.severity,
        suppressUntil: opts.suppressUntil,
        scriptid: opts.scriptid,
        gate: {
          panel: options.value,
          datasourceEnableWrites: dsEnableWrites(p.datasourceUid),
          liveWritesEnv: typeof process !== "undefined" ? process.env.ZABBIX_LIVE_WRITES : void 0,
          userCanWrite: true,
          eventManualClose: p.manual_close === "1" || p.manual_close === true,
          hasScript: Boolean(opts.scriptid),
          scriptid: opts.scriptid
        },
        reread: (eventid) => reread(eventid, p.datasourceUid)
      });
      if (res.status !== "success")
        actionError.value = res.message || res.reason || "动作失败";
      else actionOk.value = res.message || "已提交";
    }
    async function onAckConfirm(payload) {
      const p = ackTarget.value;
      ackOpen.value = false;
      if (!p) return;
      await execute(
        p,
        ackMode.value === "message" ? "message" : ackMode.value,
        payload
      );
      ackTarget.value = null;
    }
    async function onScriptConfirm(scriptid) {
      const p = scriptTarget.value;
      scriptOpen.value = false;
      if (!p) return;
      await execute(p, "executeScript", { scriptid });
      scriptTarget.value = null;
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock(
        "div",
        {
          class: "zbx-problems",
          "data-testid": "zabbix-problems-panel",
          style: normalizeStyle({
            width: __props.width + "px",
            height: __props.height + "px",
            fontSize: options.value.fontSize
          })
        },
        [
          createElementVNode("div", _hoisted_1$P, [
            createElementVNode(
              "span",
              null,
              "问题 " + toDisplayString(problems.value.length),
              1
              /* TEXT */
            ),
            withDirectives(createElementVNode(
              "input",
              {
                "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => message.value = $event),
                placeholder: "动作备注",
                "data-testid": "ack-message",
                "aria-label": "动作备注"
              },
              null,
              512
              /* NEED_PATCH */
            ), [
              [vModelText, message.value]
            ])
          ]),
          (openBlock(true), createElementBlock(
            Fragment,
            null,
            renderList(notices.value, (n) => {
              return openBlock(), createElementBlock(
                "div",
                {
                  key: n,
                  class: "notice",
                  role: "status"
                },
                toDisplayString(n),
                1
                /* TEXT */
              );
            }),
            128
            /* KEYED_FRAGMENT */
          )),
          actionError.value ? (openBlock(), createElementBlock(
            "div",
            _hoisted_2$C,
            toDisplayString(actionError.value),
            1
            /* TEXT */
          )) : createCommentVNode("v-if", true),
          actionOk.value ? (openBlock(), createElementBlock(
            "div",
            _hoisted_3$v,
            toDisplayString(actionOk.value),
            1
            /* TEXT */
          )) : createCommentVNode("v-if", true),
          !problems.value.length ? (openBlock(), createElementBlock("div", _hoisted_4$n, " 当前筛选条件下没有 Zabbix 问题 ")) : options.value.layout === "table" ? (openBlock(), createBlock(ProblemsTable, {
            key: 3,
            items: problems.value,
            options: options.value,
            onSelect: _cache[1] || (_cache[1] = ($event) => selected.value = $event),
            onAcknowledge: _cache[2] || (_cache[2] = ($event) => openAck($event, "acknowledge")),
            onUnacknowledge: _cache[3] || (_cache[3] = ($event) => openAck($event, "unacknowledge")),
            onClose: _cache[4] || (_cache[4] = ($event) => openAck($event, "close")),
            onSeverity: _cache[5] || (_cache[5] = ($event) => openAck($event, "changeSeverity")),
            onSuppress: _cache[6] || (_cache[6] = ($event) => openAck($event, "suppress")),
            onUnsuppress: _cache[7] || (_cache[7] = ($event) => openAck($event, "unsuppress")),
            onScript: openScript,
            "onUpdate:options": _cache[8] || (_cache[8] = (o) => props.onOptionsChange?.(o))
          }, null, 8, ["items", "options"])) : (openBlock(), createBlock(ProblemsList, {
            key: 4,
            items: pageItems.value,
            options: options.value,
            onSelect: _cache[9] || (_cache[9] = ($event) => selected.value = $event)
          }, null, 8, ["items", "options"])),
          options.value.layout === "list" && problems.value.length > pageSize.value ? (openBlock(), createElementBlock("div", _hoisted_5$i, [
            createElementVNode("button", {
              type: "button",
              disabled: page.value === 0,
              "data-testid": "problems-prev",
              onClick: _cache[10] || (_cache[10] = ($event) => page.value--)
            }, " 上一页 ", 8, _hoisted_6$f),
            createElementVNode(
              "span",
              null,
              toDisplayString(page.value + 1) + " / " + toDisplayString(Math.max(1, Math.ceil(problems.value.length / pageSize.value))),
              1
              /* TEXT */
            ),
            createElementVNode("button", {
              type: "button",
              disabled: (page.value + 1) * pageSize.value >= problems.value.length,
              "data-testid": "problems-next",
              onClick: _cache[11] || (_cache[11] = ($event) => page.value++)
            }, " 下一页 ", 8, _hoisted_7$c)
          ])) : createCommentVNode("v-if", true),
          selected.value && options.value.showDetails ? (openBlock(), createBlock(ProblemDetails, {
            key: 6,
            problem: selected.value,
            options: options.value,
            onClose: _cache[12] || (_cache[12] = ($event) => selected.value = null)
          }, null, 8, ["problem", "options"])) : createCommentVNode("v-if", true),
          createVNode(AcknowledgeModal, {
            problem: ackTarget.value,
            open: ackOpen.value,
            mode: ackMode.value,
            onConfirm: onAckConfirm,
            onCancel: _cache[13] || (_cache[13] = ($event) => {
              ackOpen.value = false;
              ackTarget.value = null;
            })
          }, null, 8, ["problem", "open", "mode"]),
          createVNode(ExecuteScriptModal, {
            problem: scriptTarget.value,
            open: scriptOpen.value,
            onConfirm: onScriptConfirm,
            onCancel: _cache[14] || (_cache[14] = ($event) => {
              scriptOpen.value = false;
              scriptTarget.value = null;
            })
          }, null, 8, ["problem", "open"])
        ],
        4
        /* STYLE */
      );
    };
  }
});
const ProblemsPanel = /* @__PURE__ */ _export_sfc(_sfc_main$S, [["__scopeId", "data-v-a4b2e9d4"]]);
const _hoisted_1$O = {
  class: "sev-editor",
  "data-testid": "severity-color-editor"
};
const _hoisted_2$B = ["data-testid"];
const _hoisted_3$u = { class: "name" };
const _sfc_main$R = /* @__PURE__ */ defineComponent({
  __name: "SeverityColorEditor",
  props: {
    value: {},
    context: {}
  },
  emits: ["update:value"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    function list() {
      const v = props.value?.length ? props.value : DEFAULT_SEVERITY;
      return v.map((s) => ({ ...s }));
    }
    function patch(i, partial) {
      const next = list().map((s, idx) => idx === i ? { ...s, ...partial } : s);
      emit("update:value", next);
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$O, [
        (openBlock(true), createElementBlock(
          Fragment,
          null,
          renderList(list(), (s, i) => {
            return openBlock(), createElementBlock("div", {
              key: s.priority,
              class: "row",
              "data-testid": `severity-row-${s.priority}`
            }, [
              createElementVNode(
                "span",
                _hoisted_3$u,
                toDisplayString(s.severity),
                1
                /* TEXT */
              ),
              createVNode(unref(GInput), {
                "model-value": s.color,
                "test-id": `severity-color-${s.priority}`,
                "aria-label": "严重性颜色",
                "onUpdate:modelValue": ($event) => patch(i, { color: String($event) })
              }, null, 8, ["model-value", "test-id", "onUpdate:modelValue"]),
              createElementVNode(
                "span",
                {
                  class: "swatch",
                  style: normalizeStyle({ background: s.color }),
                  "aria-hidden": "true"
                },
                null,
                4
                /* STYLE */
              ),
              createVNode(unref(_sfc_main$19), {
                checked: s.show !== false,
                "test-id": `severity-show-${s.priority}`,
                "onUpdate:checked": ($event) => patch(i, { show: $event })
              }, null, 8, ["checked", "test-id", "onUpdate:checked"])
            ], 8, _hoisted_2$B);
          }),
          128
          /* KEYED_FRAGMENT */
        ))
      ]);
    };
  }
});
const SeverityColorEditor = /* @__PURE__ */ _export_sfc(_sfc_main$R, [["__scopeId", "data-v-3ad6848a"]]);
const _hoisted_1$N = {
  class: "reset-cols",
  "data-testid": "reset-columns-editor"
};
const _hoisted_2$A = {
  key: 0,
  class: "hint"
};
const _sfc_main$Q = /* @__PURE__ */ defineComponent({
  __name: "ResetColumnsEditor",
  props: {
    value: {}
  },
  emits: ["update:value"],
  setup(__props, { emit: __emit }) {
    const emit = __emit;
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$N, [
        createVNode(unref(GButton), {
          size: "sm",
          variant: "secondary",
          "test-id": "reset-columns-btn",
          onClick: _cache[0] || (_cache[0] = ($event) => emit("update:value", []))
        }, {
          default: withCtx(() => [..._cache[1] || (_cache[1] = [
            createTextVNode(
              " 重置列宽 ",
              -1
              /* CACHED */
            )
          ])]),
          _: 1
          /* STABLE */
        }),
        (__props.value || []).length ? (openBlock(), createElementBlock(
          "span",
          _hoisted_2$A,
          "已自定义 " + toDisplayString(__props.value.length) + " 列",
          1
          /* TEXT */
        )) : createCommentVNode("v-if", true)
      ]);
    };
  }
});
const ResetColumnsEditor = /* @__PURE__ */ _export_sfc(_sfc_main$Q, [["__scopeId", "data-v-1745230d"]]);
const FONT_SIZES = [
  "80%",
  "90%",
  "100%",
  "110%",
  "120%",
  "130%",
  "150%",
  "160%",
  "180%",
  "200%",
  "220%",
  "250%"
];
const plugin$3 = new VuePanelPlugin(
  {
    id: "alexanderzobnin-zabbix-triggers-panel",
    name: "Zabbix Problems",
    state: "stable"
  },
  ProblemsPanel
).setPanelOptions((builder) => {
  builder.addRadio(
    {
      id: "layout",
      path: "layout",
      name: "布局",
      category: ["显示"],
      editor: "radio",
      settings: {
        options: [
          { label: "表格", value: "table" },
          { label: "列表", value: "list" }
        ]
      }
    },
    "table"
  ).addRadio(
    {
      id: "sortProblems",
      path: "sortProblems",
      name: "排序",
      category: ["显示"],
      editor: "radio",
      settings: {
        options: [
          { label: "默认", value: "default" },
          { label: "最后变更", value: "lastchange" },
          { label: "严重性", value: "priority" }
        ]
      }
    },
    "lastchange"
  ).addSelect(
    {
      id: "fontSize",
      path: "fontSize",
      name: "字号",
      category: ["显示"],
      editor: "select",
      settings: {
        options: FONT_SIZES.map((v) => ({ label: v, value: v }))
      }
    },
    "100%"
  ).addSelect(
    {
      id: "pageSize",
      path: "pageSize",
      name: "每页条数",
      category: ["显示"],
      editor: "select",
      settings: {
        options: [5, 10, 20, 25, 50, 100].map((n) => ({
          label: String(n),
          value: n
        }))
      }
    },
    10
  ).addBoolean(
    {
      id: "problemTimeline",
      path: "problemTimeline",
      name: "问题时间线",
      category: ["显示"],
      editor: "boolean"
    },
    true
  ).addBoolean(
    {
      id: "highlightBackground",
      path: "highlightBackground",
      name: "高亮背景",
      category: ["显示"],
      editor: "boolean"
    },
    false
  ).addBoolean(
    {
      id: "highlightNewEvents",
      path: "highlightNewEvents",
      name: "高亮新事件",
      category: ["显示"],
      editor: "boolean"
    },
    false
  ).addText(
    {
      id: "highlightNewerThan",
      path: "highlightNewerThan",
      name: "新事件阈值",
      category: ["显示"],
      editor: "text"
    },
    "1h"
  ).addBoolean(
    {
      id: "customLastChangeFormat",
      path: "customLastChangeFormat",
      name: "自定义时间格式",
      category: ["显示"],
      editor: "boolean"
    },
    false
  ).addText(
    {
      id: "lastChangeFormat",
      path: "lastChangeFormat",
      name: "时间格式",
      category: ["显示"],
      editor: "text"
    },
    ""
  ).addBoolean(
    {
      id: "markAckEvents",
      path: "markAckEvents",
      name: "标记已确认事件",
      category: ["显示"],
      editor: "boolean"
    },
    false
  ).addBoolean(
    {
      id: "hostField",
      path: "hostField",
      name: "主机",
      category: ["字段"],
      editor: "boolean"
    },
    true
  ).addBoolean(
    {
      id: "hostTechNameField",
      path: "hostTechNameField",
      name: "主机技术名",
      category: ["字段"],
      editor: "boolean"
    },
    false
  ).addBoolean(
    {
      id: "hostGroups",
      path: "hostGroups",
      name: "主机组",
      category: ["字段"],
      editor: "boolean"
    },
    false
  ).addBoolean(
    {
      id: "hostProxy",
      path: "hostProxy",
      name: "代理",
      category: ["字段"],
      editor: "boolean"
    },
    false
  ).addBoolean(
    {
      id: "showTags",
      path: "showTags",
      name: "标签",
      category: ["字段"],
      editor: "boolean"
    },
    true
  ).addBoolean(
    {
      id: "statusField",
      path: "statusField",
      name: "状态",
      category: ["字段"],
      editor: "boolean"
    },
    true
  ).addBoolean(
    {
      id: "statusIcon",
      path: "statusIcon",
      name: "状态图标",
      category: ["字段"],
      editor: "boolean"
    },
    false
  ).addBoolean(
    {
      id: "severityField",
      path: "severityField",
      name: "严重性",
      category: ["字段"],
      editor: "boolean"
    },
    true
  ).addBoolean(
    {
      id: "ackField",
      path: "ackField",
      name: "确认",
      category: ["字段"],
      editor: "boolean"
    },
    true
  ).addBoolean(
    {
      id: "ageField",
      path: "ageField",
      name: "年龄",
      category: ["字段"],
      editor: "boolean"
    },
    false
  ).addBoolean(
    {
      id: "opdataField",
      path: "opdataField",
      name: "运行数据",
      category: ["字段"],
      editor: "boolean"
    },
    false
  ).addBoolean(
    {
      id: "descriptionField",
      path: "descriptionField",
      name: "描述",
      category: ["字段"],
      editor: "boolean"
    },
    true
  ).addBoolean(
    {
      id: "descriptionAtNewLine",
      path: "descriptionAtNewLine",
      name: "描述换行",
      category: ["字段"],
      editor: "boolean"
    },
    false
  ).addBoolean(
    {
      id: "showDatasourceName",
      path: "showDatasourceName",
      name: "数据源名",
      category: ["字段"],
      editor: "boolean"
    },
    false
  ).addText(
    {
      id: "customTagColumns",
      path: "customTagColumns",
      name: "标签列",
      category: ["字段"],
      editor: "text"
    },
    ""
  ).addCustomEditor(
    {
      id: "triggerSeverity",
      path: "triggerSeverity",
      name: "严重性颜色",
      category: ["严重级别"],
      editor: "custom",
      customEditor: SeverityColorEditor
    },
    DEFAULT_SEVERITY.map((s) => ({ ...s }))
  ).addCustomEditor(
    {
      id: "resizedColumns",
      path: "resizedColumns",
      name: "列宽",
      category: ["显示"],
      editor: "custom",
      customEditor: ResetColumnsEditor
    },
    []
  ).addBoolean(
    {
      id: "allowDangerousHTML",
      path: "allowDangerousHTML",
      name: "允许危险 HTML",
      category: ["安全"],
      editor: "boolean"
    },
    false
  ).addBoolean(
    {
      id: "allowAcknowledge",
      path: "allowAcknowledge",
      name: "允许确认",
      category: ["动作"],
      editor: "boolean"
    },
    false
  ).addBoolean(
    {
      id: "allowUnacknowledge",
      path: "allowUnacknowledge",
      name: "允许取消确认",
      category: ["动作"],
      editor: "boolean"
    },
    false
  ).addBoolean(
    {
      id: "allowClose",
      path: "allowClose",
      name: "允许关闭",
      category: ["动作"],
      editor: "boolean"
    },
    false
  ).addBoolean(
    {
      id: "allowChangeSeverity",
      path: "allowChangeSeverity",
      name: "允许改严重级别",
      category: ["动作"],
      editor: "boolean"
    },
    false
  ).addBoolean(
    {
      id: "allowSuppress",
      path: "allowSuppress",
      name: "允许抑制",
      category: ["动作"],
      editor: "boolean"
    },
    false
  ).addBoolean(
    {
      id: "allowUnsuppress",
      path: "allowUnsuppress",
      name: "允许取消抑制",
      category: ["动作"],
      editor: "boolean"
    },
    false
  ).addBoolean(
    {
      id: "allowExecuteScripts",
      path: "allowExecuteScripts",
      name: "允许执行脚本",
      category: ["动作"],
      editor: "boolean"
    },
    false
  ).addBoolean(
    {
      id: "showDetails",
      path: "showDetails",
      name: "显示详情",
      category: ["布局"],
      editor: "boolean"
    },
    true
  ).addColor(
    {
      id: "okEventColor",
      path: "okEventColor",
      name: "OK 颜色",
      category: ["严重级别"],
      editor: "color"
    },
    "rgb(56, 189, 113)"
  ).addColor(
    {
      id: "ackEventColor",
      path: "ackEventColor",
      name: "确认颜色",
      category: ["严重级别"],
      editor: "color"
    },
    "rgb(56, 219, 156)"
  );
}).setPanelMigrationHandler(migrateProblemsPanel).setMigrationHandler((options) => ({
  options: migrateProblemsPanelOptions({
    ...DEFAULT_PROBLEMS_OPTIONS,
    ...options
  })
})).setRuntimeConsumedPaths(Object.keys(DEFAULT_PROBLEMS_OPTIONS)).register();
const module$4 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
  __proto__: null,
  default: plugin$3
}, Symbol.toStringTag, { value: "Module" }));
const DS_QUERY_SCHEMA = 12;
const DS_CONFIG_SCHEMA = 4;
const TYPE_MAP = {
  "0": "0",
  metrics: "0",
  "1": "1",
  services: "1",
  "2": "2",
  text: "2",
  "3": "3",
  itemid: "3",
  "4": "4",
  triggers: "4",
  "5": "5",
  problems: "5",
  "6": "6",
  macros: "6"
};
function normalizeZabbixQueryType(value) {
  const key = String(value ?? "0").toLowerCase();
  if (TYPE_MAP[key]) return TYPE_MAP[key];
  return key;
}
const filter = () => ({ filter: "" });
const DEFAULT_ZABBIX_QUERY = {
  refId: "A",
  schema: DS_QUERY_SCHEMA,
  queryType: "0",
  group: filter(),
  host: filter(),
  application: filter(),
  itemTag: filter(),
  item: filter(),
  proxy: filter(),
  trigger: filter(),
  tags: filter(),
  macro: filter(),
  itemids: "",
  textFilter: "",
  useCaptureGroups: false,
  itServiceFilter: "",
  slaFilter: "",
  slaProperty: "sli",
  slaInterval: "none",
  showProblems: "problems",
  countTriggersBy: "",
  functions: [],
  options: {
    useTrends: "default",
    acknowledged: 2,
    sortProblems: "default",
    limit: 1001
  }
};
const DEFAULT_ZABBIX_OPTIONS = {
  dataMode: "live",
  authPlacement: "auto",
  enableWrites: false,
  authType: "token",
  trends: true,
  trendsFrom: "7d",
  trendsRange: "4d",
  cacheTTL: "1h",
  metadataPageLimit: 1e3,
  historyPageLimit: 1e4,
  historyBatchSize: 100,
  historyConcurrency: 4,
  timeout: 3e4,
  queryTimeout: 6e4,
  dbConnectionEnable: false,
  disableReadOnlyUsersAck: false,
  disableDataAlignment: false,
  schema: DS_CONFIG_SCHEMA
};
const LEGACY_SLA_PROPERTY = {
  sla: "sli",
  okTime: "uptime",
  downtimeTime: "downtime",
  problemTime: "downtime"
};
const LEGACY_SLA_INTERVAL = {
  day: "1d",
  week: "1w",
  month: "1M",
  hour: "1h"
};
function mapLegacySLAProperty(value) {
  const s = String(value ?? "sli");
  return LEGACY_SLA_PROPERTY[s] ?? s;
}
function mapLegacySLAInterval(value) {
  const s = String(value ?? "none");
  return LEGACY_SLA_INTERVAL[s] ?? s;
}
function deepClone$2(v) {
  try {
    return structuredClone(v);
  } catch {
    return JSON.parse(JSON.stringify(v));
  }
}
function asFilter(value) {
  if (value && typeof value === "object" && !Array.isArray(value)) {
    const o = value;
    return {
      filter: String(o.filter ?? ""),
      ...o.name != null ? { name: String(o.name) } : {},
      ...Array.isArray(o.ids) ? { ids: o.ids.map(String) } : {}
    };
  }
  return { filter: "" };
}
function convertToRegex(str) {
  if (str) return `/${str}/`;
  return "/.*/";
}
function normalizeZabbixFunction(input) {
  const o = input && typeof input === "object" ? input : {};
  const def = o.def && typeof o.def === "object" ? o.def : {};
  let name = String(o.name ?? def.name ?? "unknown");
  if (name === "percentil") name = "percentile";
  const params = Array.isArray(o.params) ? o.params : [];
  const out = { name, params };
  if (o.text != null) out.text = String(o.text);
  if (o.added != null) out.added = Boolean(o.added);
  return out;
}
function fixTargetGroup(target) {
  if (Array.isArray(target.group)) {
    target.group = { filter: "" };
  }
}
function isGrafana2target(target) {
  const mode2 = target.mode;
  if (mode2 == null || mode2 === 0 || mode2 === 2) {
    const item = target.item;
    const host = target.host;
    if ((target.hostFilter || target.itemFilter || target.downsampleFunction || host && host.host) && item?.filter === void 0 && host?.filter === void 0) {
      return true;
    }
  }
  return false;
}
function migrateFrom2To3version(target) {
  const group = target.group && typeof target.group === "object" ? target.group : {};
  const host = target.host && typeof target.host === "object" ? target.host : {};
  const application = target.application && typeof target.application === "object" ? target.application : {};
  const item = target.item && typeof target.item === "object" ? target.item : {};
  const macro = target.macro && typeof target.macro === "object" ? target.macro : {};
  target.group = {
    filter: group.name === "*" ? "/.*/" : String(group.name ?? group.filter ?? "")
  };
  target.host = {
    filter: host.name === "*" ? convertToRegex(target.hostFilter) : String(host.name ?? host.filter ?? "")
  };
  target.application = {
    filter: application.name === "*" ? "" : String(application.name ?? application.filter ?? "")
  };
  target.item = {
    filter: item.name === "All" ? convertToRegex(target.itemFilter) : String(item.name ?? item.filter ?? "")
  };
  target.macro = {
    filter: macro.macro === "*" ? convertToRegex(target.macroFilter) : String(macro.macro ?? macro.filter ?? "")
  };
}
function migrateFunctions(target) {
  if (!Array.isArray(target.functions)) {
    target.functions = [];
    return;
  }
  target.functions = target.functions.map((f) => normalizeZabbixFunction(f));
}
function migrateQueryType(target) {
  if (target.queryType === void 0) {
    if (target.mode === "Metrics") {
      target.queryType = "0";
    } else if (target.mode !== void 0) {
      target.queryType = target.mode;
      delete target.mode;
    }
  }
  if (typeof target.queryType === "number") {
    target.queryType = String(target.queryType);
  }
  if (target.queryType != null) {
    target.queryType = normalizeZabbixQueryType(target.queryType);
  }
}
function migrateSLA(target) {
  if (normalizeZabbixQueryType(target.queryType) === "1" && !target.slaInterval) {
    target.slaInterval = "none";
  }
}
function migrateProblemSort(target) {
  const options = target.options && typeof target.options === "object" ? target.options : null;
  if (options?.sortProblems === "priority") {
    options.sortProblems = "severity";
  }
}
function migrateApplications(target) {
  if (!target.itemTag) {
    const application = target.application && typeof target.application === "object" ? target.application : {};
    const appFilter = String(application.filter ?? "");
    target.itemTag = { filter: appFilter ? `Application: ${appFilter}` : "" };
  }
}
function migrateSLAProperty(target) {
  if (target.slaProperty && typeof target.slaProperty === "object") {
    const prop = target.slaProperty.property;
    if (prop != null) target.slaProperty = String(prop);
  }
  if (target.slaProperty != null) {
    target.slaProperty = mapLegacySLAProperty(target.slaProperty);
  }
  if (target.slaInterval != null) {
    target.slaInterval = mapLegacySLAInterval(target.slaInterval);
  }
}
function migrateTriggersMode(target) {
  const triggers = target.triggers && typeof target.triggers === "object" ? target.triggers : null;
  if (!triggers) return;
  const options = {
    ...target.options && typeof target.options === "object" ? target.options : {}
  };
  if (triggers.minSeverity != null) {
    options.minSeverity = triggers.minSeverity;
    delete triggers.minSeverity;
  }
  if (triggers.count != null) {
    options.count = triggers.count;
    delete triggers.count;
  }
  target.options = options;
}
function migrateNewTriggersCountModes(target) {
  const schema = Number(target.schema ?? 0);
  if (schema >= 11) return;
  const qt = String(target.queryType ?? "");
  if (qt === "6") {
    target.queryType = "4";
    target.countTriggersBy = "items";
  } else if (qt === "7") {
    target.queryType = "4";
    target.countTriggersBy = "problems";
  } else if (qt === "8") {
    target.queryType = "6";
  }
}
function migrateProblemsSeverity(target) {
  const schema = Number(target.schema ?? 0);
  if (schema >= 12) return;
  const options = target.options && typeof target.options === "object" ? target.options : null;
  if (!options || options.minSeverity == null) return;
  const min = Number(options.minSeverity);
  options.severities = [0, 1, 2, 3, 4, 5].filter((v) => v >= min);
}
function migrateLld(target) {
  const hasNew = target.lld && typeof target.lld === "object" && String(target.lld.ruleId || "");
  const legacyRule = String(target.lldRuleId || "");
  const legacyKeys = Array.isArray(target.lldItemKeys) ? target.lldItemKeys.map(String) : [];
  const legacyName = target.lldRuleName != null ? String(target.lldRuleName) : void 0;
  const qtRaw = String(target.queryType || "").toLowerCase();
  const wasLldQueryType = qtRaw === "lld" || qtRaw === "7" || qtRaw === "8" && Boolean(hasNew || legacyRule || legacyKeys.length);
  if (hasNew) {
    const lld = target.lld;
    target.executionMode = target.executionMode || "lld";
    target.lld = {
      ruleId: String(lld.ruleId || ""),
      ruleName: lld.ruleName != null ? String(lld.ruleName) : void 0,
      prototypeIds: Array.isArray(lld.prototypeIds) ? lld.prototypeIds.map(String) : [],
      prototypeKeys: Array.isArray(lld.prototypeKeys) ? lld.prototypeKeys.map(String) : [],
      discoveredItemIds: Array.isArray(lld.discoveredItemIds) ? lld.discoveredItemIds.map(String) : void 0
    };
    if (wasLldQueryType) target.queryType = "0";
    return;
  }
  if (legacyRule || legacyKeys.length || wasLldQueryType) {
    target.executionMode = "lld";
    target.lld = {
      ruleId: legacyRule,
      ruleName: legacyName,
      prototypeIds: [],
      prototypeKeys: legacyKeys
    };
    if (wasLldQueryType) target.queryType = "0";
  } else if (!target.executionMode) {
    target.executionMode = "standard";
  }
}
function migrateZabbixQuery(input) {
  const target = deepClone$2(input);
  target.resultFormat = target.resultFormat || "time_series";
  fixTargetGroup(target);
  if (isGrafana2target(target)) {
    migrateFrom2To3version(target);
  }
  migrateFunctions(target);
  migrateQueryType(target);
  migrateSLA(target);
  migrateProblemSort(target);
  migrateApplications(target);
  migrateSLAProperty(target);
  migrateTriggersMode(target);
  migrateNewTriggersCountModes(target);
  migrateProblemsSeverity(target);
  migrateLld(target);
  target.schema = DS_QUERY_SCHEMA;
  const base = deepClone$2(DEFAULT_ZABBIX_QUERY);
  const qtCode = String(target.queryType ?? "0");
  if (!/^[0-6]$/.test(qtCode)) {
    throw new DataSourceError(
      "INVALID_QUERY",
      `不支持的 Zabbix queryType: ${qtCode}`
    );
  }
  return {
    ...base,
    ...target,
    group: asFilter(target.group ?? base.group),
    host: asFilter(target.host ?? base.host),
    application: asFilter(target.application ?? base.application),
    itemTag: asFilter(target.itemTag ?? base.itemTag),
    item: asFilter(target.item ?? base.item),
    proxy: asFilter(target.proxy ?? base.proxy),
    trigger: asFilter(target.trigger ?? base.trigger),
    tags: asFilter(target.tags ?? base.tags),
    macro: asFilter(target.macro ?? base.macro),
    itemids: String(target.itemids ?? base.itemids ?? ""),
    textFilter: String(target.textFilter ?? base.textFilter ?? ""),
    useCaptureGroups: Boolean(target.useCaptureGroups ?? base.useCaptureGroups),
    itServiceFilter: String(
      target.itServiceFilter ?? base.itServiceFilter ?? ""
    ),
    slaFilter: String(target.slaFilter ?? base.slaFilter ?? ""),
    slaProperty: String(target.slaProperty ?? base.slaProperty ?? "sli"),
    slaInterval: String(target.slaInterval ?? base.slaInterval ?? "none"),
    showProblems: target.showProblems ?? base.showProblems,
    functions: Array.isArray(target.functions) ? target.functions : [],
    options: {
      ...base.options,
      ...target.options && typeof target.options === "object" ? target.options : {}
    },
    queryType: normalizeZabbixQueryType(target.queryType ?? base.queryType),
    schema: DS_QUERY_SCHEMA,
    refId: String(target.refId ?? base.refId),
    executionMode: target.executionMode || "standard",
    lld: target.lld,
    lldRuleId: target.lldRuleId,
    lldRuleName: target.lldRuleName,
    lldItemKeys: target.lldItemKeys
  };
}
function migrateZabbixConfig(input, resolveUid) {
  const jsonData = deepClone$2(input);
  let error;
  if (jsonData.dbConnection && typeof jsonData.dbConnection === "object") {
    const db = jsonData.dbConnection;
    jsonData.dbConnectionEnable = Boolean(db.enable);
    if (!jsonData.dbConnectionDatasourceUID && Number(db.datasourceId) > 0) {
      const uid = resolveUid?.(Number(db.datasourceId));
      if (uid) jsonData.dbConnectionDatasourceUID = uid;
      else {
        error = {
          code: "DIRECT_DB_DATASOURCE_NOT_FOUND",
          message: `找不到 id 为 ${db.datasourceId} 的 Direct DB 数据源`
        };
      }
    }
    delete jsonData.dbConnection;
  }
  if (typeof jsonData.timeout === "string") {
    jsonData.timeout = jsonData.timeout === "" ? 0 : Number(jsonData.timeout);
  }
  if (!jsonData.dbConnectionDatasourceUID && Number(jsonData.dbConnectionDatasourceId) > 0) {
    const id = Number(jsonData.dbConnectionDatasourceId);
    const uid = resolveUid?.(id);
    if (!uid) {
      error = {
        code: "DIRECT_DB_DATASOURCE_NOT_FOUND",
        message: `找不到 id 为 ${id} 的 Direct DB 数据源`
      };
      delete jsonData.dbConnectionDatasourceUID;
    } else {
      jsonData.dbConnectionDatasourceUID = uid;
    }
  }
  delete jsonData.dbConnectionDatasourceId;
  jsonData.schema = DS_CONFIG_SCHEMA;
  const options = {
    ...DEFAULT_ZABBIX_OPTIONS,
    ...jsonData,
    schema: DS_CONFIG_SCHEMA
  };
  return error ? { options, error } : { options };
}
function prepareZabbixAnnotation(input) {
  const json = deepClone$2(input);
  const existing = json.target && typeof json.target === "object" ? json.target : {};
  const defaultTarget = {
    group: { filter: String(json.group ?? "") },
    host: { filter: String(json.host ?? "") },
    application: { filter: String(json.application ?? "") },
    trigger: { filter: String(json.trigger ?? "") },
    options: {
      minSeverity: json.minseverity ?? 0,
      showOkEvents: json.showOkEvents ?? false,
      hideAcknowledged: json.hideAcknowledged ?? false,
      showHostname: json.showHostname ?? false
    }
  };
  const existingOptions = existing.options && typeof existing.options === "object" ? existing.options : {};
  json.target = {
    ...defaultTarget,
    ...existing,
    fromAnnotations: true,
    options: {
      ...defaultTarget.options,
      ...existingOptions
    }
  };
  return json;
}
const DESCENDANTS = {
  group: ["host", "application", "item", "trigger", "macro"],
  host: ["application", "item", "trigger", "macro"],
  application: ["item"],
  item: [],
  trigger: [],
  macro: [],
  proxy: []
};
function canRunWithoutParentScope(owner, parents) {
  if (parents.scope === "all") return true;
  if (owner === "group" || owner === "proxy") return true;
  if (owner === "host") return (parents.groupIds?.length ?? 0) > 0;
  if (owner === "application" || owner === "item" || owner === "trigger" || owner === "macro") {
    return (parents.hostIds?.length ?? 0) > 0 || (parents.groupIds?.length ?? 0) > 0;
  }
  return true;
}
class ZabbixMetadataScheduler {
  maxConcurrent;
  running = 0;
  queue = [];
  active = /* @__PURE__ */ new Map();
  revisions = /* @__PURE__ */ new Map();
  inflightByKey = /* @__PURE__ */ new Map();
  constructor(opts) {
    this.maxConcurrent = Math.max(1, opts?.maxConcurrent ?? 4);
  }
  getRevision(owner) {
    return this.revisions.get(owner) ?? 0;
  }
  /**
   * Bump revision for owner and abort owner + descendants.
   * Returns the new revision.
   */
  invalidateFrom(owner, revision) {
    const next = revision ?? this.getRevision(owner) + 1;
    this.revisions.set(owner, next);
    const victims = /* @__PURE__ */ new Set([owner, ...DESCENDANTS[owner]]);
    for (const o of victims) {
      if (o !== owner) this.revisions.set(o, next);
    }
    for (const [key, active] of this.active) {
      if (victims.has(active.owner)) {
        active.controller.abort();
        this.active.delete(key);
      }
    }
    for (let i = this.queue.length - 1; i >= 0; i--) {
      if (victims.has(this.queue[i].request.owner)) {
        const t = this.queue.splice(i, 1)[0];
        t.controller.abort();
        t.resolve(void 0);
      }
    }
    for (const [key, _p] of this.inflightByKey) {
      const ownerKey = key.split(":")[0];
      if (victims.has(ownerKey)) this.inflightByKey.delete(key);
    }
    return next;
  }
  cancel(owner) {
    if (!owner) {
      for (const active of this.active.values()) active.controller.abort();
      this.active.clear();
      for (const t of this.queue) {
        t.controller.abort();
        t.resolve(void 0);
      }
      this.queue.length = 0;
      this.inflightByKey.clear();
      return;
    }
    this.invalidateFrom(owner);
  }
  async request(request, loader) {
    if (!canRunWithoutParentScope(request.owner, request.parents)) {
      return void 0;
    }
    const latest = this.getRevision(request.owner);
    if (request.revision < latest) {
      return void 0;
    }
    const inflightKey = `${request.owner}:${request.key}:r${request.revision}`;
    const existing = this.inflightByKey.get(inflightKey);
    if (existing) return existing;
    const promise = new Promise((resolve, reject) => {
      const controller = new AbortController();
      const task = {
        request,
        loader,
        resolve,
        reject,
        controller
      };
      if (request.priority === "interactive") {
        this.queue.unshift(task);
      } else {
        this.queue.push(task);
      }
      this.pump();
    });
    this.inflightByKey.set(inflightKey, promise);
    promise.finally(() => {
      if (this.inflightByKey.get(inflightKey) === promise) {
        this.inflightByKey.delete(inflightKey);
      }
    });
    return promise;
  }
  pump() {
    while (this.running < this.maxConcurrent && this.queue.length > 0) {
      const task = this.queue.shift();
      const latest = this.getRevision(task.request.owner);
      if (task.request.revision < latest) {
        task.resolve(void 0);
        continue;
      }
      this.running += 1;
      const key = `${task.request.owner}:${task.request.key}`;
      this.active.set(key, {
        controller: task.controller,
        revision: task.request.revision,
        owner: task.request.owner
      });
      void (async () => {
        try {
          if (task.controller.signal.aborted) {
            task.resolve(void 0);
            return;
          }
          const value = await task.loader(task.controller.signal);
          const stillLatest = this.getRevision(task.request.owner);
          if (task.request.revision < stillLatest || task.controller.signal.aborted) {
            task.resolve(void 0);
            return;
          }
          task.resolve(value);
        } catch (e) {
          if (e?.name === "AbortError") {
            task.resolve(void 0);
          } else {
            task.reject(e);
          }
        } finally {
          this.active.delete(key);
          this.running -= 1;
          this.pump();
        }
      })();
    }
  }
}
const byUid = /* @__PURE__ */ new Map();
function getZabbixMetadataScheduler(uid, opts) {
  const key = String(uid || "__default__");
  let s = byUid.get(key);
  if (!s) {
    s = new ZabbixMetadataScheduler(opts);
    byUid.set(key, s);
  }
  return s;
}
function useZabbixMetadata(load, opts = {}) {
  const options = ref([]);
  const loading = ref(false);
  const error = ref("");
  const stale = ref(false);
  let sequence = 0;
  let controller = null;
  let debounceTimer = null;
  const debounceMs = opts.debounceMs ?? 0;
  let localRevision = 0;
  async function runLoad(priority = "refresh") {
    if (opts.canLoad && !opts.canLoad()) {
      options.value = [];
      loading.value = false;
      error.value = "";
      return;
    }
    const current = ++sequence;
    loading.value = true;
    error.value = "";
    stale.value = false;
    try {
      let rows;
      if (opts.scheduler && opts.owner) {
        localRevision += 1;
        const revision = localRevision;
        const result = await opts.scheduler.request(
          {
            owner: opts.owner,
            revision,
            parents: opts.parents?.() ?? {},
            key: opts.requestKey?.() ?? `${opts.owner}:${revision}`,
            priority: opts.priority ?? priority
          },
          (signal) => load(signal)
        );
        if (current !== sequence) return;
        if (result === void 0) {
          if (opts.canLoad && !opts.canLoad()) options.value = [];
          stale.value = true;
          return;
        }
        rows = result;
      } else {
        controller?.abort();
        controller = new AbortController();
        rows = await load(controller.signal);
      }
      if (current === sequence) {
        options.value = Array.isArray(rows) ? rows : [];
      }
    } catch (cause) {
      if (current === sequence) {
        const err = cause;
        if (err?.name !== "AbortError") {
          error.value = err instanceof Error ? err.message : String(cause);
        }
      }
    } finally {
      if (current === sequence) loading.value = false;
    }
  }
  function refresh(meta2) {
    if (meta2?.revision != null) localRevision = Math.max(localRevision, meta2.revision);
    const priority = meta2?.priority ?? "refresh";
    if (debounceMs > 0) {
      if (debounceTimer) clearTimeout(debounceTimer);
      debounceTimer = setTimeout(() => {
        debounceTimer = null;
        void runLoad(priority);
      }, debounceMs);
      return;
    }
    void runLoad(priority);
  }
  function retry() {
    if (debounceTimer) {
      clearTimeout(debounceTimer);
      debounceTimer = null;
    }
    void runLoad("interactive");
  }
  function cancel() {
    if (debounceTimer) {
      clearTimeout(debounceTimer);
      debounceTimer = null;
    }
    controller?.abort();
    if (opts.scheduler && opts.owner) opts.scheduler.cancel(opts.owner);
  }
  onBeforeUnmount(() => {
    cancel();
  });
  return {
    options,
    loading,
    error,
    stale,
    refresh,
    retry,
    cancel,
    /** @internal test */
    getController: () => controller
  };
}
function resolveZabbixMetadataApi(datasourceUid, fallback) {
  const uid = String(datasourceUid || "").trim();
  if (uid) {
    const registered2 = getRuntimeDataSource(uid);
    if (registered2 && typeof registered2.getMetadata === "function") {
      return registered2;
    }
  }
  if (fallback && typeof fallback.getMetadata === "function") return fallback;
  return null;
}
function isFreeformFilter(value) {
  const v = value.trim();
  if (!v) return false;
  if (v.startsWith("/") && v.lastIndexOf("/") > 0) return true;
  if (v.startsWith("$") || v.includes("${") || v.startsWith("[[") && v.endsWith("]]"))
    return true;
  return false;
}
function optionToFilter(opt) {
  const text = String(opt.text ?? opt.value ?? "");
  const id = opt.id != null ? String(opt.id) : void 0;
  return id ? { filter: text, name: text, ids: [id] } : { filter: text, name: text, ids: [] };
}
function freeformToFilter(raw) {
  return { filter: raw };
}
const RAW = [
  {
    name: "groupBy",
    category: "Transform",
    params: [
      { name: "interval", type: "string" },
      {
        name: "function",
        type: "string",
        options: [
          "avg",
          "min",
          "max",
          "sum",
          "count",
          "median",
          "first",
          "last"
        ]
      }
    ],
    defaultParams: ["1m", "avg"]
  },
  {
    name: "scale",
    category: "Transform",
    params: [{ name: "factor", type: "float", options: [100, 0.01, 10, -1] }],
    defaultParams: [100]
  },
  {
    name: "offset",
    category: "Transform",
    params: [{ name: "delta", type: "float", options: [-100, 100] }],
    defaultParams: [100]
  },
  { name: "delta", category: "Transform", params: [], defaultParams: [] },
  { name: "rate", category: "Transform", params: [], defaultParams: [] },
  {
    name: "movingAverage",
    category: "Transform",
    params: [{ name: "factor", type: "int", options: [6, 10, 60, 100, 600] }],
    defaultParams: [10]
  },
  {
    name: "exponentialMovingAverage",
    category: "Transform",
    params: [
      { name: "smoothing", type: "float", options: [6, 10, 60, 100, 600] }
    ],
    defaultParams: [0.2]
  },
  {
    name: "percentile",
    category: "Transform",
    params: [
      { name: "interval", type: "string" },
      {
        name: "percent",
        type: "float",
        options: [25, 50, 75, 90, 95, 99, 99.9]
      }
    ],
    defaultParams: ["1m", 95]
  },
  {
    name: "removeAboveValue",
    category: "Transform",
    params: [{ name: "number", type: "float" }],
    defaultParams: [0]
  },
  {
    name: "removeBelowValue",
    category: "Transform",
    params: [{ name: "number", type: "float" }],
    defaultParams: [0]
  },
  {
    name: "transformNull",
    category: "Transform",
    params: [{ name: "number", type: "float" }],
    defaultParams: [0]
  },
  {
    name: "aggregateBy",
    category: "Aggregate",
    params: [
      { name: "interval", type: "string" },
      {
        name: "function",
        type: "string",
        options: [
          "avg",
          "min",
          "max",
          "sum",
          "count",
          "median",
          "first",
          "last"
        ]
      }
    ],
    defaultParams: ["1m", "avg"]
  },
  { name: "sumSeries", category: "Aggregate", params: [], defaultParams: [] },
  {
    name: "percentileAgg",
    category: "Aggregate",
    params: [
      { name: "interval", type: "string" },
      {
        name: "percent",
        type: "float",
        options: [25, 50, 75, 90, 95, 99, 99.9]
      }
    ],
    defaultParams: ["1m", 95]
  },
  {
    name: "top",
    category: "Filter",
    params: [
      { name: "number", type: "int" },
      {
        name: "value",
        type: "string",
        options: [
          "avg",
          "min",
          "max",
          "sum",
          "count",
          "median",
          "first",
          "last"
        ]
      }
    ],
    defaultParams: [5, "avg"]
  },
  {
    name: "bottom",
    category: "Filter",
    params: [
      { name: "number", type: "int" },
      {
        name: "value",
        type: "string",
        options: [
          "avg",
          "min",
          "max",
          "sum",
          "count",
          "median",
          "first",
          "last"
        ]
      }
    ],
    defaultParams: [5, "avg"]
  },
  {
    name: "sortSeries",
    category: "Filter",
    params: [{ name: "direction", type: "string", options: ["asc", "desc"] }],
    defaultParams: ["asc"]
  },
  {
    name: "trendValue",
    category: "Trends",
    params: [
      {
        name: "type",
        type: "string",
        options: ["avg", "min", "max", "sum", "count"]
      }
    ],
    defaultParams: ["avg"]
  },
  {
    name: "timeShift",
    category: "Time",
    params: [
      {
        name: "interval",
        type: "string",
        options: ["24h", "7d", "1M", "+24h", "-24h"]
      }
    ],
    defaultParams: ["24h"]
  },
  {
    name: "setAlias",
    category: "Alias",
    params: [{ name: "alias", type: "string" }],
    defaultParams: []
  },
  {
    name: "setAliasByRegex",
    category: "Alias",
    params: [{ name: "aliasByRegex", type: "string" }],
    defaultParams: []
  },
  {
    name: "replaceAlias",
    category: "Alias",
    params: [
      { name: "regexp", type: "string" },
      { name: "newAlias", type: "string" }
    ],
    defaultParams: ["/(.*)/", "$1"]
  },
  {
    name: "consolidateBy",
    category: "Special",
    params: [
      {
        name: "type",
        type: "string",
        options: ["avg", "min", "max", "sum", "count"]
      }
    ],
    defaultParams: ["avg"]
  }
];
const CATEGORY_ORDER = [
  "Transform",
  "Aggregate",
  "Filter",
  "Trends",
  "Time",
  "Alias",
  "Special"
];
function sortDefs(defs) {
  return [...defs].sort((a, b) => {
    const ca = CATEGORY_ORDER.indexOf(a.category);
    const cb = CATEGORY_ORDER.indexOf(b.category);
    if (ca !== cb) return ca - cb;
    return a.name.localeCompare(b.name);
  });
}
const FUNCTION_DEFINITIONS = sortDefs(RAW);
FUNCTION_DEFINITIONS.map((d) => ({
  name: d.name,
  category: d.category,
  params: d.params.map((p) => ({
    name: p.name,
    type: p.type === "string" ? "string" : p.type === "int" || p.type === "float" ? "number" : "string",
    options: p.options?.map(String),
    defaultValue: d.defaultParams[d.params.indexOf(p)]
  })),
  description: d.name
}));
function getFunctionDef(name) {
  return FUNCTION_DEFINITIONS.find((d) => d.name === name);
}
function createFunctionInstance(name) {
  const def = getFunctionDef(name);
  const params = def ? [...def.defaultParams] : [];
  return {
    name,
    params,
    text: formatFunctionText(name, params),
    added: true
  };
}
function formatFunctionText(name, params) {
  if (!params.length) return `${name}()`;
  return `${name}(${params.map(String).join(", ")})`;
}
const ALIAS_FUNCTIONS = /* @__PURE__ */ new Set([
  "setAlias",
  "setAliasByRegex",
  "replaceAlias"
]);
function isAliasFunction(name) {
  const def = getFunctionDef(name);
  return def?.category === "Alias" || ALIAS_FUNCTIONS.has(name);
}
function moveAliasFuncLast(fns) {
  const nonAlias = [];
  const alias = [];
  for (const f of fns || []) {
    if (isAliasFunction(f.name)) alias.push(f);
    else nonAlias.push(f);
  }
  return [...nonAlias, ...alias];
}
const _hoisted_1$M = {
  class: "zbx-fn",
  "data-testid": "zabbix-functions"
};
const _hoisted_2$z = { class: "row add-row" };
const _hoisted_3$t = ["data-testid"];
const _hoisted_4$m = { class: "fn-main" };
const _hoisted_5$h = ["title"];
const _hoisted_6$e = {
  class: "fn-toolbar",
  "data-testid": "fn-toolbar"
};
const _sfc_main$P = /* @__PURE__ */ defineComponent({
  __name: "FunctionEditor",
  props: {
    modelValue: { default: void 0 },
    functions: { default: void 0 }
  },
  emits: ["update:modelValue", "update:functions"],
  setup(__props, { expose: __expose, emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const list = computed(() => props.functions ?? props.modelValue ?? []);
    function commit(next) {
      const ordered = moveAliasFuncLast(next);
      emit("update:modelValue", ordered);
      emit("update:functions", ordered);
    }
    const addOptions = computed(() => {
      const groups = /* @__PURE__ */ new Map();
      for (const d of FUNCTION_DEFINITIONS) {
        const arr = groups.get(d.category) || [];
        arr.push({ label: d.name, value: d.name });
        groups.set(d.category, arr);
      }
      return [...groups.entries()].map(([label, options]) => ({ label, options }));
    });
    function add(name) {
      const n = String(name || "");
      if (!n) return;
      const inst = createFunctionInstance(n);
      commit([...list.value, inst]);
    }
    function remove(idx) {
      commit(list.value.filter((_, i) => i !== idx));
    }
    function move(idx, dir) {
      const next = [...list.value];
      const j = idx + dir;
      if (j < 0 || j >= next.length) return;
      const a = next[idx];
      const b = next[j];
      if (isAliasFunction(a.name) !== isAliasFunction(b.name)) return;
      const tmp = next[idx];
      next[idx] = next[j];
      next[j] = tmp;
      commit(next);
    }
    function setParam(idx, pidx, value) {
      const next = list.value.map((f, i) => {
        if (i !== idx) return f;
        const def = getFunctionDef(f.name);
        const params = [...f.params || []];
        while (params.length <= pidx) params.push("");
        const pdef = def?.params[pidx];
        let v = value;
        if (pdef?.type === "int") v = Number.parseInt(String(value), 10);
        else if (pdef?.type === "float") v = Number(value);
        params[pidx] = v;
        const cleaned = def && def.defaultParams.length === 0 && params.every((p) => p === "" || p == null) ? [] : params;
        return { ...f, params: cleaned, text: formatFunctionText(f.name, cleaned) };
      });
      commit(next);
    }
    function paramValue(fn, pidx) {
      const v = fn.params?.[pidx];
      return v == null ? "" : String(v);
    }
    function unknownDef(name) {
      return !getFunctionDef(name);
    }
    __expose({ add, remove, move, setParam, moveAliasFuncLast });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$M, [
        _cache[4] || (_cache[4] = createElementVNode(
          "span",
          {
            hidden: "",
            "data-testid": "zabbix-function-editor"
          },
          null,
          -1
          /* CACHED */
        )),
        createElementVNode("div", _hoisted_2$z, [
          createVNode(unref(GSelect), {
            options: addOptions.value,
            placeholder: "添加函数",
            "test-id": "zabbix-function-add",
            "onUpdate:value": add
          }, null, 8, ["options"])
        ]),
        (openBlock(true), createElementBlock(
          Fragment,
          null,
          renderList(list.value, (fn, idx) => {
            return openBlock(), createElementBlock("div", {
              key: `${fn.name}-${idx}`,
              class: normalizeClass(["fn-row", {
                "fn-row--unknown": unknownDef(fn.name),
                "fn-row--alias": unref(isAliasFunction)(fn.name)
              }]),
              "data-testid": `fn-${fn.name}`
            }, [
              createElementVNode("div", _hoisted_4$m, [
                createElementVNode("strong", {
                  title: fn.text || fn.name,
                  class: normalizeClass({ "fn-name--error": unknownDef(fn.name) })
                }, toDisplayString(fn.name), 11, _hoisted_5$h),
                unref(getFunctionDef)(fn.name) ? (openBlock(true), createElementBlock(
                  Fragment,
                  { key: 0 },
                  renderList(unref(getFunctionDef)(fn.name).params, (p, pidx) => {
                    return openBlock(), createElementBlock(
                      Fragment,
                      { key: pidx },
                      [
                        p.options?.length ? (openBlock(), createBlock(unref(GSelect), {
                          key: 0,
                          value: paramValue(fn, pidx),
                          options: p.options.map((o) => ({ label: String(o), value: String(o) })),
                          "test-id": `fn-${fn.name}-p${pidx}`,
                          "aria-label": `${fn.name} ${p.name}`,
                          "onUpdate:value": ($event) => setParam(idx, pidx, $event)
                        }, null, 8, ["value", "options", "test-id", "aria-label", "onUpdate:value"])) : (openBlock(), createBlock(unref(GInput), {
                          key: 1,
                          "model-value": paramValue(fn, pidx),
                          type: p.type === "string" ? "text" : "number",
                          "test-id": `fn-${fn.name}-p${pidx}`,
                          placeholder: p.name,
                          "onUpdate:modelValue": ($event) => setParam(
                            idx,
                            pidx,
                            p.type === "string" ? String($event) : Number($event)
                          )
                        }, null, 8, ["model-value", "type", "test-id", "placeholder", "onUpdate:modelValue"]))
                      ],
                      64
                      /* STABLE_FRAGMENT */
                    );
                  }),
                  128
                  /* KEYED_FRAGMENT */
                )) : (openBlock(), createElementBlock(
                  Fragment,
                  { key: 1 },
                  [
                    (openBlock(true), createElementBlock(
                      Fragment,
                      null,
                      renderList(fn.params || [], (pv, pidx) => {
                        return openBlock(), createBlock(unref(GInput), {
                          key: "legacy-" + pidx,
                          "model-value": String(pv),
                          "test-id": `fn-${fn.name}-p${pidx}`,
                          "onUpdate:modelValue": ($event) => setParam(idx, pidx, String($event))
                        }, null, 8, ["model-value", "test-id", "onUpdate:modelValue"]);
                      }),
                      128
                      /* KEYED_FRAGMENT */
                    )),
                    _cache[0] || (_cache[0] = createElementVNode(
                      "span",
                      {
                        class: "unknown-hint",
                        role: "status"
                      },
                      "未知函数",
                      -1
                      /* CACHED */
                    ))
                  ],
                  64
                  /* STABLE_FRAGMENT */
                ))
              ]),
              createElementVNode("div", _hoisted_6$e, [
                createVNode(
                  unref(_sfc_main$18),
                  { title: "左移" },
                  {
                    default: withCtx(() => [
                      createVNode(unref(GButton), {
                        size: "sm",
                        variant: "text",
                        "test-id": `fn-up-${idx}`,
                        "aria-label": "左移",
                        onClick: ($event) => move(idx, -1)
                      }, {
                        default: withCtx(() => [..._cache[1] || (_cache[1] = [
                          createTextVNode(
                            "←",
                            -1
                            /* CACHED */
                          )
                        ])]),
                        _: 1
                        /* STABLE */
                      }, 8, ["test-id", "onClick"])
                    ]),
                    _: 2
                    /* DYNAMIC */
                  },
                  1024
                  /* DYNAMIC_SLOTS */
                ),
                createVNode(
                  unref(_sfc_main$18),
                  { title: "右移" },
                  {
                    default: withCtx(() => [
                      createVNode(unref(GButton), {
                        size: "sm",
                        variant: "text",
                        "test-id": `fn-down-${idx}`,
                        "aria-label": "右移",
                        onClick: ($event) => move(idx, 1)
                      }, {
                        default: withCtx(() => [..._cache[2] || (_cache[2] = [
                          createTextVNode(
                            "→",
                            -1
                            /* CACHED */
                          )
                        ])]),
                        _: 1
                        /* STABLE */
                      }, 8, ["test-id", "onClick"])
                    ]),
                    _: 2
                    /* DYNAMIC */
                  },
                  1024
                  /* DYNAMIC_SLOTS */
                ),
                createVNode(
                  unref(_sfc_main$18),
                  { title: "删除" },
                  {
                    default: withCtx(() => [
                      createVNode(unref(GButton), {
                        size: "sm",
                        variant: "destructive",
                        "test-id": `fn-del-${idx}`,
                        "aria-label": "删除",
                        onClick: ($event) => remove(idx)
                      }, {
                        default: withCtx(() => [..._cache[3] || (_cache[3] = [
                          createTextVNode(
                            "×",
                            -1
                            /* CACHED */
                          )
                        ])]),
                        _: 1
                        /* STABLE */
                      }, 8, ["test-id", "onClick"])
                    ]),
                    _: 2
                    /* DYNAMIC */
                  },
                  1024
                  /* DYNAMIC_SLOTS */
                )
              ])
            ], 10, _hoisted_3$t);
          }),
          128
          /* KEYED_FRAGMENT */
        ))
      ]);
    };
  }
});
const FunctionEditor$1 = /* @__PURE__ */ _export_sfc(_sfc_main$P, [["__scopeId", "data-v-4ab2902e"]]);
const _hoisted_1$L = {
  class: "host-tag-editor",
  "data-testid": "zabbix-host-tag-editor"
};
const _hoisted_2$y = { class: "toolbar" };
const _hoisted_3$s = ["data-testid"];
const _sfc_main$O = /* @__PURE__ */ defineComponent({
  __name: "HostTagQueryEditor",
  props: {
    tags: { default: () => [] },
    evaltype: { default: "0" },
    tagOptions: { default: () => [] },
    zabbixMajor: { default: 6 }
  },
  emits: ["change"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const operators = computed(() => {
      const major = props.zabbixMajor ?? 6;
      return [
        { label: "Contains", value: 0 },
        { label: "Equals", value: 1 },
        { label: major >= 7 ? "Does not contain" : "Not like", value: 2 },
        { label: major >= 7 ? "Does not equal" : "Not equal", value: 3 },
        { label: "Exists", value: 4 },
        { label: major >= 7 ? "Does not exist" : "Not exists", value: 5 }
      ];
    });
    const evalOptions = [
      { label: "AND/OR", value: "0" },
      { label: "OR", value: "2" }
    ];
    function addRow() {
      emit(
        "change",
        [...props.tags || [], { tag: "", value: "", operator: 0 }],
        props.evaltype || "0"
      );
    }
    function patchRow(i, partial) {
      const next = (props.tags || []).map(
        (t, j) => j === i ? { ...t, ...partial } : t
      );
      emit("change", next, props.evaltype || "0");
    }
    function removeRow(i) {
      emit(
        "change",
        (props.tags || []).filter((_, j) => j !== i),
        props.evaltype || "0"
      );
    }
    function setEvaltype(v) {
      const e = String(v) === "2" ? "2" : "0";
      emit("change", props.tags || [], e);
    }
    function needsValue(op) {
      return op !== 4 && op !== 5;
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$L, [
        createElementVNode("div", _hoisted_2$y, [
          createVNode(unref(GButton), {
            size: "sm",
            variant: "secondary",
            "test-id": "zabbix-host-tag-add",
            "aria-label": "Add new host tag filter",
            onClick: addRow
          }, {
            default: withCtx(() => [
              createVNode(unref(GIcon), { name: "plus" }),
              _cache[0] || (_cache[0] = createTextVNode(
                " 主机标签 ",
                -1
                /* CACHED */
              ))
            ]),
            _: 1
            /* STABLE */
          }),
          (__props.tags || []).length > 1 ? (openBlock(), createBlock(unref(GSelect), {
            key: 0,
            value: __props.evaltype || "0",
            options: evalOptions,
            "test-id": "zabbix-host-tag-evaltype",
            "aria-label": "Host tag evaluation type",
            "onUpdate:value": setEvaltype
          }, null, 8, ["value"])) : createCommentVNode("v-if", true)
        ]),
        (openBlock(true), createElementBlock(
          Fragment,
          null,
          renderList(__props.tags || [], (t, i) => {
            return openBlock(), createElementBlock("div", {
              key: i,
              class: "host-tag-row",
              "data-testid": `zabbix-host-tag-row-${i}`
            }, [
              createVNode(unref(GSelect), {
                value: t.tag,
                options: __props.tagOptions,
                "show-search": "",
                mode: "tags",
                placeholder: "tag",
                "test-id": `zabbix-host-tag-name-${i}`,
                "onUpdate:value": (v) => {
                  const arr = Array.isArray(v) ? v.map(String) : [String(v ?? "")];
                  patchRow(i, { tag: arr[arr.length - 1] || "" });
                }
              }, null, 8, ["value", "options", "test-id", "onUpdate:value"]),
              createVNode(unref(GSelect), {
                value: t.operator,
                options: operators.value,
                "test-id": `zabbix-host-tag-op-${i}`,
                "onUpdate:value": ($event) => patchRow(i, { operator: Number($event) })
              }, null, 8, ["value", "options", "test-id", "onUpdate:value"]),
              needsValue(Number(t.operator)) ? (openBlock(), createBlock(unref(GInput), {
                key: 0,
                "model-value": t.value,
                placeholder: "value",
                "test-id": `zabbix-host-tag-value-${i}`,
                "onUpdate:modelValue": ($event) => patchRow(i, { value: String($event) })
              }, null, 8, ["model-value", "test-id", "onUpdate:modelValue"])) : createCommentVNode("v-if", true),
              createVNode(unref(GButton), {
                size: "sm",
                variant: "text",
                "test-id": `zabbix-host-tag-remove-${i}`,
                "aria-label": "Remove host tag filter",
                onClick: ($event) => removeRow(i)
              }, {
                default: withCtx(() => [..._cache[1] || (_cache[1] = [
                  createTextVNode(
                    " × ",
                    -1
                    /* CACHED */
                  )
                ])]),
                _: 1
                /* STABLE */
              }, 8, ["test-id", "onClick"])
            ], 8, _hoisted_3$s);
          }),
          128
          /* KEYED_FRAGMENT */
        ))
      ]);
    };
  }
});
const HostTagQueryEditor = /* @__PURE__ */ _export_sfc(_sfc_main$O, [["__scopeId", "data-v-7aa10521"]]);
const _hoisted_1$K = ["for"];
const _hoisted_2$x = { class: "inline-field__text" };
const _hoisted_3$r = {
  class: "inline-field__tip",
  "aria-hidden": "true"
};
const _hoisted_4$l = { class: "inline-field__control" };
const _sfc_main$N = /* @__PURE__ */ defineComponent({
  __name: "InlineField",
  props: {
    label: {},
    labelWidth: { default: 12 },
    tooltip: {},
    htmlFor: {},
    grow: { type: Boolean, default: false }
  },
  setup(__props) {
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock(
        "div",
        {
          class: normalizeClass(["inline-field", { "inline-field--grow": __props.grow }]),
          "data-testid": "zabbix-inline-field"
        },
        [
          createElementVNode("label", {
            class: "inline-field__label",
            for: __props.htmlFor,
            style: normalizeStyle({ width: `${(__props.labelWidth ?? 12) * 8}px` })
          }, [
            createElementVNode(
              "span",
              _hoisted_2$x,
              toDisplayString(__props.label),
              1
              /* TEXT */
            ),
            __props.tooltip ? (openBlock(), createBlock(unref(_sfc_main$18), {
              key: 0,
              title: __props.tooltip
            }, {
              default: withCtx(() => [
                createElementVNode("span", _hoisted_3$r, [
                  createVNode(unref(GIcon), { name: "info-circle" })
                ])
              ]),
              _: 1
              /* STABLE */
            }, 8, ["title"])) : createCommentVNode("v-if", true)
          ], 12, _hoisted_1$K),
          createElementVNode("div", _hoisted_4$l, [
            renderSlot(_ctx.$slots, "default", {}, void 0, true)
          ])
        ],
        2
        /* CLASS */
      );
    };
  }
});
const InlineField = /* @__PURE__ */ _export_sfc(_sfc_main$N, [["__scopeId", "data-v-b1be77e5"]]);
const _hoisted_1$J = {
  class: "inline-field-row",
  "data-testid": "zabbix-inline-field-row"
};
const _sfc_main$M = /* @__PURE__ */ defineComponent({
  __name: "InlineFieldRow",
  props: {
    filler: { type: Boolean, default: true },
    fillerWidth: { default: 10 }
  },
  setup(__props) {
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$J, [
        renderSlot(_ctx.$slots, "default", {}, void 0, true),
        __props.filler ? (openBlock(), createElementBlock(
          "label",
          {
            key: 0,
            class: "inline-field-row__filler",
            style: normalizeStyle({ width: `${(__props.fillerWidth ?? 10) * 8}px` }),
            "aria-hidden": "true"
          },
          null,
          4
          /* STYLE */
        )) : createCommentVNode("v-if", true)
      ]);
    };
  }
});
const InlineFieldRow = /* @__PURE__ */ _export_sfc(_sfc_main$M, [["__scopeId", "data-v-e9095d9e"]]);
const _hoisted_1$I = {
  class: "lld",
  "data-testid": "zabbix-lld-selector"
};
const _hoisted_2$w = {
  key: 0,
  class: "hint",
  "data-testid": "zabbix-lld-loading"
};
const _hoisted_3$q = {
  key: 1,
  class: "hint",
  "data-testid": "zabbix-lld-empty"
};
const _hoisted_4$k = {
  key: 2,
  class: "err",
  "data-testid": "zabbix-lld-error"
};
const _sfc_main$L = /* @__PURE__ */ defineComponent({
  __name: "LldSelector",
  props: {
    query: {},
    datasourceApi: {},
    hostids: {}
  },
  emits: ["update:query", "item-count-change"],
  setup(__props, { expose: __expose, emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const rulesMeta = useZabbixMetadata(async (signal) => {
      if (!props.datasourceApi || !props.hostids.length) return [];
      const res = await props.datasourceApi.getMetadata(
        { type: "discoveryRules", hostids: props.hostids },
        signal
      );
      if (res.type !== "discoveryRules") return [];
      return res.values;
    });
    const ruleId = computed(
      () => String(props.query.lld?.ruleId || props.query.lldRuleId || "")
    );
    const prototypesMeta = useZabbixMetadata(async (signal) => {
      const id = ruleId.value;
      if (!props.datasourceApi || !id) return [];
      const res = await props.datasourceApi.getMetadata(
        { type: "itemPrototypes", discoveryRuleId: id },
        signal
      );
      if (res.type !== "itemPrototypes") return [];
      return res.values;
    });
    const rulesError = computed(() => rulesMeta.error.value);
    const protosError = computed(() => prototypesMeta.error.value);
    const ruleOptions = computed(
      () => rulesMeta.options.value.map((o) => ({
        label: o.text || o.value,
        value: String(o.id || o.value)
      }))
    );
    const prototypeOptions = computed(
      () => prototypesMeta.options.value.map((o) => ({
        label: `${o.text || o.value}${o.id ? ` (${o.id})` : ""}`,
        // value encodes id|key for multi-select recovery
        value: `${o.id || ""}::${o.value || o.text || ""}`
      }))
    );
    const ruleValue = computed(() => ruleId.value);
    const prototypeValue = computed(() => {
      const ids = props.query.lld?.prototypeIds || [];
      const keys = props.query.lld?.prototypeKeys || props.query.lldItemKeys || [];
      if (ids.length) {
        return ids.map((id, i) => `${id}::${keys[i] || ""}`);
      }
      return keys.map((k) => `::${k}`);
    });
    function patch(partial) {
      emit("update:query", { ...props.query, ...partial });
    }
    function onRule(v) {
      const id = String(v || "");
      const opt = rulesMeta.options.value.find(
        (o) => String(o.id || o.value) === id
      );
      const name = opt ? String(opt.text || opt.value) : void 0;
      patch({
        executionMode: id ? "lld" : "standard",
        lld: id ? { ruleId: id, ruleName: name, prototypeIds: [], prototypeKeys: [] } : void 0,
        // legacy mirrors
        lldRuleId: id || void 0,
        lldRuleName: name,
        lldItemKeys: []
      });
      emit("item-count-change", 0);
    }
    function onPrototypes(v) {
      const arr = Array.isArray(v) ? v.map(String) : v ? [String(v)] : [];
      const seen = /* @__PURE__ */ new Set();
      const prototypeIds = [];
      const prototypeKeys = [];
      for (const raw of arr) {
        if (seen.has(raw)) continue;
        seen.add(raw);
        const [id, ...rest] = raw.split("::");
        const key = rest.join("::");
        if (id) prototypeIds.push(id);
        if (key) prototypeKeys.push(key);
      }
      const rid = ruleId.value;
      patch({
        executionMode: "lld",
        lld: {
          ruleId: rid,
          ruleName: props.query.lld?.ruleName || props.query.lldRuleName,
          prototypeIds,
          prototypeKeys
        },
        lldRuleId: rid || void 0,
        lldItemKeys: prototypeKeys
      });
      emit(
        "item-count-change",
        Math.max(prototypeIds.length, prototypeKeys.length)
      );
    }
    watch(
      () => props.hostids.join(","),
      async () => {
        if (props.query.lld?.ruleId || props.query.lldRuleId || (props.query.lldItemKeys || []).length) {
          patch({
            executionMode: "standard",
            lld: void 0,
            lldRuleId: void 0,
            lldRuleName: void 0,
            lldItemKeys: []
          });
        }
        await rulesMeta.refresh();
        prototypesMeta.options.value = [];
      },
      { immediate: true }
    );
    watch(
      () => ruleId.value,
      async () => {
        await prototypesMeta.refresh();
      }
    );
    __expose({ onRule, onPrototypes });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$I, [
        _cache[1] || (_cache[1] = createElementVNode(
          "label",
          null,
          "发现规则 (LLD)",
          -1
          /* CACHED */
        )),
        createVNode(unref(GSelect), {
          value: ruleValue.value || void 0,
          options: ruleOptions.value,
          "allow-clear": "",
          placeholder: "选择 discovery rule",
          "test-id": "zabbix-lld-rule",
          "onUpdate:value": onRule
        }, null, 8, ["value", "options"]),
        _cache[2] || (_cache[2] = createElementVNode(
          "label",
          null,
          "监控项原型",
          -1
          /* CACHED */
        )),
        createVNode(unref(GSelect), {
          mode: "multiple",
          value: prototypeValue.value,
          options: prototypeOptions.value,
          "allow-clear": "",
          placeholder: "选择 item prototypes",
          "test-id": "zabbix-lld-prototypes",
          "onUpdate:value": onPrototypes
        }, null, 8, ["value", "options"]),
        unref(rulesMeta).loading.value || unref(prototypesMeta).loading.value ? (openBlock(), createElementBlock("p", _hoisted_2$w, " 加载中… ")) : !unref(rulesMeta).loading.value && __props.hostids.length && !ruleOptions.value.length ? (openBlock(), createElementBlock("p", _hoisted_3$q, " 无发现规则 ")) : createCommentVNode("v-if", true),
        rulesError.value || protosError.value ? (openBlock(), createElementBlock("p", _hoisted_4$k, [
          createTextVNode(
            toDisplayString(rulesError.value || protosError.value) + " ",
            1
            /* TEXT */
          ),
          createElementVNode("button", {
            type: "button",
            "data-testid": "zabbix-lld-retry",
            onClick: _cache[0] || (_cache[0] = ($event) => {
              unref(rulesMeta).retry();
              unref(prototypesMeta).retry();
            })
          }, " 重试 ")
        ])) : createCommentVNode("v-if", true)
      ]);
    };
  }
});
const LldSelector = /* @__PURE__ */ _export_sfc(_sfc_main$L, [["__scopeId", "data-v-31767cc1"]]);
const _hoisted_1$H = ["data-testid"];
const _hoisted_2$v = {
  key: 0,
  class: "lbl"
};
const _hoisted_3$p = {
  key: 1,
  class: "hint",
  role: "status"
};
const _hoisted_4$j = ["data-testid"];
const _sfc_main$K = /* @__PURE__ */ defineComponent({
  __name: "MetricPicker",
  props: {
    value: { default: "" },
    options: { default: () => [] },
    loading: { type: Boolean, default: false },
    placeholder: { default: "选择或输入" },
    variables: { default: () => [] },
    disabled: { type: Boolean, default: false },
    testId: { default: "zabbix-metric-picker" },
    label: { default: "" },
    single: { type: Boolean, default: true }
  },
  emits: ["update:value", "search"],
  setup(__props, { expose: __expose, emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const mergedOptions = computed(() => {
      const vars = (props.variables || []).map((v) => {
        const name = String(v).replace(/^\$/, "");
        return { label: `$${name}`, value: `$${name}` };
      });
      const seen = /* @__PURE__ */ new Set();
      const out = [];
      for (const o of [
        ...vars,
        { label: "/.*/", value: "/.*/" },
        ...props.options || []
      ]) {
        const val = String(o.value ?? "");
        if (!val || seen.has(val)) continue;
        seen.add(val);
        out.push({ label: o.label || val, value: val });
      }
      return out;
    });
    const selectValue = computed(() => {
      const v = String(props.value || "").trim();
      return v ? [v] : [];
    });
    const error = computed(() => {
      const v = String(props.value || "").trim();
      if (!v) return "";
      if (v === "*") return "请使用 /.*/ 匹配全部";
      if (v.startsWith("/") && !/^\/.*\/[gmius]*$/.test(v))
        return "正则必须以 / 结尾";
      return "";
    });
    function onChange(raw) {
      const arr = Array.isArray(raw) ? raw.map(String) : raw == null || raw === "" ? [] : [String(raw)];
      if (!arr.length) {
        emit("update:value", "");
        return;
      }
      const token = props.single ? arr[arr.length - 1] : arr.join(",");
      emit("update:value", token);
    }
    __expose({ error, mergedOptions, onChange });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", {
        class: normalizeClass(["metric-picker", { "has-error": !!error.value }]),
        "data-testid": __props.testId
      }, [
        __props.label ? (openBlock(), createElementBlock(
          "label",
          _hoisted_2$v,
          toDisplayString(__props.label),
          1
          /* TEXT */
        )) : createCommentVNode("v-if", true),
        createVNode(unref(GSelect), {
          mode: "tags",
          value: selectValue.value,
          options: mergedOptions.value,
          disabled: __props.disabled,
          placeholder: __props.placeholder,
          "allow-clear": "",
          "test-id": `${__props.testId}-select`,
          "aria-label": __props.label || __props.placeholder,
          "onUpdate:value": onChange
        }, null, 8, ["value", "options", "disabled", "placeholder", "test-id", "aria-label"]),
        __props.loading ? (openBlock(), createElementBlock("p", _hoisted_3$p, "加载中…")) : createCommentVNode("v-if", true),
        error.value ? (openBlock(), createElementBlock("p", {
          key: 2,
          class: "picker-error",
          role: "status",
          "data-testid": `${__props.testId}-error`
        }, toDisplayString(error.value), 9, _hoisted_4$j)) : createCommentVNode("v-if", true)
      ], 10, _hoisted_1$H);
    };
  }
});
const MetricPicker = /* @__PURE__ */ _export_sfc(_sfc_main$K, [["__scopeId", "data-v-ac0f0c02"]]);
const _hoisted_1$G = {
  class: "fields",
  "data-testid": "zabbix-fields-metrics"
};
const _sfc_main$J = /* @__PURE__ */ defineComponent({
  __name: "MetricsQueryEditor",
  props: {
    query: {},
    datasourceUid: {},
    datasourceApi: {},
    variables: {},
    zabbixMajor: {},
    supportsApplications: { type: Boolean }
  },
  emits: ["update:query", "item-count-change"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const api = computed(
      () => resolveZabbixMetadataApi(props.datasourceUid, props.datasourceApi || null)
    );
    const useApplications = computed(() => props.supportsApplications !== false);
    const hostTagOptions = ref([]);
    const itemTagOptions = ref([]);
    const scheduler = computed(
      () => getZabbixMetadataScheduler(String(props.datasourceUid || "default"))
    );
    const groupRevision = ref(0);
    const groups = useZabbixMetadata(
      async (signal) => {
        if (!api.value) return [];
        const res = await api.value.getMetadata(
          { type: "groups", filter: "" },
          signal
        );
        return res.type === "groups" ? res.values : [];
      },
      {
        scheduler: scheduler.value,
        owner: "group",
        parents: () => ({}),
        requestKey: () => "groups"
      }
    );
    const hosts = useZabbixMetadata(
      async (signal) => {
        if (!api.value) return [];
        const groupids = props.query.group?.ids || [];
        const res = await api.value.getMetadata(
          {
            type: "hosts",
            groupids,
            filter: "",
            hostTags: props.query.hostTags || []
          },
          signal
        );
        return res.type === "hosts" ? res.values : [];
      },
      {
        scheduler: scheduler.value,
        owner: "host",
        canLoad: () => (props.query.group?.ids?.length ?? 0) > 0 || Boolean(props.query.group?.filter?.trim()),
        parents: () => ({ groupIds: props.query.group?.ids || [] }),
        requestKey: () => `hosts:${(props.query.group?.ids || []).join(",")}|${props.query.group?.filter || ""}`
      }
    );
    const applications = useZabbixMetadata(
      async (signal) => {
        if (!api.value || !useApplications.value) return [];
        const hostids2 = props.query.host?.ids || [];
        const res = await api.value.getMetadata(
          { type: "applications", hostids: hostids2, filter: "" },
          signal
        );
        return res.type === "applications" ? res.values : [];
      },
      {
        scheduler: scheduler.value,
        owner: "application",
        canLoad: () => (props.query.host?.ids?.length ?? 0) > 0,
        parents: () => ({ hostIds: props.query.host?.ids || [] }),
        requestKey: () => `apps:${(props.query.host?.ids || []).join(",")}`
      }
    );
    const items = useZabbixMetadata(
      async (signal) => {
        if (!api.value) return [];
        const hostids2 = props.query.host?.ids || [];
        const applicationids = props.query.application?.ids || [];
        const res = await api.value.getMetadata(
          {
            type: "items",
            hostids: hostids2,
            applicationids,
            filter: "",
            itemTag: props.query.itemTag?.filter || "",
            showDisabled: Boolean(props.query.options?.showDisabledItems)
          },
          signal
        );
        if (res.type === "items") {
          emit("item-count-change", res.values.length);
          const tags = /* @__PURE__ */ new Map();
          for (const it of res.values) {
            const rawTags = it.tags;
            if (Array.isArray(rawTags)) {
              for (const t of rawTags) {
                const key = `${t.tag}: ${t.value}`;
                tags.set(key, key);
              }
            }
          }
          if (tags.size)
            itemTagOptions.value = [...tags.values()].map((v) => ({
              label: v,
              value: v
            }));
          return res.values;
        }
        return [];
      },
      {
        scheduler: scheduler.value,
        owner: "item",
        canLoad: () => (props.query.host?.ids?.length ?? 0) > 0,
        parents: () => ({
          hostIds: props.query.host?.ids || [],
          applicationIds: props.query.application?.ids || []
        }),
        requestKey: () => `items:${(props.query.host?.ids || []).join(",")}|${props.query.itemTag?.filter || ""}`
      }
    );
    watch(
      () => [
        props.query.group?.filter,
        props.query.group?.ids?.join(","),
        // hostTags signature without full JSON.stringify of query
        (props.query.hostTags || []).map((t) => `${t.tag ?? t.key ?? ""}=${t.value ?? ""}`).join("|")
      ],
      () => {
        groupRevision.value = scheduler.value.invalidateFrom(
          "group",
          groupRevision.value + 1
        );
        groups.refresh({ revision: groupRevision.value });
        hosts.refresh({ revision: groupRevision.value });
      }
    );
    onMounted(() => {
      nextTick(() => {
        groupRevision.value = scheduler.value.invalidateFrom(
          "group",
          groupRevision.value + 1
        );
        groups.refresh({ revision: groupRevision.value });
        hosts.refresh({ revision: groupRevision.value });
      });
    });
    watch(
      () => [props.query.host?.filter, props.query.host?.ids?.join(",")],
      () => {
        const rev = scheduler.value.invalidateFrom("host");
        hosts.refresh({ revision: rev });
        applications.refresh({ revision: rev });
        items.refresh({ revision: rev });
      }
    );
    watch(
      () => [
        props.query.application?.filter,
        props.query.itemTag?.filter,
        props.query.options?.showDisabledItems
      ],
      () => items.refresh({ priority: "refresh" })
    );
    const hostids = computed(() => props.query.host?.ids || []);
    const functions = computed({
      get: () => props.query.functions || [],
      set: (v) => emit("update:query", { ...props.query, functions: v })
    });
    function toOptions(list) {
      return (list || []).map((o) => ({
        label: o.text || o.value,
        value: String(o.value ?? o.text ?? "")
      }));
    }
    function findOption(list, token) {
      return list.find(
        (o) => String(o.value) === token || String(o.text) === token || String(o.id) === token
      );
    }
    function filterFromToken(list, token) {
      const t = String(token || "").trim();
      if (!t) return { filter: "" };
      if (t.startsWith("/") || t.startsWith("$") || t === "/.*/")
        return freeformToFilter(t);
      const opt = findOption(list, t);
      if (opt) {
        const next = optionToFilter(opt);
        return next.ids?.length ? next : { filter: next.filter, name: next.name };
      }
      return freeformToFilter(t);
    }
    function filterDisplay(f) {
      if (!f) return "";
      if (f.filter) return f.filter;
      if (f.name) return f.name;
      if (f.ids?.length) return f.ids[0];
      return "";
    }
    function patchFilter(key, token) {
      const list = key === "group" ? groups.options.value : key === "host" ? hosts.options.value : key === "application" ? applications.options.value : key === "item" ? items.options.value : [];
      const value = key === "itemTag" ? freeformToFilter(token) : filterFromToken(list, token);
      emit("update:query", { ...props.query, [key]: value });
    }
    function onHostTags(tags, evaltype) {
      emit("update:query", { ...props.query, hostTags: tags, evaltype });
    }
    function onUpdate(q) {
      emit("update:query", q);
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$G, [
        _cache[7] || (_cache[7] = createStaticVNode('<span hidden data-testid="zabbix-functions" data-v-4026e5eb></span><span hidden data-testid="zabbix-cascade-filters" data-v-4026e5eb></span><span hidden data-testid="zabbix-group" data-v-4026e5eb></span><span hidden data-testid="zabbix-host" data-v-4026e5eb></span><span hidden data-testid="zabbix-application" data-v-4026e5eb></span><span hidden data-testid="zabbix-itemTag" data-v-4026e5eb></span><span hidden data-testid="zabbix-item" data-v-4026e5eb></span>', 7)),
        createVNode(InlineFieldRow, null, {
          default: withCtx(() => [
            createVNode(InlineField, {
              label: "Group",
              "label-width": 12
            }, {
              default: withCtx(() => [
                createVNode(MetricPicker, {
                  value: filterDisplay(__props.query.group),
                  options: toOptions(unref(groups).options.value),
                  loading: unref(groups).loading.value,
                  variables: __props.variables,
                  "test-id": "zabbix-group",
                  placeholder: "Group",
                  "onUpdate:value": _cache[0] || (_cache[0] = ($event) => patchFilter("group", $event))
                }, null, 8, ["value", "options", "loading", "variables"])
              ]),
              _: 1
              /* STABLE */
            }),
            createVNode(InlineField, {
              label: "Host tag",
              "label-width": 12,
              grow: ""
            }, {
              default: withCtx(() => [
                createVNode(HostTagQueryEditor, {
                  tags: __props.query.hostTags || [],
                  evaltype: __props.query.evaltype || "0",
                  "tag-options": hostTagOptions.value,
                  "zabbix-major": __props.zabbixMajor ?? 6,
                  onChange: onHostTags
                }, null, 8, ["tags", "evaltype", "tag-options", "zabbix-major"])
              ]),
              _: 1
              /* STABLE */
            }),
            createVNode(InlineField, {
              label: "Host",
              "label-width": 12
            }, {
              default: withCtx(() => [
                createVNode(MetricPicker, {
                  value: filterDisplay(__props.query.host),
                  options: toOptions(unref(hosts).options.value),
                  loading: unref(hosts).loading.value,
                  variables: __props.variables,
                  "test-id": "zabbix-host",
                  placeholder: "Host",
                  "onUpdate:value": _cache[1] || (_cache[1] = ($event) => patchFilter("host", $event))
                }, null, 8, ["value", "options", "loading", "variables"])
              ]),
              _: 1
              /* STABLE */
            })
          ]),
          _: 1
          /* STABLE */
        }),
        createVNode(InlineFieldRow, null, {
          default: withCtx(() => [
            useApplications.value ? (openBlock(), createBlock(InlineField, {
              key: 0,
              label: "Application",
              "label-width": 12
            }, {
              default: withCtx(() => [
                createVNode(MetricPicker, {
                  value: filterDisplay(__props.query.application),
                  options: toOptions(unref(applications).options.value),
                  loading: unref(applications).loading.value,
                  variables: __props.variables,
                  "test-id": "zabbix-application",
                  placeholder: "Application",
                  "onUpdate:value": _cache[2] || (_cache[2] = ($event) => patchFilter("application", $event))
                }, null, 8, ["value", "options", "loading", "variables"])
              ]),
              _: 1
              /* STABLE */
            })) : (openBlock(), createBlock(InlineField, {
              key: 1,
              label: "Item tag",
              "label-width": 12
            }, {
              default: withCtx(() => [
                createVNode(MetricPicker, {
                  value: filterDisplay(__props.query.itemTag),
                  options: itemTagOptions.value,
                  variables: __props.variables,
                  "test-id": "zabbix-itemTag",
                  placeholder: "tag: value",
                  "onUpdate:value": _cache[3] || (_cache[3] = ($event) => patchFilter("itemTag", $event))
                }, null, 8, ["value", "options", "variables"])
              ]),
              _: 1
              /* STABLE */
            })),
            createVNode(InlineField, {
              label: "Item",
              "label-width": 12,
              grow: ""
            }, {
              default: withCtx(() => [
                createVNode(MetricPicker, {
                  value: filterDisplay(__props.query.item),
                  options: toOptions(unref(items).options.value),
                  loading: unref(items).loading.value,
                  variables: __props.variables,
                  "test-id": "zabbix-item",
                  placeholder: "Item",
                  "onUpdate:value": _cache[4] || (_cache[4] = ($event) => patchFilter("item", $event))
                }, null, 8, ["value", "options", "loading", "variables"])
              ]),
              _: 1
              /* STABLE */
            })
          ]),
          _: 1
          /* STABLE */
        }),
        createVNode(LldSelector, {
          query: __props.query,
          "datasource-api": __props.datasourceApi || null,
          hostids: hostids.value,
          "onUpdate:query": onUpdate,
          onItemCountChange: _cache[5] || (_cache[5] = ($event) => emit("item-count-change", $event))
        }, null, 8, ["query", "datasource-api", "hostids"]),
        createVNode(InlineFieldRow, { filler: false }, {
          default: withCtx(() => [
            createVNode(InlineField, {
              label: "Functions",
              "label-width": 12,
              grow: ""
            }, {
              default: withCtx(() => [
                createVNode(FunctionEditor$1, {
                  modelValue: functions.value,
                  "onUpdate:modelValue": _cache[6] || (_cache[6] = ($event) => functions.value = $event)
                }, null, 8, ["modelValue"])
              ]),
              _: 1
              /* STABLE */
            })
          ]),
          _: 1
          /* STABLE */
        })
      ]);
    };
  }
});
const MetricsQueryEditor = /* @__PURE__ */ _export_sfc(_sfc_main$J, [["__scopeId", "data-v-4026e5eb"]]);
const _hoisted_1$F = ["data-testid", "data-disabled"];
const _hoisted_2$u = {
  key: 0,
  class: "vmp-selected",
  "data-testid": "metadata-selected"
};
const _hoisted_3$o = ["aria-busy"];
const _hoisted_4$i = ["aria-selected", "disabled", "onClick"];
const _hoisted_5$g = { class: "vmp-label" };
const _hoisted_6$d = {
  key: 0,
  class: "vmp-empty"
};
const _hoisted_7$b = {
  key: 1,
  class: "vmp-empty"
};
const _hoisted_8$6 = { class: "vmp-footer" };
const _hoisted_9$5 = {
  key: 0,
  class: "vmp-warn",
  "data-testid": "metadata-truncated"
};
const _hoisted_10$4 = ["disabled"];
const _hoisted_11$4 = { class: "vmp-count" };
const ROW_H = 28;
const OVERSCAN = 20;
const WINDOW = 80;
const _sfc_main$I = /* @__PURE__ */ defineComponent({
  __name: "VirtualMetadataPicker",
  props: {
    modelValue: { default: "" },
    options: { default: () => [] },
    loading: { type: Boolean, default: false },
    truncated: { type: Boolean, default: false },
    complete: { type: Boolean, default: true },
    placeholder: { default: "搜索…" },
    testId: { default: "virtual-metadata-picker" },
    disabled: { type: Boolean, default: false },
    remoteSearch: { type: Boolean, default: false }
  },
  emits: ["update:modelValue", "search", "load-more"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const query = ref("");
    const scrollTop = ref(0);
    const viewportH = ref(ROW_H * 10);
    let searchTimer = null;
    const selected = computed(() => String(props.modelValue || "").trim());
    const filtered = computed(() => {
      const q = query.value.trim().toLowerCase();
      const list = props.options || [];
      if (!q || props.remoteSearch) return list;
      return list.filter(
        (o) => o.label.toLowerCase().includes(q) || o.value.toLowerCase().includes(q) || String(o.id || "").includes(q)
      );
    });
    const displayList = computed(() => {
      const list = filtered.value.slice();
      if (selected.value && !list.some((o) => o.value === selected.value)) {
        list.unshift({ label: selected.value, value: selected.value });
      }
      return list;
    });
    const total = computed(() => displayList.value.length);
    const start = computed(
      () => Math.max(0, Math.floor(scrollTop.value / ROW_H) - OVERSCAN)
    );
    const end = computed(
      () => Math.min(total.value, start.value + WINDOW + OVERSCAN * 2)
    );
    const windowItems = computed(
      () => displayList.value.slice(start.value, end.value).map((item, i) => ({
        item,
        index: start.value + i
      }))
    );
    const padTop = computed(() => start.value * ROW_H);
    const padBottom = computed(
      () => Math.max(0, (total.value - end.value) * ROW_H)
    );
    function onScroll(ev) {
      const el = ev.target;
      scrollTop.value = el.scrollTop;
      viewportH.value = el.clientHeight;
      if (el.scrollTop + el.clientHeight >= el.scrollHeight - ROW_H * 4) {
        if (!props.complete) emit("load-more");
      }
    }
    function onSearchInput(v) {
      query.value = String(v ?? "");
      if (!props.remoteSearch) return;
      if (searchTimer) clearTimeout(searchTimer);
      searchTimer = setTimeout(() => {
        emit("search", query.value.trim());
      }, 300);
    }
    function select(value) {
      emit("update:modelValue", value);
    }
    watch(
      () => props.options?.length,
      () => {
        scrollTop.value = 0;
      }
    );
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", {
        class: "vmp",
        "data-testid": __props.testId,
        "data-disabled": __props.disabled || void 0
      }, [
        createVNode(unref(GInput), {
          value: query.value,
          placeholder: __props.placeholder,
          disabled: __props.disabled,
          "test-id": "metadata-search",
          "onUpdate:value": _cache[0] || (_cache[0] = ($event) => onSearchInput(String($event ?? "")))
        }, null, 8, ["value", "placeholder", "disabled"]),
        selected.value ? (openBlock(), createElementBlock(
          "div",
          _hoisted_2$u,
          " 已选：" + toDisplayString(selected.value),
          1
          /* TEXT */
        )) : createCommentVNode("v-if", true),
        createElementVNode("div", {
          class: "vmp-list",
          role: "listbox",
          "aria-busy": __props.loading || void 0,
          onScroll
        }, [
          createElementVNode(
            "div",
            {
              class: "vmp-spacer",
              style: normalizeStyle({ height: padTop.value + "px" })
            },
            null,
            4
            /* STYLE */
          ),
          (openBlock(true), createElementBlock(
            Fragment,
            null,
            renderList(windowItems.value, ({ item, index: index2 }) => {
              return openBlock(), createElementBlock("button", {
                key: item.value + ":" + index2,
                type: "button",
                role: "option",
                class: normalizeClass(["vmp-row", { active: item.value === selected.value }]),
                "aria-selected": item.value === selected.value,
                style: normalizeStyle({ height: ROW_H + "px" }),
                disabled: __props.disabled,
                onClick: ($event) => select(item.value)
              }, [
                createElementVNode(
                  "span",
                  _hoisted_5$g,
                  toDisplayString(item.label),
                  1
                  /* TEXT */
                )
              ], 14, _hoisted_4$i);
            }),
            128
            /* KEYED_FRAGMENT */
          )),
          createElementVNode(
            "div",
            {
              class: "vmp-spacer",
              style: normalizeStyle({ height: padBottom.value + "px" })
            },
            null,
            4
            /* STYLE */
          ),
          !displayList.value.length && !__props.loading ? (openBlock(), createElementBlock("div", _hoisted_6$d, "无选项")) : createCommentVNode("v-if", true),
          __props.loading ? (openBlock(), createElementBlock("div", _hoisted_7$b, "加载中…")) : createCommentVNode("v-if", true)
        ], 40, _hoisted_3$o),
        createElementVNode("div", _hoisted_8$6, [
          __props.truncated ? (openBlock(), createElementBlock("span", _hoisted_9$5, " 结果可能被截断，请缩小搜索范围 ")) : createCommentVNode("v-if", true),
          !__props.complete ? (openBlock(), createElementBlock("button", {
            key: 1,
            type: "button",
            class: "vmp-more",
            "data-testid": "metadata-load-more",
            disabled: __props.disabled || __props.loading,
            onClick: _cache[1] || (_cache[1] = ($event) => emit("load-more"))
          }, " 加载更多 ", 8, _hoisted_10$4)) : createCommentVNode("v-if", true),
          createElementVNode(
            "span",
            _hoisted_11$4,
            toDisplayString(total.value) + " 项",
            1
            /* TEXT */
          )
        ])
      ], 8, _hoisted_1$F);
    };
  }
});
const VirtualMetadataPicker = /* @__PURE__ */ _export_sfc(_sfc_main$I, [["__scopeId", "data-v-64b71318"]]);
const _hoisted_1$E = ["data-testid"];
const _hoisted_2$t = {
  key: 0,
  class: "lbl"
};
const _hoisted_3$n = {
  key: 1,
  class: "hint",
  role: "status"
};
const _sfc_main$H = /* @__PURE__ */ defineComponent({
  __name: "FilterPicker",
  props: {
    modelValue: { default: () => ({ filter: "" }) },
    options: { default: () => [] },
    loading: { type: Boolean, default: false },
    label: { default: "" },
    testId: { default: "zabbix-filter" },
    disabled: { type: Boolean, default: false },
    placeholder: { default: "选择或输入过滤条件" }
  },
  emits: ["update:modelValue", "search"],
  setup(__props, { expose: __expose, emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const useVirtual = computed(() => (props.options?.length ?? 0) > 200);
    const selectOptions = computed(
      () => (props.options || []).map((o) => ({
        label: o.text || o.value,
        value: String(o.value ?? o.text ?? "")
      }))
    );
    const selectValue = computed(() => {
      const f = String(props.modelValue?.filter || "").trim();
      return f ? [f] : [];
    });
    function findOption(token) {
      return (props.options || []).find(
        (o) => String(o.value) === token || String(o.text) === token || String(o.id) === token
      );
    }
    function onChange(raw) {
      const arr = Array.isArray(raw) ? raw.map(String) : raw == null || raw === "" ? [] : [String(raw)];
      if (!arr.length) {
        emit("update:modelValue", { filter: "" });
        return;
      }
      const token = arr[arr.length - 1];
      if (isFreeformFilter(token)) {
        emit("update:modelValue", freeformToFilter(token));
        return;
      }
      const opt = findOption(token);
      if (opt) {
        const next = optionToFilter(opt);
        emit(
          "update:modelValue",
          next.ids.length ? next : { filter: next.filter, name: next.name }
        );
        return;
      }
      emit("update:modelValue", freeformToFilter(token));
    }
    __expose({ onChange });
    const virtualOptions = computed(
      () => (props.options || []).map((o) => ({
        label: String(o.text || o.value || ""),
        value: String(o.value ?? o.text ?? ""),
        id: o.id != null ? String(o.id) : void 0
      }))
    );
    function onVirtualSelect(value) {
      const opt = findOption(value);
      if (opt) {
        emit("update:modelValue", optionToFilter(opt));
        return;
      }
      if (isFreeformFilter(value) || value) {
        emit("update:modelValue", freeformToFilter(value));
      } else {
        emit("update:modelValue", { filter: "" });
      }
    }
    return (_ctx, _cache) => {
      return useVirtual.value ? (openBlock(), createBlock(VirtualMetadataPicker, {
        key: 0,
        "model-value": String(__props.modelValue?.filter || ""),
        options: virtualOptions.value,
        loading: __props.loading,
        disabled: __props.disabled,
        placeholder: __props.placeholder,
        "test-id": __props.testId,
        "remote-search": "",
        "onUpdate:modelValue": onVirtualSelect,
        onSearch: _cache[0] || (_cache[0] = ($event) => emit("search", $event))
      }, null, 8, ["model-value", "options", "loading", "disabled", "placeholder", "test-id"])) : (openBlock(), createElementBlock("div", {
        key: 1,
        class: "filter-picker",
        "data-testid": __props.testId
      }, [
        __props.label ? (openBlock(), createElementBlock(
          "label",
          _hoisted_2$t,
          toDisplayString(__props.label),
          1
          /* TEXT */
        )) : createCommentVNode("v-if", true),
        createVNode(unref(GSelect), {
          mode: "tags",
          value: selectValue.value,
          options: selectOptions.value,
          disabled: __props.disabled,
          placeholder: __props.placeholder,
          "allow-clear": "",
          "test-id": `${__props.testId}-select`,
          "aria-label": __props.label || __props.placeholder,
          "onUpdate:value": onChange
        }, null, 8, ["value", "options", "disabled", "placeholder", "test-id", "aria-label"]),
        __props.loading ? (openBlock(), createElementBlock("p", _hoisted_3$n, "加载中…")) : createCommentVNode("v-if", true)
      ], 8, _hoisted_1$E));
    };
  }
});
const FilterPicker = /* @__PURE__ */ _export_sfc(_sfc_main$H, [["__scopeId", "data-v-3cf479da"]]);
const _hoisted_1$D = {
  class: "cascade",
  "data-testid": "zabbix-cascade-filters"
};
const _sfc_main$G = /* @__PURE__ */ defineComponent({
  __name: "CascadeFilters",
  props: {
    query: {},
    datasourceUid: {},
    datasourceApi: {},
    fields: {}
  },
  emits: ["update:query", "item-count-change"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const api = computed(
      () => resolveZabbixMetadataApi(props.datasourceUid, props.datasourceApi || null)
    );
    function patchFilter(key, value) {
      emit("update:query", { ...props.query, [key]: value });
    }
    const groups = useZabbixMetadata(async (signal) => {
      if (!api.value) return [];
      const res = await api.value.getMetadata(
        { type: "groups", filter: "" },
        signal
      );
      return res.type === "groups" ? res.values : [];
    });
    const hosts = useZabbixMetadata(async (signal) => {
      if (!api.value) return [];
      const groupids = props.query.group?.ids || [];
      if (!groupids.length && !String(props.query.group?.filter || "").trim()) {
        return [];
      }
      const res = await api.value.getMetadata(
        {
          type: "hosts",
          groupids,
          filter: "",
          hostTags: props.query.hostTags || []
        },
        signal
      );
      return res.type === "hosts" ? res.values : [];
    });
    const applications = useZabbixMetadata(async (signal) => {
      if (!api.value) return [];
      const hostids = props.query.host?.ids || [];
      const res = await api.value.getMetadata(
        { type: "applications", hostids, filter: "" },
        signal
      );
      return res.type === "applications" ? res.values : [];
    });
    const items = useZabbixMetadata(async (signal) => {
      if (!api.value) return [];
      const hostids = props.query.host?.ids || [];
      const applicationids = props.query.application?.ids || [];
      if (!hostids.length) return [];
      const res = await api.value.getMetadata(
        {
          type: "items",
          hostids,
          applicationids,
          filter: "",
          itemTag: props.query.itemTag?.filter || "",
          showDisabled: Boolean(props.query.options?.showDisabledItems)
        },
        signal
      );
      if (res.type === "items") {
        emit("item-count-change", res.values.length);
        return res.values;
      }
      return [];
    });
    const triggers = useZabbixMetadata(async (signal) => {
      if (!api.value) return [];
      const hostids = props.query.host?.ids || [];
      const res = await api.value.getMetadata(
        { type: "triggers", hostids, filter: "" },
        signal
      );
      return res.type === "triggers" ? res.values : [];
    });
    const proxies = useZabbixMetadata(async (signal) => {
      if (!api.value) return [];
      const res = await api.value.getMetadata(
        { type: "proxies", filter: "" },
        signal
      );
      return res.type === "proxies" ? res.values : [];
    });
    const macros = useZabbixMetadata(async (signal) => {
      if (!api.value) return [];
      const hostids = props.query.host?.ids || [];
      const res = await api.value.getMetadata(
        { type: "macros", hostids, filter: "" },
        signal
      );
      return res.type === "macros" ? res.values : [];
    });
    const labels = {
      group: "主机组",
      host: "主机",
      application: "应用集",
      itemTag: "监控项标签",
      item: "监控项",
      proxy: "代理",
      trigger: "触发器",
      tags: "标签",
      macro: "宏"
    };
    watch(
      () => [props.query.group?.filter, props.query.group?.ids?.join(",")],
      () => {
        groups.refresh();
        hosts.refresh();
      }
    );
    onMounted(() => {
      nextTick(() => {
        groups.refresh();
        hosts.refresh();
      });
    });
    watch(
      () => [props.query.host?.filter, props.query.host?.ids?.join(",")],
      () => {
        hosts.refresh();
        applications.refresh();
        items.refresh();
        triggers.refresh();
        macros.refresh();
      }
    );
    watch(
      () => [props.query.application?.filter, props.query.itemTag?.filter],
      () => items.refresh()
    );
    function optsFor(field) {
      switch (field) {
        case "group":
          return groups.options.value;
        case "host":
          return hosts.options.value;
        case "application":
          return applications.options.value;
        case "item":
          return items.options.value;
        case "trigger":
          return triggers.options.value;
        case "proxy":
          return proxies.options.value;
        case "macro":
          return macros.options.value;
        default:
          return [];
      }
    }
    function loadingFor(field) {
      switch (field) {
        case "group":
          return groups.loading.value;
        case "host":
          return hosts.loading.value;
        case "application":
          return applications.loading.value;
        case "item":
          return items.loading.value;
        case "trigger":
          return triggers.loading.value;
        case "proxy":
          return proxies.loading.value;
        case "macro":
          return macros.loading.value;
        default:
          return false;
      }
    }
    function valueFor(field) {
      const q = props.query;
      return q[field] || { filter: "" };
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$D, [
        createCommentVNode(" static registry for field-matrix extraction "),
        _cache[0] || (_cache[0] = createStaticVNode('<span hidden data-testid="zabbix-group" data-v-bc850fdd></span><span hidden data-testid="zabbix-host" data-v-bc850fdd></span><span hidden data-testid="zabbix-application" data-v-bc850fdd></span><span hidden data-testid="zabbix-itemTag" data-v-bc850fdd></span><span hidden data-testid="zabbix-item" data-v-bc850fdd></span><span hidden data-testid="zabbix-proxy" data-v-bc850fdd></span><span hidden data-testid="zabbix-trigger" data-v-bc850fdd></span><span hidden data-testid="zabbix-tags" data-v-bc850fdd></span><span hidden data-testid="zabbix-macro" data-v-bc850fdd></span>', 9)),
        (openBlock(true), createElementBlock(
          Fragment,
          null,
          renderList(__props.fields, (field) => {
            return openBlock(), createBlock(FilterPicker, {
              key: field,
              "model-value": valueFor(field),
              options: optsFor(field),
              loading: loadingFor(field),
              label: labels[field],
              "test-id": `zabbix-${field}`,
              "onUpdate:modelValue": ($event) => patchFilter(field, $event)
            }, null, 8, ["model-value", "options", "loading", "label", "test-id", "onUpdate:modelValue"]);
          }),
          128
          /* KEYED_FRAGMENT */
        ))
      ]);
    };
  }
});
const CascadeFilters = /* @__PURE__ */ _export_sfc(_sfc_main$G, [["__scopeId", "data-v-bc850fdd"]]);
const _hoisted_1$C = {
  class: "fields",
  "data-testid": "zabbix-fields-text"
};
const _hoisted_2$s = { class: "row" };
const _sfc_main$F = /* @__PURE__ */ defineComponent({
  __name: "TextQueryEditor",
  props: {
    query: {},
    datasourceUid: {},
    datasourceApi: {}
  },
  emits: ["update:query"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    function patch(partial) {
      emit("update:query", { ...props.query, ...partial });
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$C, [
        createVNode(CascadeFilters, {
          query: __props.query,
          "datasource-uid": __props.datasourceUid,
          "datasource-api": __props.datasourceApi,
          fields: ["group", "host", "application", "item"],
          "onUpdate:query": _cache[0] || (_cache[0] = ($event) => emit("update:query", $event))
        }, null, 8, ["query", "datasource-uid", "datasource-api"]),
        _cache[4] || (_cache[4] = createElementVNode(
          "label",
          null,
          "文本过滤",
          -1
          /* CACHED */
        )),
        createVNode(unref(GInput), {
          "model-value": __props.query.textFilter,
          "test-id": "zabbix-text-filter",
          "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => patch({ textFilter: String($event) }))
        }, null, 8, ["model-value"]),
        createElementVNode("label", _hoisted_2$s, [
          createVNode(unref(_sfc_main$19), {
            checked: __props.query.useCaptureGroups,
            "test-id": "zabbix-use-capture-groups",
            "onUpdate:checked": _cache[2] || (_cache[2] = ($event) => patch({ useCaptureGroups: $event }))
          }, null, 8, ["checked"]),
          _cache[3] || (_cache[3] = createTextVNode(
            " 使用捕获组 ",
            -1
            /* CACHED */
          ))
        ])
      ]);
    };
  }
});
const TextQueryEditor = /* @__PURE__ */ _export_sfc(_sfc_main$F, [["__scopeId", "data-v-0d88475b"]]);
const _hoisted_1$B = {
  class: "fields",
  "data-testid": "zabbix-fields-itemid"
};
const _sfc_main$E = /* @__PURE__ */ defineComponent({
  __name: "ItemIdQueryEditor",
  props: {
    query: {}
  },
  emits: ["update:query"],
  setup(__props, { emit: __emit }) {
    const emit = __emit;
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$B, [
        _cache[1] || (_cache[1] = createElementVNode(
          "label",
          null,
          "Item IDs（逗号分隔）",
          -1
          /* CACHED */
        )),
        createVNode(unref(GInput), {
          "model-value": __props.query.itemids,
          "test-id": "zabbix-itemids",
          placeholder: "10001,10002",
          "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => emit("update:query", { ...__props.query, itemids: String($event) }))
        }, null, 8, ["model-value"])
      ]);
    };
  }
});
const ItemIdQueryEditor = /* @__PURE__ */ _export_sfc(_sfc_main$E, [["__scopeId", "data-v-422148e0"]]);
const _hoisted_1$A = {
  class: "fields",
  "data-testid": "zabbix-fields-problems"
};
const _sfc_main$D = /* @__PURE__ */ defineComponent({
  __name: "ProblemsQueryEditor",
  props: {
    query: {},
    datasourceUid: {},
    datasourceApi: {},
    variables: {}
  },
  emits: ["update:query"],
  setup(__props, { emit: __emit }) {
    const SEVERITIES = [
      { label: "Not classified", value: 0 },
      { label: "Information", value: 1 },
      { label: "Warning", value: 2 },
      { label: "Average", value: 3 },
      { label: "High", value: 4 },
      { label: "Disaster", value: 5 }
    ];
    const props = __props;
    const emit = __emit;
    function patch(partial) {
      emit("update:query", { ...props.query, ...partial });
    }
    const severities = computed(() => props.query.options?.severities ?? []);
    function setSeverities(raw) {
      const arr = Array.isArray(raw) ? raw.map(Number).filter((n) => Number.isFinite(n)) : [];
      patch({ options: { ...props.query.options, severities: arr } });
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$A, [
        createVNode(CascadeFilters, {
          query: __props.query,
          "datasource-uid": __props.datasourceUid,
          "datasource-api": __props.datasourceApi,
          fields: ["group", "host", "application", "proxy", "trigger", "tags"],
          "onUpdate:query": _cache[0] || (_cache[0] = ($event) => emit("update:query", $event))
        }, null, 8, ["query", "datasource-uid", "datasource-api"]),
        createVNode(InlineFieldRow, null, {
          default: withCtx(() => [
            createVNode(InlineField, {
              label: "Host tags",
              "label-width": 12,
              grow: ""
            }, {
              default: withCtx(() => [
                createVNode(HostTagQueryEditor, {
                  tags: __props.query.hostTags || [],
                  evaltype: __props.query.evaltype || "0",
                  onChange: _cache[1] || (_cache[1] = (tags, evaltype) => patch({ hostTags: tags, evaltype }))
                }, null, 8, ["tags", "evaltype"])
              ]),
              _: 1
              /* STABLE */
            })
          ]),
          _: 1
          /* STABLE */
        }),
        createVNode(InlineFieldRow, null, {
          default: withCtx(() => [
            createVNode(InlineField, {
              label: "Severity",
              "label-width": 12
            }, {
              default: withCtx(() => [
                createVNode(unref(GSelect), {
                  mode: "multiple",
                  value: severities.value,
                  options: SEVERITIES,
                  "test-id": "zabbix-problem-severities",
                  placeholder: "全部级别",
                  "onUpdate:value": setSeverities
                }, null, 8, ["value"])
              ]),
              _: 1
              /* STABLE */
            }),
            createVNode(InlineField, {
              label: "Tags eval",
              "label-width": 12
            }, {
              default: withCtx(() => [
                createVNode(unref(GSelect), {
                  value: __props.query.evaltype || "0",
                  options: [
                    { label: "AND/OR", value: "0" },
                    { label: "OR", value: "2" }
                  ],
                  "test-id": "zabbix-problem-evaltype",
                  "onUpdate:value": _cache[2] || (_cache[2] = ($event) => patch({ evaltype: String($event) === "2" ? "2" : "0" }))
                }, null, 8, ["value"])
              ]),
              _: 1
              /* STABLE */
            }),
            createVNode(InlineField, {
              label: "Problem",
              "label-width": 12,
              grow: ""
            }, {
              default: withCtx(() => [
                createVNode(unref(GInput), {
                  "model-value": String(__props.query.trigger?.filter || ""),
                  "test-id": "zabbix-problem-text",
                  placeholder: "问题名称过滤",
                  "onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => patch({
                    trigger: {
                      ...__props.query.trigger || { filter: "" },
                      filter: String($event)
                    }
                  }))
                }, null, 8, ["model-value"])
              ]),
              _: 1
              /* STABLE */
            }),
            createVNode(InlineField, {
              label: "Show",
              "label-width": 10
            }, {
              default: withCtx(() => [
                createVNode(unref(GSelect), {
                  value: __props.query.showProblems || "problems",
                  options: [
                    { label: "Problems", value: "problems" },
                    { label: "Recent problems", value: "recent" },
                    { label: "History", value: "history" }
                  ],
                  "test-id": "zabbix-show-problems",
                  "onUpdate:value": _cache[4] || (_cache[4] = ($event) => patch({ showProblems: $event }))
                }, null, 8, ["value"])
              ]),
              _: 1
              /* STABLE */
            })
          ]),
          _: 1
          /* STABLE */
        })
      ]);
    };
  }
});
const ProblemsQueryEditor = /* @__PURE__ */ _export_sfc(_sfc_main$D, [["__scopeId", "data-v-b65b5880"]]);
const _hoisted_1$z = {
  class: "fields",
  "data-testid": "zabbix-fields-triggers"
};
const _hoisted_2$r = { class: "row" };
const _sfc_main$C = /* @__PURE__ */ defineComponent({
  __name: "TriggersQueryEditor",
  props: {
    query: {},
    datasourceUid: {},
    datasourceApi: {}
  },
  emits: ["update:query"],
  setup(__props, { emit: __emit }) {
    const SEVERITY_LABELS = [
      { label: "Not classified", value: 0 },
      { label: "Information", value: 1 },
      { label: "Warning", value: 2 },
      { label: "Average", value: 3 },
      { label: "High", value: 4 },
      { label: "Disaster", value: 5 }
    ];
    const props = __props;
    const emit = __emit;
    const countBy = computed(() => props.query.countTriggersBy || "");
    function patch(partial) {
      emit("update:query", { ...props.query, ...partial });
    }
    const cascadeFields = computed(() => {
      if (countBy.value === "problems")
        return ["group", "host", "application", "proxy", "tags"];
      if (countBy.value === "items")
        return ["group", "host", "application", "itemTag", "item", "tags"];
      return [
        "group",
        "host",
        "application",
        "itemTag",
        "item",
        "trigger",
        "tags"
      ];
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$z, [
        createVNode(InlineFieldRow, null, {
          default: withCtx(() => [
            createVNode(InlineField, {
              label: "Count by",
              "label-width": 12
            }, {
              default: withCtx(() => [
                createVNode(unref(GSelect), {
                  value: countBy.value,
                  options: [
                    { label: "All triggers", value: "" },
                    { label: "Problems", value: "problems" },
                    { label: "Items", value: "items" }
                  ],
                  "test-id": "zabbix-count-by",
                  "onUpdate:value": _cache[0] || (_cache[0] = ($event) => patch({ countTriggersBy: $event || "" }))
                }, null, 8, ["value"])
              ]),
              _: 1
              /* STABLE */
            }),
            createVNode(InlineField, {
              label: "Min severity",
              "label-width": 12
            }, {
              default: withCtx(() => [
                createVNode(unref(GSelect), {
                  value: __props.query.options?.minSeverity ?? 0,
                  options: SEVERITY_LABELS,
                  "test-id": "zabbix-opt-min-severity",
                  "onUpdate:value": _cache[1] || (_cache[1] = ($event) => patch({
                    options: { ...__props.query.options, minSeverity: Number($event) }
                  }))
                }, null, 8, ["value"])
              ]),
              _: 1
              /* STABLE */
            })
          ]),
          _: 1
          /* STABLE */
        }),
        createVNode(CascadeFilters, {
          query: __props.query,
          "datasource-uid": __props.datasourceUid,
          "datasource-api": __props.datasourceApi,
          fields: [...cascadeFields.value],
          "onUpdate:query": _cache[2] || (_cache[2] = ($event) => emit("update:query", $event))
        }, null, 8, ["query", "datasource-uid", "datasource-api", "fields"]),
        countBy.value === "problems" ? (openBlock(), createBlock(InlineFieldRow, { key: 0 }, {
          default: withCtx(() => [
            createVNode(InlineField, {
              label: "Problem",
              "label-width": 12,
              grow: ""
            }, {
              default: withCtx(() => [
                createVNode(unref(GInput), {
                  "model-value": String(__props.query.trigger?.filter || ""),
                  "test-id": "zabbix-trigger-problem",
                  placeholder: "问题过滤",
                  "onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => patch({
                    trigger: {
                      ...__props.query.trigger || { filter: "" },
                      filter: String($event)
                    }
                  }))
                }, null, 8, ["model-value"])
              ]),
              _: 1
              /* STABLE */
            })
          ]),
          _: 1
          /* STABLE */
        })) : createCommentVNode("v-if", true),
        createElementVNode("label", _hoisted_2$r, [
          createVNode(unref(_sfc_main$19), {
            checked: Boolean(__props.query.options?.count),
            "test-id": "zabbix-count-triggers",
            "onUpdate:checked": _cache[4] || (_cache[4] = ($event) => patch({ options: { ...__props.query.options, count: $event } }))
          }, null, 8, ["checked"]),
          _cache[5] || (_cache[5] = createTextVNode(
            " 仅返回数量 ",
            -1
            /* CACHED */
          ))
        ])
      ]);
    };
  }
});
const TriggersQueryEditor = /* @__PURE__ */ _export_sfc(_sfc_main$C, [["__scopeId", "data-v-9e1c71cd"]]);
const _hoisted_1$y = {
  class: "fields",
  "data-testid": "zabbix-fields-services"
};
const _sfc_main$B = /* @__PURE__ */ defineComponent({
  __name: "ServicesQueryEditor",
  props: {
    query: {},
    datasourceUid: {},
    datasourceApi: {},
    variables: {},
    supportsSla: { type: Boolean }
  },
  emits: ["update:query"],
  setup(__props, { emit: __emit }) {
    const SLA_PROPERTY = [
      { label: "状态", value: "status" },
      { label: "SLI", value: "sli" },
      { label: "正常时长", value: "uptime" },
      { label: "故障时长", value: "downtime" },
      { label: "错误预算", value: "error_budget" }
    ];
    const SLA_INTERVAL = [
      { label: "无间隔", value: "none" },
      { label: "自动", value: "auto" },
      { label: "1 小时", value: "1h" },
      { label: "12 小时", value: "12h" },
      { label: "24 小时", value: "1d" },
      { label: "1 周", value: "1w" },
      { label: "1 月", value: "1M" }
    ];
    const props = __props;
    const emit = __emit;
    const api = computed(
      () => resolveZabbixMetadataApi(props.datasourceUid, props.datasourceApi || null)
    );
    const services = useZabbixMetadata(async (signal) => {
      if (!api.value) return [];
      const res = await api.value.getMetadata(
        { type: "services", filter: props.query.itServiceFilter || "" },
        signal
      );
      return res.type === "services" ? res.values : [];
    });
    const slas = useZabbixMetadata(async (signal) => {
      if (!api.value || props.supportsSla === false) return [];
      const serviceids = services.options.value.map((s) => String(s.id || s.value)).filter(Boolean);
      const res = await api.value.getMetadata(
        { type: "slas", serviceids, filter: props.query.slaFilter || "" },
        signal
      );
      return res.type === "slas" ? res.values : [];
    });
    watch(
      () => props.query.itServiceFilter,
      () => services.refresh()
    );
    onMounted(() => {
      nextTick(() => services.refresh());
    });
    watch(
      () => [props.query.slaFilter, services.options.value.length],
      () => slas.refresh()
    );
    function patch(partial) {
      emit("update:query", { ...props.query, ...partial });
    }
    function serviceOptions() {
      return services.options.value.map((s) => ({
        label: s.text || s.value,
        value: String(s.value ?? s.text ?? "")
      }));
    }
    function slaOptions() {
      return slas.options.value.map((s) => ({
        label: s.text || s.value,
        value: String(s.value ?? s.text ?? "")
      }));
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$y, [
        createVNode(InlineFieldRow, null, {
          default: withCtx(() => [
            createVNode(InlineField, {
              label: "Service",
              "label-width": 12,
              grow: ""
            }, {
              default: withCtx(() => [
                createVNode(MetricPicker, {
                  value: __props.query.itServiceFilter,
                  options: serviceOptions(),
                  loading: unref(services).loading.value,
                  variables: __props.variables,
                  "test-id": "zabbix-service-filter",
                  placeholder: "IT 服务",
                  "onUpdate:value": _cache[0] || (_cache[0] = ($event) => patch({ itServiceFilter: $event }))
                }, null, 8, ["value", "options", "loading", "variables"])
              ]),
              _: 1
              /* STABLE */
            }),
            __props.supportsSla !== false ? (openBlock(), createBlock(InlineField, {
              key: 0,
              label: "SLA",
              "label-width": 12,
              grow: ""
            }, {
              default: withCtx(() => [
                createVNode(MetricPicker, {
                  value: __props.query.slaFilter,
                  options: slaOptions(),
                  loading: unref(slas).loading.value,
                  variables: __props.variables,
                  "test-id": "zabbix-sla-filter",
                  placeholder: "SLA",
                  "onUpdate:value": _cache[1] || (_cache[1] = ($event) => patch({ slaFilter: $event }))
                }, null, 8, ["value", "options", "loading", "variables"])
              ]),
              _: 1
              /* STABLE */
            })) : createCommentVNode("v-if", true)
          ]),
          _: 1
          /* STABLE */
        }),
        createVNode(InlineFieldRow, null, {
          default: withCtx(() => [
            createVNode(InlineField, {
              label: "Property",
              "label-width": 12
            }, {
              default: withCtx(() => [
                createVNode(unref(GSelect), {
                  value: __props.query.slaProperty || "sli",
                  options: SLA_PROPERTY,
                  "test-id": "zabbix-sla-property",
                  "onUpdate:value": _cache[2] || (_cache[2] = ($event) => patch({ slaProperty: String($event) }))
                }, null, 8, ["value"])
              ]),
              _: 1
              /* STABLE */
            }),
            createVNode(InlineField, {
              label: "Interval",
              "label-width": 12
            }, {
              default: withCtx(() => [
                createVNode(unref(GSelect), {
                  value: __props.query.slaInterval || "none",
                  options: SLA_INTERVAL,
                  "test-id": "zabbix-sla-interval",
                  "onUpdate:value": _cache[3] || (_cache[3] = ($event) => patch({ slaInterval: String($event) }))
                }, null, 8, ["value"])
              ]),
              _: 1
              /* STABLE */
            })
          ]),
          _: 1
          /* STABLE */
        })
      ]);
    };
  }
});
const ServicesQueryEditor = /* @__PURE__ */ _export_sfc(_sfc_main$B, [["__scopeId", "data-v-e28f273d"]]);
const _hoisted_1$x = {
  class: "fields",
  "data-testid": "zabbix-fields-macros"
};
const _sfc_main$A = /* @__PURE__ */ defineComponent({
  __name: "MacrosQueryEditor",
  props: {
    query: {},
    datasourceUid: {},
    datasourceApi: {}
  },
  emits: ["update:query"],
  setup(__props, { emit: __emit }) {
    const emit = __emit;
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$x, [
        createVNode(CascadeFilters, {
          query: __props.query,
          "datasource-uid": __props.datasourceUid,
          "datasource-api": __props.datasourceApi,
          fields: ["group", "host", "macro"],
          "onUpdate:query": _cache[0] || (_cache[0] = ($event) => emit("update:query", $event))
        }, null, 8, ["query", "datasource-uid", "datasource-api"])
      ]);
    };
  }
});
const MacrosQueryEditor = /* @__PURE__ */ _export_sfc(_sfc_main$A, [["__scopeId", "data-v-65d7b236"]]);
const ITEM_COUNT_WARNING_THRESHOLD = 500;
const TIME_RANGE_WARNING_THRESHOLD_DAYS = 365;
function getTimeRangeDurationDays(range) {
  const from = range?.from?.valueOf?.() ?? NaN;
  const to = range?.to?.valueOf?.() ?? NaN;
  if (!Number.isFinite(from) || !Number.isFinite(to) || to < from) return 0;
  return (to - from) / (1e3 * 60 * 60 * 24);
}
function isTimeRangeLarge(range, thresholdDays = TIME_RANGE_WARNING_THRESHOLD_DAYS) {
  const days = getTimeRangeDurationDays(range);
  return days >= thresholdDays;
}
function formatDurationDays(days) {
  const whole = Math.floor(days);
  if (whole < 365) return `${whole} 天`;
  const years = Math.floor(whole / 365);
  const rem = whole % 365;
  if (rem === 0) return `${years} 年`;
  return `${years} 年 ${rem} 天`;
}
function shouldWarnItemCount(count, threshold = ITEM_COUNT_WARNING_THRESHOLD) {
  return Number.isFinite(count) && count >= threshold;
}
const _hoisted_1$w = ["data-testid"];
const _hoisted_2$q = {
  class: "editor-alert__icon",
  "aria-hidden": "true"
};
const _hoisted_3$m = { class: "editor-alert__body" };
const _hoisted_4$h = { class: "editor-alert__title" };
const _hoisted_5$f = {
  key: 0,
  class: "editor-alert__msg"
};
const _sfc_main$z = /* @__PURE__ */ defineComponent({
  __name: "EditorAlert",
  props: {
    title: {},
    message: { default: "" },
    testId: { default: "zabbix-editor-alert" },
    severity: { default: "warning" }
  },
  setup(__props) {
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", {
        class: normalizeClass(["editor-alert", `editor-alert--${__props.severity}`]),
        role: "status",
        "aria-live": "polite",
        "data-testid": __props.testId
      }, [
        createElementVNode("span", _hoisted_2$q, [
          createVNode(unref(GIcon), { name: "exclamation-triangle" })
        ]),
        createElementVNode("div", _hoisted_3$m, [
          createElementVNode(
            "strong",
            _hoisted_4$h,
            toDisplayString(__props.title),
            1
            /* TEXT */
          ),
          __props.message ? (openBlock(), createElementBlock(
            "p",
            _hoisted_5$f,
            toDisplayString(__props.message),
            1
            /* TEXT */
          )) : createCommentVNode("v-if", true),
          renderSlot(_ctx.$slots, "default", {}, void 0, true)
        ])
      ], 10, _hoisted_1$w);
    };
  }
});
const EditorAlert = /* @__PURE__ */ _export_sfc(_sfc_main$z, [["__scopeId", "data-v-300ed766"]]);
const _sfc_main$y = /* @__PURE__ */ defineComponent({
  __name: "ItemCountWarning",
  props: {
    itemCount: {},
    threshold: { default: ITEM_COUNT_WARNING_THRESHOLD }
  },
  setup(__props) {
    const props = __props;
    const visible = computed(
      () => shouldWarnItemCount(props.itemCount, props.threshold)
    );
    return (_ctx, _cache) => {
      return visible.value ? (openBlock(), createBlock(EditorAlert, {
        key: 0,
        title: "监控项数量过多",
        message: `此查询匹配 ${__props.itemCount} 个监控项，可能返回大量数据，请缩小筛选范围。`,
        "test-id": "zabbix-item-count-warning"
      }, null, 8, ["message"])) : createCommentVNode("v-if", true);
    };
  }
});
const _sfc_main$x = /* @__PURE__ */ defineComponent({
  __name: "TimeRangeWarning",
  props: {
    range: {}
  },
  setup(__props) {
    const props = __props;
    const visible = computed(
      () => props.range ? isTimeRangeLarge(props.range) : false
    );
    const duration = computed(
      () => props.range ? formatDurationDays(getTimeRangeDurationDays(props.range)) : ""
    );
    return (_ctx, _cache) => {
      return visible.value ? (openBlock(), createBlock(EditorAlert, {
        key: 0,
        title: "时间范围过大",
        message: `当前选择的时间范围为 ${duration.value}。该查询可能返回大量数据并耗时较长。`,
        "test-id": "zabbix-time-range-warning"
      }, null, 8, ["message"])) : createCommentVNode("v-if", true);
    };
  }
});
const _hoisted_1$v = {
  key: 0,
  class: "opts",
  "data-testid": "zabbix-query-options"
};
const _hoisted_2$p = ["aria-expanded"];
const _hoisted_3$l = { class: "chev" };
const _hoisted_4$g = {
  key: 0,
  class: "summary",
  "data-testid": "zabbix-query-options-summary"
};
const _hoisted_5$e = {
  key: 1,
  class: "summary muted"
};
const _hoisted_6$c = {
  class: "opts-body",
  "data-testid": "zabbix-query-options-body"
};
const _hoisted_7$a = {
  key: 1,
  "data-testid": "zabbix-query-options-empty",
  class: "empty"
};
const _sfc_main$w = /* @__PURE__ */ defineComponent({
  __name: "QueryOptionsEditor",
  props: {
    options: {},
    queryType: {}
  },
  emits: ["update:options"],
  setup(__props, { expose: __expose, emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const expanded = ref(false);
    const code = computed(
      () => normalizeZabbixQueryType(props.queryType)
    );
    const show = computed(() => {
      const c = code.value;
      return {
        showDisabled: c === "0" || c === "3",
        skipEmpty: c === "0" || c === "2" || c === "3",
        alignment: c === "0" || c === "1" || c === "3",
        valueMapping: c === "0" || c === "3",
        trends: c === "0" || c === "1" || c === "3",
        severity: c === "4" || c === "5",
        sort: c === "5",
        ack: c === "4" || c === "5",
        maintenance: c === "5",
        proxy: c === "5",
        limit: c === "5",
        timeRange: c === "4" || c === "5",
        fetchHistorical: c === "5",
        count: c === "4",
        any: c !== "6"
      };
    });
    const summary = computed(() => {
      const o = props.options || {};
      const parts = [];
      if (show.value.trends && o.useTrends && o.useTrends !== "default")
        parts.push(`Trends = ${o.useTrends}`);
      if (show.value.showDisabled && o.showDisabledItems)
        parts.push("Show disabled items = true");
      if (show.value.valueMapping && o.useZabbixValueMapping)
        parts.push("Use Zabbix value mapping = true");
      if (show.value.alignment && o.disableDataAlignment)
        parts.push("Disable data alignment = true");
      if (show.value.skipEmpty && o.skipEmptyValues)
        parts.push("Skip empty values = true");
      if (show.value.severity && o.minSeverity != null && o.minSeverity > 0)
        parts.push(`Min severity = ${o.minSeverity}`);
      if (show.value.sort && o.sortProblems && o.sortProblems !== "default")
        parts.push(`Sort = ${o.sortProblems}`);
      if (show.value.ack && o.acknowledged != null && o.acknowledged !== 2)
        parts.push(`Acknowledged = ${o.acknowledged}`);
      if (show.value.maintenance && o.hostsInMaintenance)
        parts.push("Hosts in maintenance = true");
      if (show.value.proxy && o.hostProxy) parts.push("Host proxy = true");
      if (show.value.limit && o.limit != null && o.limit !== 1001)
        parts.push(`Limit = ${o.limit}`);
      if (show.value.timeRange && o.useTimeRange)
        parts.push("Use time range = true");
      if (show.value.fetchHistorical && o.fetchHistoricalItemValue)
        parts.push("Fetch historical item value = true");
      if (show.value.count && o.count) parts.push("Count = true");
      return parts.join(", ");
    });
    function patchOptions(partial) {
      emit("update:options", { ...props.options, ...partial });
    }
    function clampLimit2(v) {
      return Math.min(1001, Math.max(1, Math.floor(v)));
    }
    function clampSeverity(v) {
      return Math.min(5, Math.max(0, Math.floor(v)));
    }
    __expose({ expanded, summary, clampLimit: clampLimit2, clampSeverity });
    return (_ctx, _cache) => {
      return show.value.any ? (openBlock(), createElementBlock("div", _hoisted_1$v, [
        createElementVNode("button", {
          type: "button",
          class: "opts-toggle",
          "data-testid": "zabbix-query-options-toggle",
          "aria-expanded": expanded.value,
          onClick: _cache[0] || (_cache[0] = ($event) => expanded.value = !expanded.value)
        }, [
          createElementVNode(
            "span",
            _hoisted_3$l,
            toDisplayString(expanded.value ? "▾" : "▸"),
            1
            /* TEXT */
          ),
          _cache[15] || (_cache[15] = createElementVNode(
            "strong",
            null,
            "Options",
            -1
            /* CACHED */
          )),
          !expanded.value && summary.value ? (openBlock(), createElementBlock(
            "span",
            _hoisted_4$g,
            toDisplayString(summary.value),
            1
            /* TEXT */
          )) : !expanded.value ? (openBlock(), createElementBlock("span", _hoisted_5$e, "无额外选项")) : createCommentVNode("v-if", true)
        ], 8, _hoisted_2$p),
        withDirectives(createElementVNode(
          "div",
          _hoisted_6$c,
          [
            show.value.trends || show.value.showDisabled || show.value.valueMapping || show.value.alignment ? (openBlock(), createBlock(InlineFieldRow, { key: 0 }, {
              default: withCtx(() => [
                show.value.trends ? (openBlock(), createBlock(InlineField, {
                  key: 0,
                  label: "Trends",
                  "label-width": 10
                }, {
                  default: withCtx(() => [
                    createVNode(unref(GSelect), {
                      value: __props.options.useTrends || "default",
                      options: [
                        { label: "Default", value: "default" },
                        { label: "True", value: "true" },
                        { label: "False", value: "false" }
                      ],
                      "test-id": "zabbix-opt-trends",
                      "onUpdate:value": _cache[1] || (_cache[1] = ($event) => patchOptions({ useTrends: $event }))
                    }, null, 8, ["value"])
                  ]),
                  _: 1
                  /* STABLE */
                })) : createCommentVNode("v-if", true),
                show.value.showDisabled ? (openBlock(), createBlock(InlineField, {
                  key: 1,
                  label: "Show disabled items",
                  "label-width": 18
                }, {
                  default: withCtx(() => [
                    createVNode(unref(_sfc_main$19), {
                      checked: Boolean(__props.options.showDisabledItems),
                      "test-id": "zabbix-opt-show-disabled",
                      "onUpdate:checked": _cache[2] || (_cache[2] = ($event) => patchOptions({ showDisabledItems: $event }))
                    }, null, 8, ["checked"])
                  ]),
                  _: 1
                  /* STABLE */
                })) : createCommentVNode("v-if", true),
                show.value.valueMapping ? (openBlock(), createBlock(InlineField, {
                  key: 2,
                  label: "Use Zabbix value mapping",
                  "label-width": 20
                }, {
                  default: withCtx(() => [
                    createVNode(unref(_sfc_main$19), {
                      checked: Boolean(__props.options.useZabbixValueMapping),
                      "test-id": "zabbix-opt-value-mapping",
                      "onUpdate:checked": _cache[3] || (_cache[3] = ($event) => patchOptions({ useZabbixValueMapping: $event }))
                    }, null, 8, ["checked"])
                  ]),
                  _: 1
                  /* STABLE */
                })) : createCommentVNode("v-if", true),
                show.value.alignment ? (openBlock(), createBlock(InlineField, {
                  key: 3,
                  label: "Disable data alignment",
                  "label-width": 18
                }, {
                  default: withCtx(() => [
                    createVNode(unref(_sfc_main$19), {
                      checked: Boolean(__props.options.disableDataAlignment),
                      "test-id": "zabbix-opt-disable-alignment",
                      "onUpdate:checked": _cache[4] || (_cache[4] = ($event) => patchOptions({ disableDataAlignment: $event }))
                    }, null, 8, ["checked"])
                  ]),
                  _: 1
                  /* STABLE */
                })) : createCommentVNode("v-if", true)
              ]),
              _: 1
              /* STABLE */
            })) : createCommentVNode("v-if", true),
            show.value.skipEmpty ? (openBlock(), createBlock(InlineFieldRow, { key: 1 }, {
              default: withCtx(() => [
                createVNode(InlineField, {
                  label: "Skip empty values",
                  "label-width": 16
                }, {
                  default: withCtx(() => [
                    createVNode(unref(_sfc_main$19), {
                      checked: Boolean(__props.options.skipEmptyValues),
                      "test-id": "zabbix-opt-skip-empty",
                      "onUpdate:checked": _cache[5] || (_cache[5] = ($event) => patchOptions({ skipEmptyValues: $event }))
                    }, null, 8, ["checked"])
                  ]),
                  _: 1
                  /* STABLE */
                })
              ]),
              _: 1
              /* STABLE */
            })) : createCommentVNode("v-if", true),
            show.value.severity || show.value.sort || show.value.ack ? (openBlock(), createBlock(InlineFieldRow, { key: 2 }, {
              default: withCtx(() => [
                show.value.severity ? (openBlock(), createBlock(InlineField, {
                  key: 0,
                  label: "Min severity",
                  "label-width": 12
                }, {
                  default: withCtx(() => [
                    createVNode(unref(GInput), {
                      "model-value": __props.options.minSeverity ?? 0,
                      type: "number",
                      "test-id": "zabbix-opt-min-severity",
                      "onUpdate:modelValue": _cache[6] || (_cache[6] = ($event) => patchOptions({ minSeverity: clampSeverity(Number($event)) }))
                    }, null, 8, ["model-value"])
                  ]),
                  _: 1
                  /* STABLE */
                })) : createCommentVNode("v-if", true),
                show.value.sort ? (openBlock(), createBlock(InlineField, {
                  key: 1,
                  label: "Sort problems",
                  "label-width": 12
                }, {
                  default: withCtx(() => [
                    createVNode(unref(GSelect), {
                      value: __props.options.sortProblems || "default",
                      options: [
                        { label: "Default", value: "default" },
                        { label: "Last change", value: "lastchange" },
                        { label: "Priority", value: "priority" }
                      ],
                      "test-id": "zabbix-opt-sort",
                      "onUpdate:value": _cache[7] || (_cache[7] = ($event) => patchOptions({ sortProblems: $event }))
                    }, null, 8, ["value"])
                  ]),
                  _: 1
                  /* STABLE */
                })) : createCommentVNode("v-if", true),
                show.value.ack ? (openBlock(), createBlock(InlineField, {
                  key: 2,
                  label: "Acknowledged",
                  "label-width": 12
                }, {
                  default: withCtx(() => [
                    createVNode(unref(GSelect), {
                      value: __props.options.acknowledged ?? 2,
                      options: [
                        { label: "All", value: 2 },
                        { label: "Unacknowledged", value: 0 },
                        { label: "Acknowledged", value: 1 }
                      ],
                      "test-id": "zabbix-opt-ack",
                      "onUpdate:value": _cache[8] || (_cache[8] = ($event) => patchOptions({ acknowledged: Number($event) }))
                    }, null, 8, ["value"])
                  ]),
                  _: 1
                  /* STABLE */
                })) : createCommentVNode("v-if", true)
              ]),
              _: 1
              /* STABLE */
            })) : createCommentVNode("v-if", true),
            show.value.maintenance || show.value.proxy || show.value.limit || show.value.timeRange || show.value.fetchHistorical || show.value.count ? (openBlock(), createBlock(InlineFieldRow, { key: 3 }, {
              default: withCtx(() => [
                show.value.maintenance ? (openBlock(), createBlock(InlineField, {
                  key: 0,
                  label: "Hosts in maintenance",
                  "label-width": 18
                }, {
                  default: withCtx(() => [
                    createVNode(unref(_sfc_main$19), {
                      checked: Boolean(__props.options.hostsInMaintenance),
                      "test-id": "zabbix-opt-maintenance",
                      "onUpdate:checked": _cache[9] || (_cache[9] = ($event) => patchOptions({ hostsInMaintenance: $event }))
                    }, null, 8, ["checked"])
                  ]),
                  _: 1
                  /* STABLE */
                })) : createCommentVNode("v-if", true),
                show.value.proxy ? (openBlock(), createBlock(InlineField, {
                  key: 1,
                  label: "Show proxy",
                  "label-width": 12
                }, {
                  default: withCtx(() => [
                    createVNode(unref(_sfc_main$19), {
                      checked: Boolean(__props.options.hostProxy),
                      "test-id": "zabbix-opt-proxy",
                      "onUpdate:checked": _cache[10] || (_cache[10] = ($event) => patchOptions({ hostProxy: $event }))
                    }, null, 8, ["checked"])
                  ]),
                  _: 1
                  /* STABLE */
                })) : createCommentVNode("v-if", true),
                show.value.limit ? (openBlock(), createBlock(InlineField, {
                  key: 2,
                  label: "Limit",
                  "label-width": 8
                }, {
                  default: withCtx(() => [
                    createVNode(unref(GInput), {
                      "model-value": __props.options.limit ?? 1001,
                      type: "number",
                      "test-id": "zabbix-opt-limit",
                      "onUpdate:modelValue": _cache[11] || (_cache[11] = ($event) => patchOptions({ limit: clampLimit2(Number($event)) }))
                    }, null, 8, ["model-value"])
                  ]),
                  _: 1
                  /* STABLE */
                })) : createCommentVNode("v-if", true),
                show.value.timeRange ? (openBlock(), createBlock(InlineField, {
                  key: 3,
                  label: "Use time range",
                  "label-width": 14
                }, {
                  default: withCtx(() => [
                    createVNode(unref(_sfc_main$19), {
                      checked: Boolean(__props.options.useTimeRange),
                      "test-id": "zabbix-opt-time-range",
                      "onUpdate:checked": _cache[12] || (_cache[12] = ($event) => patchOptions({ useTimeRange: $event }))
                    }, null, 8, ["checked"])
                  ]),
                  _: 1
                  /* STABLE */
                })) : createCommentVNode("v-if", true),
                show.value.fetchHistorical ? (openBlock(), createBlock(InlineField, {
                  key: 4,
                  label: "Historical item value",
                  "label-width": 18
                }, {
                  default: withCtx(() => [
                    createVNode(unref(_sfc_main$19), {
                      checked: Boolean(__props.options.fetchHistoricalItemValue),
                      "test-id": "zabbix-opt-historical",
                      "onUpdate:checked": _cache[13] || (_cache[13] = ($event) => patchOptions({ fetchHistoricalItemValue: $event }))
                    }, null, 8, ["checked"])
                  ]),
                  _: 1
                  /* STABLE */
                })) : createCommentVNode("v-if", true),
                show.value.count ? (openBlock(), createBlock(InlineField, {
                  key: 5,
                  label: "Count only",
                  "label-width": 10
                }, {
                  default: withCtx(() => [
                    createVNode(unref(_sfc_main$19), {
                      checked: Boolean(__props.options.count),
                      "test-id": "zabbix-opt-count",
                      "onUpdate:checked": _cache[14] || (_cache[14] = ($event) => patchOptions({ count: $event }))
                    }, null, 8, ["checked"])
                  ]),
                  _: 1
                  /* STABLE */
                })) : createCommentVNode("v-if", true)
              ]),
              _: 1
              /* STABLE */
            })) : createCommentVNode("v-if", true)
          ],
          512
          /* NEED_PATCH */
        ), [
          [vShow, expanded.value]
        ])
      ])) : (openBlock(), createElementBlock("div", _hoisted_7$a));
    };
  }
});
const QueryOptionsEditor = /* @__PURE__ */ _export_sfc(_sfc_main$w, [["__scopeId", "data-v-06e7e1b4"]]);
const _hoisted_1$u = {
  class: "zbx-qe",
  "data-testid": "query-editor-zabbix"
};
const _sfc_main$v = /* @__PURE__ */ defineComponent({
  __name: "QueryEditor",
  props: {
    query: {},
    onChange: { type: Function },
    onRunQuery: { type: Function },
    datasource: {},
    range: {},
    datasourceApi: {},
    variables: {}
  },
  setup(__props, { expose: __expose }) {
    const TYPE_OPTIONS = [
      { label: "指标", value: "0" },
      { label: "IT 服务", value: "1" },
      { label: "文本", value: "2" },
      { label: "监控项 ID", value: "3" },
      { label: "触发器", value: "4" },
      { label: "问题", value: "5" },
      { label: "宏", value: "6" }
    ];
    const props = __props;
    const itemCount = ref(0);
    const query = computed(() => migrateZabbixQuery(props.query || {}));
    const queryType = computed(
      () => normalizeZabbixQueryType(query.value.queryType)
    );
    const datasourceUid = computed(
      () => String(
        props.datasource?.uid || props.query?.datasource?.uid || ""
      )
    );
    const metaApi = computed(
      () => resolveZabbixMetadataApi(
        datasourceUid.value,
        props.datasourceApi || props.datasource || null
      )
    );
    function update(next) {
      const base = props.query;
      props.onChange({
        ...base,
        ...next,
        refId: next.refId ?? base?.refId,
        datasource: next.datasource ?? base?.datasource,
        hide: next.hide ?? base?.hide
      });
    }
    function setQueryType(v) {
      const code = normalizeZabbixQueryType(v);
      update({ ...query.value, queryType: code });
    }
    const legendFormat = computed({
      get: () => String(query.value.legendFormat || ""),
      set: (v) => update({ ...query.value, legendFormat: v })
    });
    const vars = computed(() => props.variables || []);
    __expose({ setQueryType, update, queryType });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$u, [
        createVNode(_sfc_main$x, {
          range: props.range
        }, null, 8, ["range"]),
        queryType.value === "0" ? (openBlock(), createBlock(_sfc_main$y, {
          key: 0,
          "item-count": itemCount.value
        }, null, 8, ["item-count"])) : createCommentVNode("v-if", true),
        createVNode(InlineFieldRow, null, {
          default: withCtx(() => [
            createVNode(InlineField, {
              label: "Query type",
              "label-width": 12,
              "html-for": "zabbix-query-type"
            }, {
              default: withCtx(() => [
                createVNode(unref(GSelect), {
                  id: "zabbix-query-type",
                  value: queryType.value,
                  options: TYPE_OPTIONS,
                  "test-id": "zabbix-query-type",
                  "onUpdate:value": setQueryType
                }, null, 8, ["value"])
              ]),
              _: 1
              /* STABLE */
            })
          ]),
          _: 1
          /* STABLE */
        }),
        queryType.value === "0" ? (openBlock(), createBlock(MetricsQueryEditor, {
          key: 1,
          query: query.value,
          "datasource-uid": datasourceUid.value,
          "datasource-api": metaApi.value,
          variables: vars.value,
          "onUpdate:query": update,
          onItemCountChange: _cache[0] || (_cache[0] = ($event) => itemCount.value = $event)
        }, null, 8, ["query", "datasource-uid", "datasource-api", "variables"])) : queryType.value === "1" ? (openBlock(), createBlock(ServicesQueryEditor, {
          key: 2,
          query: query.value,
          "datasource-uid": datasourceUid.value,
          "datasource-api": metaApi.value,
          variables: vars.value,
          "onUpdate:query": update
        }, null, 8, ["query", "datasource-uid", "datasource-api", "variables"])) : queryType.value === "2" ? (openBlock(), createBlock(TextQueryEditor, {
          key: 3,
          query: query.value,
          "datasource-uid": datasourceUid.value,
          "datasource-api": metaApi.value,
          "onUpdate:query": update
        }, null, 8, ["query", "datasource-uid", "datasource-api"])) : queryType.value === "3" ? (openBlock(), createBlock(ItemIdQueryEditor, {
          key: 4,
          query: query.value,
          "onUpdate:query": update
        }, null, 8, ["query"])) : queryType.value === "4" ? (openBlock(), createBlock(TriggersQueryEditor, {
          key: 5,
          query: query.value,
          "datasource-uid": datasourceUid.value,
          "datasource-api": metaApi.value,
          "onUpdate:query": update
        }, null, 8, ["query", "datasource-uid", "datasource-api"])) : queryType.value === "5" ? (openBlock(), createBlock(ProblemsQueryEditor, {
          key: 6,
          query: query.value,
          "datasource-uid": datasourceUid.value,
          "datasource-api": metaApi.value,
          variables: vars.value,
          "onUpdate:query": update
        }, null, 8, ["query", "datasource-uid", "datasource-api", "variables"])) : queryType.value === "6" ? (openBlock(), createBlock(MacrosQueryEditor, {
          key: 7,
          query: query.value,
          "datasource-uid": datasourceUid.value,
          "datasource-api": metaApi.value,
          "onUpdate:query": update
        }, null, 8, ["query", "datasource-uid", "datasource-api"])) : createCommentVNode("v-if", true),
        createVNode(QueryOptionsEditor, {
          "query-type": queryType.value,
          options: query.value.options || {},
          "onUpdate:options": _cache[1] || (_cache[1] = ($event) => update({ ...query.value, options: $event }))
        }, null, 8, ["query-type", "options"]),
        createVNode(InlineFieldRow, null, {
          default: withCtx(() => [
            createVNode(InlineField, {
              label: "Legend",
              "label-width": 12,
              grow: ""
            }, {
              default: withCtx(() => [
                createVNode(unref(GInput), {
                  modelValue: legendFormat.value,
                  "onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => legendFormat.value = $event),
                  placeholder: "{{item}}",
                  "test-id": "zabbix-legend"
                }, null, 8, ["modelValue"])
              ]),
              _: 1
              /* STABLE */
            })
          ]),
          _: 1
          /* STABLE */
        }),
        createVNode(unref(GButton), {
          size: "sm",
          variant: "primary",
          "test-id": "run-query",
          onClick: _cache[3] || (_cache[3] = ($event) => props.onRunQuery?.())
        }, {
          default: withCtx(() => [..._cache[4] || (_cache[4] = [
            createTextVNode(
              "运行查询",
              -1
              /* CACHED */
            )
          ])]),
          _: 1
          /* STABLE */
        })
      ]);
    };
  }
});
const QueryEditor$1 = /* @__PURE__ */ _export_sfc(_sfc_main$v, [["__scopeId", "data-v-63f24bf1"]]);
const DURATION_RE = /^(\d+(?:\.\d+)?)(ms|s|m|h|d|w)$/i;
const DURATION_SCALE = {
  ms: 1,
  s: 1e3,
  m: 6e4,
  h: 36e5,
  d: 864e5,
  w: 6048e5
};
function isValidDurationString(value) {
  return DURATION_RE.test(String(value || "").trim());
}
function parseDurationMs(value, fallback) {
  const m = String(value || "").trim().match(DURATION_RE);
  if (!m) return fallback;
  return Number(m[1]) * DURATION_SCALE[m[2].toLowerCase()];
}
function parseCacheTtlMs$1(raw, fallback = 36e5) {
  if (typeof raw === "number" && Number.isFinite(raw))
    return Math.max(0, Math.floor(raw));
  const s = String(raw ?? "").trim();
  if (!s) return fallback;
  if (!isValidDurationString(s)) return fallback;
  return parseDurationMs(s, fallback);
}
function shouldUseTrends(args) {
  if (args.query === "false") return false;
  if (!args.enabled && args.query !== "true") return false;
  if (args.query === "true") return args.enabled !== false;
  if (!args.enabled) return false;
  const oldEnough = args.fromMs < args.nowMs - parseDurationMs(args.trendsFrom, 7 * 864e5);
  const wideEnough = args.toMs - args.fromMs > parseDurationMs(args.trendsRange, 4 * 864e5);
  return oldEnough || wideEnough;
}
function pickTrendValue(point, mode2) {
  switch (mode2) {
    case "min":
      return Number(point.value_min);
    case "max":
      return Number(point.value_max);
    case "sum":
      return Number(point.value_avg) * Number(point.num || 0);
    case "count":
      return Number(point.num || 0);
    case "avg":
    default:
      return Number(point.value_avg);
  }
}
const _hoisted_1$t = {
  class: "zbx-cfg",
  "data-testid": "config-editor-zabbix"
};
const _hoisted_2$o = {
  class: "section",
  "aria-labelledby": "zbx-conn"
};
const _hoisted_3$k = { class: "cred-field" };
const _hoisted_4$f = {
  class: "tip-wrap",
  "data-testid": "zabbix-token-tip",
  tabindex: "0"
};
const _hoisted_5$d = {
  class: "cred-status",
  "data-testid": "zabbix-credential-status"
};
const _hoisted_6$b = {
  key: 0,
  class: "configured"
};
const _hoisted_7$9 = {
  key: 1,
  class: "not-configured"
};
const _hoisted_8$5 = {
  class: "section section-collapsible",
  "data-testid": "zabbix-additional-settings"
};
const _hoisted_9$4 = ["aria-expanded"];
const _hoisted_10$3 = {
  key: 0,
  class: "adv-body",
  role: "region",
  "aria-labelledby": "zbx-extra",
  "data-testid": "zabbix-additional-body"
};
const _hoisted_11$3 = { class: "row" };
const _hoisted_12$3 = {
  key: 1,
  class: "err",
  "data-testid": "zabbix-cache-ttl-error",
  role: "alert"
};
const _hoisted_13$3 = {
  key: 2,
  class: "err",
  "data-testid": "zabbix-timeout-error",
  role: "alert"
};
const _hoisted_14$3 = {
  key: 3,
  class: "err",
  "data-testid": "zabbix-query-timeout-error",
  role: "alert"
};
const _hoisted_15$3 = { class: "row" };
const _hoisted_16$2 = {
  class: "sr-only",
  "data-testid": "zabbix-db-candidates",
  "aria-label": "Direct DB 候选项"
};
const _hoisted_17$2 = ["data-uid", "data-type"];
const _hoisted_18$2 = {
  key: 1,
  class: "err"
};
const _hoisted_19$2 = { class: "row" };
const _hoisted_20$2 = { class: "row" };
const _hoisted_21$1 = { class: "row" };
const _hoisted_22$1 = {
  key: 5,
  "data-testid": "zabbix-enable-writes-warn"
};
const _sfc_main$u = /* @__PURE__ */ defineComponent({
  __name: "ConfigEditor",
  props: {
    options: {},
    onOptionsChange: { type: Function },
    onValidationChange: { type: Function }
  },
  setup(__props) {
    const DIRECT_DB_TYPES = /* @__PURE__ */ new Set([
      "mysql",
      "postgres",
      "postgresql",
      "grafana-postgresql-datasource",
      "influxdb"
    ]);
    const props = __props;
    const tokenLocal = ref("");
    const usernameLocal = ref("");
    const passwordLocal = ref("");
    const fieldErrors = ref({});
    const directDbCandidates = ref([]);
    const listLoaded = ref(false);
    const credentialConfigured = ref(false);
    const additionalOpen = ref(false);
    const legacyIdMigrated = ref(false);
    const dsUid = computed(() => String(props.options?.uid || "zabbix"));
    const configMigration = computed(
      () => migrateZabbixConfig(
        {
          ...DEFAULT_ZABBIX_OPTIONS,
          ...props.options.jsonData ?? {}
        },
        (numericId) => directDbCandidates.value.find((s) => s.id === numericId)?.uid
      )
    );
    const jsonData = computed(() => configMigration.value.options);
    function emitValidation() {
      const urlValue = String(props.options?.url || "").trim();
      let isValid = Boolean(urlValue) && !configMigration.value.error;
      let message = configMigration.value.error?.message;
      if (!urlValue) {
        isValid = false;
        message = "请填写 Zabbix URL";
      }
      if (jsonData.value.dbConnectionEnable) {
        const uid = String(jsonData.value.dbConnectionDatasourceUID || "").trim();
        if (!uid) {
          isValid = false;
          message = "Direct DB 已启用，请选择数据源 UID";
        } else {
          const found = directDbCandidates.value.find((s) => s.uid === uid);
          if (!found) {
            if (directDbCandidates.value.length > 0 || listLoaded.value) {
              isValid = false;
              message = `找不到 Direct DB 数据源 ${uid}`;
            }
          } else if (!DIRECT_DB_TYPES.has(found.type)) {
            isValid = false;
            message = `数据源类型 ${found.type} 不支持作为 Direct DB`;
          }
        }
      }
      for (const err of Object.values(fieldErrors.value)) {
        if (err) {
          isValid = false;
          message = err;
          break;
        }
      }
      props.onValidationChange?.({ isValid, message });
    }
    function patchJson(patch, url2) {
      const options = props.options;
      const next = {
        ...options,
        ...url2 != null ? { url: url2 } : {},
        jsonData: { ...jsonData.value, ...patch }
      };
      props.onOptionsChange(next);
    }
    async function refreshCredentialStatus() {
      const cred = await getRuntimeCredential(dsUid.value);
      credentialConfigured.value = Boolean(
        cred && (cred.value || cred.username || cred.password || cred.headers && Object.keys(cred.headers).length)
      );
    }
    function setToken(value) {
      tokenLocal.value = value;
      setRuntimeCredential(dsUid.value, value ? { kind: "apiKey", value } : null);
      void refreshCredentialStatus();
    }
    function setBasic(username, password) {
      usernameLocal.value = username;
      passwordLocal.value = password;
      setRuntimeCredential(
        dsUid.value,
        username || password ? { kind: "basic", username, password } : null
      );
      void refreshCredentialStatus();
    }
    function clearCredentials() {
      tokenLocal.value = "";
      usernameLocal.value = "";
      passwordLocal.value = "";
      setRuntimeCredential(dsUid.value, null);
      credentialConfigured.value = false;
    }
    const url = computed({
      get: () => String(props.options?.url || ""),
      set: (v) => patchJson({}, v)
    });
    const authType = computed({
      get: () => jsonData.value.authType === "userLogin" ? "userLogin" : "token",
      set: (v) => {
        const next = v === "userLogin" ? "userLogin" : "token";
        tokenLocal.value = "";
        usernameLocal.value = "";
        passwordLocal.value = "";
        setRuntimeCredential(dsUid.value, null);
        credentialConfigured.value = false;
        patchJson({ authType: next });
      }
    });
    const trends = computed({
      get: () => Boolean(jsonData.value.trends),
      set: (v) => patchJson({ trends: v })
    });
    const trendsFrom = computed({
      get: () => String(jsonData.value.trendsFrom || "7d"),
      set: (v) => patchJson({ trendsFrom: v })
    });
    const trendsRange = computed({
      get: () => String(jsonData.value.trendsRange || "4d"),
      set: (v) => patchJson({ trendsRange: v })
    });
    const cacheTTL = computed({
      get: () => String(jsonData.value.cacheTTL || "1h"),
      set: (v) => {
        const s = String(v || "").trim();
        if (!s || !isValidDurationString(s)) {
          fieldErrors.value = {
            ...fieldErrors.value,
            cacheTTL: "缓存 TTL 必须是合法 duration，例如 1h / 5m / 30s"
          };
        } else {
          const { cacheTTL: _drop, ...rest } = fieldErrors.value;
          fieldErrors.value = rest;
        }
        patchJson({ cacheTTL: s });
      }
    });
    const timeoutSeconds = computed({
      get: () => Math.max(1, Math.round(Number(jsonData.value.timeout || 3e4) / 1e3)),
      set: (v) => {
        const sec = Number(v);
        if (!Number.isFinite(sec) || sec <= 0 || !Number.isInteger(sec)) {
          fieldErrors.value = {
            ...fieldErrors.value,
            timeout: "超时必须为正整数（秒）"
          };
          return;
        }
        const { timeout: _t, ...rest } = fieldErrors.value;
        fieldErrors.value = rest;
        patchJson({ timeout: Math.round(sec) * 1e3 });
      }
    });
    const queryTimeoutSeconds = computed({
      get: () => Math.max(
        1,
        Math.round(Number(jsonData.value.queryTimeout || 6e4) / 1e3)
      ),
      set: (v) => {
        const sec = Number(v);
        if (!Number.isFinite(sec) || sec <= 0 || !Number.isInteger(sec)) {
          fieldErrors.value = {
            ...fieldErrors.value,
            queryTimeout: "查询超时必须为正整数（秒）"
          };
          return;
        }
        const { queryTimeout: _q, ...rest } = fieldErrors.value;
        fieldErrors.value = rest;
        patchJson({ queryTimeout: Math.round(sec) * 1e3 });
      }
    });
    const dbConnectionEnable = computed({
      get: () => Boolean(jsonData.value.dbConnectionEnable),
      set: (v) => patchJson({ dbConnectionEnable: v })
    });
    function setDbUid(uid) {
      const candidate = directDbCandidates.value.find((s) => s.uid === uid);
      patchJson({
        dbConnectionDatasourceUID: uid || void 0,
        dbConnectionDatasourceName: candidate?.name
      });
    }
    const dbConnectionDatasourceUID = computed({
      get: () => String(jsonData.value.dbConnectionDatasourceUID || ""),
      set: (v) => setDbUid(v)
    });
    const selectedDbType = computed(() => {
      const uid = String(jsonData.value.dbConnectionDatasourceUID || "");
      return directDbCandidates.value.find((s) => s.uid === uid)?.type || "";
    });
    const showRetentionPolicy = computed(
      () => Boolean(jsonData.value.dbConnectionEnable) && selectedDbType.value === "influxdb"
    );
    const retentionPolicy = computed({
      get: () => String(jsonData.value.dbConnectionRetentionPolicy || ""),
      set: (v) => patchJson({ dbConnectionRetentionPolicy: v })
    });
    const disableReadOnlyUsersAck = computed({
      get: () => Boolean(jsonData.value.disableReadOnlyUsersAck),
      set: (v) => patchJson({ disableReadOnlyUsersAck: v })
    });
    const disableDataAlignment = computed({
      get: () => Boolean(jsonData.value.disableDataAlignment),
      set: (v) => patchJson({ disableDataAlignment: v })
    });
    const authPlacement = computed({
      get: () => jsonData.value.authPlacement || "auto",
      set: (v) => patchJson({ authPlacement: v })
    });
    const historyPageLimit2 = computed({
      get: () => Number(jsonData.value.historyPageLimit ?? 1e4),
      set: (v) => patchJson({ historyPageLimit: Math.max(1, Number(v) || 1e4) })
    });
    const historyBatchSize2 = computed({
      get: () => Number(jsonData.value.historyBatchSize ?? 100),
      set: (v) => patchJson({ historyBatchSize: Math.max(1, Number(v) || 100) })
    });
    const historyConcurrency = computed({
      get: () => Number(jsonData.value.historyConcurrency ?? 4),
      set: (v) => patchJson({ historyConcurrency: Math.max(1, Number(v) || 4) })
    });
    const metadataPageLimit = computed({
      get: () => Number(jsonData.value.metadataPageLimit ?? 1e3),
      set: (v) => patchJson({ metadataPageLimit: Math.max(1, Number(v) || 1e3) })
    });
    const enableWrites = computed({
      get: () => Boolean(jsonData.value.enableWrites),
      set: (v) => patchJson({ enableWrites: v })
    });
    const dbOptions = computed(
      () => directDbCandidates.value.map((s) => ({
        label: `${s.name} (${s.type})`,
        value: s.uid
      }))
    );
    async function loadCandidates() {
      try {
        const list = await listDataSources();
        directDbCandidates.value = (list || []).filter(
          (s) => DIRECT_DB_TYPES.has(String(s.type || ""))
        );
      } catch {
        directDbCandidates.value = [];
      } finally {
        listLoaded.value = true;
        if (!legacyIdMigrated.value) {
          const raw = props.options?.jsonData ?? {};
          const hasLegacyId = Number(raw.dbConnectionDatasourceId) > 0 || raw.dbConnection && typeof raw.dbConnection === "object" && Number(raw.dbConnection.datasourceId) > 0;
          const migUid = configMigration.value.options.dbConnectionDatasourceUID;
          if (hasLegacyId && migUid) {
            const candidate = directDbCandidates.value.find(
              (s) => s.uid === migUid
            );
            patchJson({
              dbConnectionDatasourceUID: migUid,
              dbConnectionDatasourceName: candidate?.name ?? configMigration.value.options.dbConnectionDatasourceName
            });
          }
          legacyIdMigrated.value = true;
        }
        emitValidation();
      }
    }
    onMounted(async () => {
      await loadCandidates();
      await refreshCredentialStatus();
      emitValidation();
    });
    onUnmounted(() => {
      tokenLocal.value = "";
      usernameLocal.value = "";
      passwordLocal.value = "";
    });
    watch(
      () => [
        props.options,
        directDbCandidates.value,
        fieldErrors.value,
        listLoaded.value
      ],
      () => emitValidation(),
      { deep: true }
    );
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$t, [
        createVNode(unref(_sfc_main$1c), {
          layout: "vertical",
          "test-id": "zabbix-config-form"
        }, {
          default: withCtx(() => [
            createElementVNode("section", _hoisted_2$o, [
              _cache[26] || (_cache[26] = createElementVNode(
                "h4",
                { id: "zbx-conn" },
                "Zabbix 连接",
                -1
                /* CACHED */
              )),
              createVNode(unref(GInlineField), {
                label: "URL",
                required: true,
                grow: ""
              }, {
                default: withCtx(() => [
                  createVNode(unref(GInput), {
                    id: "zabbix-url",
                    modelValue: url.value,
                    "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => url.value = $event),
                    placeholder: "https://zabbix.example/api_jsonrpc.php",
                    "test-id": "zabbix-url"
                  }, null, 8, ["modelValue"])
                ]),
                _: 1
                /* STABLE */
              }),
              createVNode(unref(GInlineField), {
                label: "认证方式",
                grow: ""
              }, {
                default: withCtx(() => [
                  createVNode(unref(GSelect), {
                    id: "zabbix-auth-type",
                    value: authType.value,
                    options: [
                      { label: "API Token", value: "token" },
                      { label: "用户名/密码", value: "userLogin" }
                    ],
                    "test-id": "zabbix-auth-type",
                    "onUpdate:value": _cache[1] || (_cache[1] = ($event) => authType.value = $event === "userLogin" ? "userLogin" : "token")
                  }, null, 8, ["value"])
                ]),
                _: 1
                /* STABLE */
              }),
              authType.value === "token" ? (openBlock(), createBlock(unref(GInlineField), {
                key: 0,
                label: "API Token",
                grow: ""
              }, {
                default: withCtx(() => [
                  createElementVNode("div", _hoisted_3$k, [
                    createVNode(unref(GInput), {
                      id: "zabbix-token",
                      "model-value": tokenLocal.value,
                      type: "password",
                      autocomplete: "off",
                      "test-id": "zabbix-token",
                      "onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => setToken(String($event)))
                    }, null, 8, ["model-value"]),
                    createVNode(unref(_sfc_main$18), { title: "凭据仅保存在运行时内存，不会写入 jsonData、URL 或日志" }, {
                      default: withCtx(() => [
                        createElementVNode("span", _hoisted_4$f, [
                          createVNode(unref(GIcon), {
                            name: "info",
                            size: 14
                          })
                        ])
                      ]),
                      _: 1
                      /* STABLE */
                    })
                  ])
                ]),
                _: 1
                /* STABLE */
              })) : (openBlock(), createElementBlock(
                Fragment,
                { key: 1 },
                [
                  createVNode(unref(GInlineField), {
                    label: "用户名",
                    grow: ""
                  }, {
                    default: withCtx(() => [
                      createVNode(unref(GInput), {
                        id: "zabbix-username",
                        "model-value": usernameLocal.value,
                        "test-id": "zabbix-username",
                        autocomplete: "off",
                        "onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => setBasic(String($event), passwordLocal.value))
                      }, null, 8, ["model-value"])
                    ]),
                    _: 1
                    /* STABLE */
                  }),
                  createVNode(unref(GInlineField), {
                    label: "密码",
                    grow: ""
                  }, {
                    default: withCtx(() => [
                      createVNode(unref(GInput), {
                        id: "zabbix-password",
                        "model-value": passwordLocal.value,
                        type: "password",
                        autocomplete: "off",
                        "test-id": "zabbix-password",
                        "onUpdate:modelValue": _cache[4] || (_cache[4] = ($event) => setBasic(usernameLocal.value, String($event)))
                      }, null, 8, ["model-value"])
                    ]),
                    _: 1
                    /* STABLE */
                  })
                ],
                64
                /* STABLE_FRAGMENT */
              )),
              createElementVNode("div", _hoisted_5$d, [
                credentialConfigured.value ? (openBlock(), createElementBlock("span", _hoisted_6$b, "已配置凭据")) : (openBlock(), createElementBlock("span", _hoisted_7$9, "未配置凭据")),
                credentialConfigured.value || tokenLocal.value || usernameLocal.value || passwordLocal.value ? (openBlock(), createBlock(unref(GButton), {
                  key: 2,
                  variant: "secondary",
                  size: "sm",
                  "test-id": "zabbix-clear-credentials",
                  onClick: clearCredentials
                }, {
                  default: withCtx(() => [..._cache[25] || (_cache[25] = [
                    createTextVNode(
                      " 清除凭据 ",
                      -1
                      /* CACHED */
                    )
                  ])]),
                  _: 1
                  /* STABLE */
                })) : createCommentVNode("v-if", true)
              ])
            ]),
            createElementVNode("section", _hoisted_8$5, [
              createElementVNode("button", {
                type: "button",
                class: "adv-toggle",
                "data-testid": "zabbix-additional-toggle",
                "aria-expanded": additionalOpen.value,
                onClick: _cache[5] || (_cache[5] = ($event) => additionalOpen.value = !additionalOpen.value),
                onKeydown: [
                  _cache[6] || (_cache[6] = withKeys(withModifiers(($event) => additionalOpen.value = !additionalOpen.value, ["prevent"]), ["enter"])),
                  _cache[7] || (_cache[7] = withKeys(withModifiers(($event) => additionalOpen.value = !additionalOpen.value, ["prevent"]), ["space"]))
                ]
              }, [
                createVNode(unref(GIcon), {
                  name: additionalOpen.value ? "angle-right" : "angle-right",
                  size: 14,
                  class: normalizeClass([{ "is-open": additionalOpen.value }, "chevron"])
                }, null, 8, ["name", "class"]),
                _cache[27] || (_cache[27] = createElementVNode(
                  "h4",
                  { id: "zbx-extra" },
                  "附加设置",
                  -1
                  /* CACHED */
                ))
              ], 40, _hoisted_9$4),
              additionalOpen.value ? (openBlock(), createElementBlock("div", _hoisted_10$3, [
                _cache[34] || (_cache[34] = createElementVNode(
                  "h5",
                  null,
                  "Zabbix API / 查询 / 趋势",
                  -1
                  /* CACHED */
                )),
                createElementVNode("label", _hoisted_11$3, [
                  createVNode(unref(_sfc_main$19), {
                    checked: trends.value,
                    "test-id": "zabbix-trends",
                    "onUpdate:checked": _cache[8] || (_cache[8] = ($event) => trends.value = $event)
                  }, null, 8, ["checked"]),
                  _cache[28] || (_cache[28] = createTextVNode(
                    " 启用趋势 ",
                    -1
                    /* CACHED */
                  ))
                ]),
                trends.value ? (openBlock(), createElementBlock(
                  Fragment,
                  { key: 0 },
                  [
                    createVNode(unref(GInlineField), {
                      label: "趋势起始",
                      grow: ""
                    }, {
                      default: withCtx(() => [
                        createVNode(unref(GInput), {
                          id: "zabbix-trends-from",
                          modelValue: trendsFrom.value,
                          "onUpdate:modelValue": _cache[9] || (_cache[9] = ($event) => trendsFrom.value = $event),
                          "test-id": "zabbix-trends-from"
                        }, null, 8, ["modelValue"])
                      ]),
                      _: 1
                      /* STABLE */
                    }),
                    createVNode(unref(GInlineField), {
                      label: "趋势范围",
                      grow: ""
                    }, {
                      default: withCtx(() => [
                        createVNode(unref(GInput), {
                          id: "zabbix-trends-range",
                          modelValue: trendsRange.value,
                          "onUpdate:modelValue": _cache[10] || (_cache[10] = ($event) => trendsRange.value = $event),
                          "test-id": "zabbix-trends-range"
                        }, null, 8, ["modelValue"])
                      ]),
                      _: 1
                      /* STABLE */
                    })
                  ],
                  64
                  /* STABLE_FRAGMENT */
                )) : createCommentVNode("v-if", true),
                createVNode(unref(GInlineField), {
                  label: "缓存 TTL",
                  grow: ""
                }, {
                  default: withCtx(() => [
                    createVNode(unref(GInput), {
                      id: "zabbix-cache-ttl",
                      modelValue: cacheTTL.value,
                      "onUpdate:modelValue": _cache[11] || (_cache[11] = ($event) => cacheTTL.value = $event),
                      "test-id": "zabbix-cache-ttl"
                    }, null, 8, ["modelValue"])
                  ]),
                  _: 1
                  /* STABLE */
                }),
                fieldErrors.value.cacheTTL ? (openBlock(), createElementBlock(
                  "p",
                  _hoisted_12$3,
                  toDisplayString(fieldErrors.value.cacheTTL),
                  1
                  /* TEXT */
                )) : createCommentVNode("v-if", true),
                createVNode(unref(GInlineField), {
                  label: "连接超时（秒）",
                  grow: "",
                  tooltip: "jsonData.timeout，内部以毫秒存储"
                }, {
                  default: withCtx(() => [
                    createVNode(unref(GInput), {
                      id: "zabbix-timeout",
                      "model-value": timeoutSeconds.value,
                      type: "number",
                      "test-id": "zabbix-timeout",
                      "aria-invalid": Boolean(fieldErrors.value.timeout) || void 0,
                      "onUpdate:modelValue": _cache[12] || (_cache[12] = ($event) => timeoutSeconds.value = Number($event))
                    }, null, 8, ["model-value", "aria-invalid"])
                  ]),
                  _: 1
                  /* STABLE */
                }),
                fieldErrors.value.timeout ? (openBlock(), createElementBlock(
                  "p",
                  _hoisted_13$3,
                  toDisplayString(fieldErrors.value.timeout),
                  1
                  /* TEXT */
                )) : createCommentVNode("v-if", true),
                createVNode(unref(GInlineField), {
                  label: "查询超时（秒）",
                  grow: "",
                  tooltip: "jsonData.queryTimeout，内部以毫秒存储"
                }, {
                  default: withCtx(() => [
                    createVNode(unref(GInput), {
                      id: "zabbix-query-timeout",
                      "model-value": queryTimeoutSeconds.value,
                      type: "number",
                      "test-id": "zabbix-query-timeout",
                      "aria-invalid": Boolean(fieldErrors.value.queryTimeout) || void 0,
                      "onUpdate:modelValue": _cache[13] || (_cache[13] = ($event) => queryTimeoutSeconds.value = Number($event))
                    }, null, 8, ["model-value", "aria-invalid"])
                  ]),
                  _: 1
                  /* STABLE */
                }),
                fieldErrors.value.queryTimeout ? (openBlock(), createElementBlock(
                  "p",
                  _hoisted_14$3,
                  toDisplayString(fieldErrors.value.queryTimeout),
                  1
                  /* TEXT */
                )) : createCommentVNode("v-if", true),
                _cache[35] || (_cache[35] = createElementVNode(
                  "h5",
                  null,
                  "Direct DB",
                  -1
                  /* CACHED */
                )),
                createElementVNode("label", _hoisted_15$3, [
                  createVNode(unref(_sfc_main$19), {
                    checked: dbConnectionEnable.value,
                    "test-id": "zabbix-direct-db",
                    "onUpdate:checked": _cache[14] || (_cache[14] = ($event) => dbConnectionEnable.value = $event)
                  }, null, 8, ["checked"]),
                  _cache[29] || (_cache[29] = createTextVNode(
                    " 启用 Direct DB ",
                    -1
                    /* CACHED */
                  ))
                ]),
                dbConnectionEnable.value ? (openBlock(), createElementBlock(
                  Fragment,
                  { key: 4 },
                  [
                    createVNode(unref(GInlineField), {
                      label: "数据库数据源",
                      grow: ""
                    }, {
                      default: withCtx(() => [
                        createVNode(unref(GSelect), {
                          id: "zabbix-db-uid",
                          value: dbConnectionDatasourceUID.value,
                          options: dbOptions.value,
                          "allow-clear": "",
                          placeholder: "选择 PostgreSQL / MySQL / InfluxDB",
                          "test-id": "zabbix-db-uid",
                          "onUpdate:value": _cache[15] || (_cache[15] = ($event) => dbConnectionDatasourceUID.value = String($event || ""))
                        }, null, 8, ["value", "options"])
                      ]),
                      _: 1
                      /* STABLE */
                    }),
                    createElementVNode("ul", _hoisted_16$2, [
                      (openBlock(true), createElementBlock(
                        Fragment,
                        null,
                        renderList(directDbCandidates.value, (c) => {
                          return openBlock(), createElementBlock("li", {
                            key: c.uid,
                            "data-uid": c.uid,
                            "data-type": c.type
                          }, toDisplayString(c.name), 9, _hoisted_17$2);
                        }),
                        128
                        /* KEYED_FRAGMENT */
                      ))
                    ]),
                    showRetentionPolicy.value ? (openBlock(), createBlock(unref(GInlineField), {
                      key: 0,
                      label: "Retention Policy",
                      grow: ""
                    }, {
                      default: withCtx(() => [
                        createVNode(unref(GInput), {
                          id: "zabbix-retention-policy",
                          modelValue: retentionPolicy.value,
                          "onUpdate:modelValue": _cache[16] || (_cache[16] = ($event) => retentionPolicy.value = $event),
                          "test-id": "zabbix-retention-policy"
                        }, null, 8, ["modelValue"])
                      ]),
                      _: 1
                      /* STABLE */
                    })) : createCommentVNode("v-if", true),
                    configMigration.value.error ? (openBlock(), createElementBlock(
                      "p",
                      _hoisted_18$2,
                      toDisplayString(configMigration.value.error.message),
                      1
                      /* TEXT */
                    )) : createCommentVNode("v-if", true)
                  ],
                  64
                  /* STABLE_FRAGMENT */
                )) : createCommentVNode("v-if", true),
                _cache[36] || (_cache[36] = createElementVNode(
                  "h5",
                  null,
                  "权限与写操作",
                  -1
                  /* CACHED */
                )),
                createElementVNode("label", _hoisted_19$2, [
                  createVNode(unref(_sfc_main$19), {
                    checked: disableReadOnlyUsersAck.value,
                    "test-id": "zabbix-disable-readonly-ack",
                    "onUpdate:checked": _cache[17] || (_cache[17] = ($event) => disableReadOnlyUsersAck.value = $event)
                  }, null, 8, ["checked"]),
                  _cache[30] || (_cache[30] = createTextVNode(
                    " 禁止只读用户确认问题 ",
                    -1
                    /* CACHED */
                  ))
                ]),
                createElementVNode("label", _hoisted_20$2, [
                  createVNode(unref(_sfc_main$19), {
                    checked: disableDataAlignment.value,
                    "test-id": "zabbix-disable-alignment",
                    "onUpdate:checked": _cache[18] || (_cache[18] = ($event) => disableDataAlignment.value = $event)
                  }, null, 8, ["checked"]),
                  _cache[31] || (_cache[31] = createTextVNode(
                    " 禁用数据对齐 ",
                    -1
                    /* CACHED */
                  ))
                ]),
                createElementVNode("label", _hoisted_21$1, [
                  createVNode(unref(_sfc_main$19), {
                    checked: enableWrites.value,
                    "test-id": "zabbix-enable-writes",
                    "onUpdate:checked": _cache[19] || (_cache[19] = ($event) => enableWrites.value = $event)
                  }, null, 8, ["checked"]),
                  _cache[32] || (_cache[32] = createTextVNode(
                    " 启用写操作（确认/关闭/脚本） ",
                    -1
                    /* CACHED */
                  ))
                ]),
                enableWrites.value ? (openBlock(), createElementBlock("div", _hoisted_22$1, [
                  createVNode(unref(GAlert), {
                    severity: "warning",
                    title: "写操作风险"
                  }, {
                    default: withCtx(() => [..._cache[33] || (_cache[33] = [
                      createTextVNode(
                        " 写操作需服务端另配 ZABBIX_LIVE_WRITES=1，且账号具备对应权限。请谨慎开启。 ",
                        -1
                        /* CACHED */
                      )
                    ])]),
                    _: 1
                    /* STABLE */
                  })
                ])) : createCommentVNode("v-if", true),
                _cache[37] || (_cache[37] = createElementVNode(
                  "h5",
                  null,
                  "高级 RPC 调优",
                  -1
                  /* CACHED */
                )),
                createVNode(unref(GInlineField), {
                  label: "认证位置",
                  grow: ""
                }, {
                  default: withCtx(() => [
                    createVNode(unref(GSelect), {
                      id: "zabbix-auth-placement",
                      value: authPlacement.value,
                      options: [
                        { label: "自动探测", value: "auto" },
                        { label: "请求体", value: "body" },
                        { label: "请求头", value: "header" }
                      ],
                      "test-id": "zabbix-auth-placement",
                      "onUpdate:value": _cache[20] || (_cache[20] = ($event) => authPlacement.value = $event)
                    }, null, 8, ["value"])
                  ]),
                  _: 1
                  /* STABLE */
                }),
                createVNode(unref(GInlineField), {
                  label: "历史分页大小",
                  grow: "",
                  tooltip: "jsonData.historyPageLimit"
                }, {
                  default: withCtx(() => [
                    createVNode(unref(GInput), {
                      id: "zabbix-history-page-limit",
                      modelValue: historyPageLimit2.value,
                      "onUpdate:modelValue": _cache[21] || (_cache[21] = ($event) => historyPageLimit2.value = $event),
                      type: "number",
                      "test-id": "zabbix-history-page-limit"
                    }, null, 8, ["modelValue"])
                  ]),
                  _: 1
                  /* STABLE */
                }),
                createVNode(unref(GInlineField), {
                  label: "历史批大小",
                  grow: "",
                  tooltip: "jsonData.historyBatchSize"
                }, {
                  default: withCtx(() => [
                    createVNode(unref(GInput), {
                      id: "zabbix-history-batch-size",
                      modelValue: historyBatchSize2.value,
                      "onUpdate:modelValue": _cache[22] || (_cache[22] = ($event) => historyBatchSize2.value = $event),
                      type: "number",
                      "test-id": "zabbix-history-batch-size"
                    }, null, 8, ["modelValue"])
                  ]),
                  _: 1
                  /* STABLE */
                }),
                createVNode(unref(GInlineField), {
                  label: "历史并发数",
                  grow: "",
                  tooltip: "jsonData.historyConcurrency"
                }, {
                  default: withCtx(() => [
                    createVNode(unref(GInput), {
                      id: "zabbix-history-concurrency",
                      modelValue: historyConcurrency.value,
                      "onUpdate:modelValue": _cache[23] || (_cache[23] = ($event) => historyConcurrency.value = $event),
                      type: "number",
                      "test-id": "zabbix-history-concurrency"
                    }, null, 8, ["modelValue"])
                  ]),
                  _: 1
                  /* STABLE */
                }),
                createVNode(unref(GInlineField), {
                  label: "元数据分页大小",
                  grow: "",
                  tooltip: "jsonData.metadataPageLimit"
                }, {
                  default: withCtx(() => [
                    createVNode(unref(GInput), {
                      id: "zabbix-metadata-page-limit",
                      modelValue: metadataPageLimit.value,
                      "onUpdate:modelValue": _cache[24] || (_cache[24] = ($event) => metadataPageLimit.value = $event),
                      type: "number",
                      "test-id": "zabbix-metadata-page-limit"
                    }, null, 8, ["modelValue"])
                  ]),
                  _: 1
                  /* STABLE */
                })
              ])) : createCommentVNode("v-if", true)
            ])
          ]),
          _: 1
          /* STABLE */
        })
      ]);
    };
  }
});
const ConfigEditor$1 = /* @__PURE__ */ _export_sfc(_sfc_main$u, [["__scopeId", "data-v-43b4b06f"]]);
function scopedValue(raw) {
  if (Array.isArray(raw)) return raw.map(String).join("|");
  if (raw && typeof raw === "object" && "value" in raw) {
    return scopedValue(raw.value);
  }
  return raw == null ? "" : String(raw);
}
function interpolateZabbixValue(value, vars) {
  return String(value || "").replace(
    /\$\{([A-Za-z_][\w]*)\}|\$([A-Za-z_][\w]*)|\[\[([A-Za-z_][\w]*)\]\]/g,
    (token, a, b, c) => {
      const name = a || b || c;
      return name in vars ? scopedValue(vars[name]) : token;
    }
  );
}
function isMatchAllZabbixFilter(filter2) {
  const source = String(filter2 || "").trim();
  if (!source || source === "*" || source === "$__all" || source === "/.*/" || source === "/^.*$/")
    return true;
  const m = source.match(/^\/(.*)\/([gimsuy]*)$/);
  if (!m) return false;
  const body = m[1];
  return body === ".*" || body === "^.*$" || body === ".+" || body === "";
}
function toApiSearchString(filter2) {
  const source = String(filter2 || "").trim();
  if (!source || isMatchAllZabbixFilter(source)) return void 0;
  if (/^\/.*\/[gimsuy]*$/.test(source)) return void 0;
  return source;
}
function zabbixFilterToApiSearch(filter2) {
  const source = String(filter2 || "").trim();
  if (!source || isMatchAllZabbixFilter(source)) return void 0;
  const plain = toApiSearchString(source);
  if (plain) return plain;
  const match = source.match(/^\/(.*)\/([gimsuy]*)$/);
  if (!match) return void 0;
  const body = match[1];
  const alts = body.split("|").map((part) => {
    let s = "";
    for (let i = 0; i < part.length; i++) {
      const ch = part[i];
      if (ch === "\\" && i + 1 < part.length) {
        s += part[i + 1];
        i += 1;
        continue;
      }
      if (/[A-Za-z0-9._:-]/.test(ch)) s += ch;
    }
    return s.trim();
  });
  const tokens = alts.filter((t) => t.length >= 2);
  if (!tokens.length) return void 0;
  tokens.sort((a, b) => b.length - a.length);
  return tokens[0];
}
function matchesZabbixFilter(value, filter2) {
  const source = String(filter2 || "").trim();
  if (isMatchAllZabbixFilter(source)) return true;
  const match = source.match(/^\/(.*)\/([gimsuy]*)$/);
  if (match) {
    try {
      return new RegExp(match[1], match[2].replace("g", "")).test(value);
    } catch {
      return false;
    }
  }
  return value.toLocaleLowerCase().includes(source.toLocaleLowerCase());
}
function interpolateFilter(filter2, vars) {
  return {
    filter: interpolateZabbixValue(String(filter2?.filter ?? ""), vars),
    ...filter2?.ids ? { ids: filter2.ids.map(String) } : {}
  };
}
const MAX_RESOLVED_HOSTS = 20;
const MAX_RESOLVED_ITEMS = 24;
const MAX_RESOLVED_GROUPS = 80;
function assertBoundedHostScope(_query, _vars) {
}
function rowsOf$1(page) {
  if (Array.isArray(page)) return page;
  return page?.rows ?? [];
}
async function resolveGroups(api, query, vars, signal) {
  const f = interpolateFilter(query.group, vars);
  if (f.ids?.length) return f.ids.map((id) => ({ groupid: id, name: id }));
  const hostF = interpolateFilter(query.host, vars);
  if (isMatchAllZabbixFilter(f.filter) && !isMatchAllZabbixFilter(hostF.filter)) {
    return [];
  }
  const page = await api.getGroups(f.filter, signal);
  let rows = rowsOf$1(page).filter(
    (r) => matchesZabbixFilter(String(r.name || ""), f.filter)
  );
  if (rows.length > MAX_RESOLVED_GROUPS) {
    rows = rows.slice(0, MAX_RESOLVED_GROUPS);
  }
  return rows;
}
async function resolveHosts(api, query, vars, groupids, signal) {
  const f = interpolateFilter(query.host, vars);
  if (f.ids?.length)
    return f.ids.map((id) => ({ hostid: id, name: id, host: id }));
  const hostTags = (query.hostTags || []).map((t) => ({
    ...t,
    tag: interpolateZabbixValue(t.tag, vars),
    value: interpolateZabbixValue(t.value, vars)
  }));
  const page = await api.getHosts(groupids, f.filter, hostTags, signal);
  let rows = rowsOf$1(page).filter(
    (r) => matchesZabbixFilter(String(r.name || r.host || ""), f.filter)
  );
  if (rows.length > MAX_RESOLVED_HOSTS) {
    rows = rows.slice(0, MAX_RESOLVED_HOSTS);
  }
  return rows;
}
async function resolveApplications(api, query, vars, hostids, signal) {
  const f = interpolateFilter(query.application, vars);
  if (f.ids?.length)
    return f.ids.map((id) => ({ applicationid: id, name: id }));
  if (!f.filter) return [];
  const page = await api.getApplications(hostids, f.filter, signal);
  return rowsOf$1(page).filter(
    (r) => matchesZabbixFilter(String(r.name || ""), f.filter)
  );
}
async function resolveItems(api, query, vars, hostids, applicationids, signal, groupids) {
  if (query.executionMode === "lld" || query.lldRuleId || query.lld?.ruleId) {
    const ruleId = String(query.lld?.ruleId || query.lldRuleId || "");
    const keys = (query.lld?.prototypeKeys || query.lldItemKeys || []).map(
      (k) => interpolateZabbixValue(k, vars)
    );
    const prototypeIds = (query.lld?.prototypeIds || []).map(String);
    return api.getDiscoveredItems(hostids, ruleId, keys, signal, {
      prototypeIds
    });
  }
  const itemFilter = interpolateFilter(query.item, vars);
  const itemTag = interpolateZabbixValue(
    String(query.itemTag?.filter ?? ""),
    vars
  );
  if (itemFilter.ids?.length) {
    return api.getItemsByIds(itemFilter.ids, signal);
  }
  const page = await api.getItems(
    {
      hostids,
      applicationids,
      filter: itemFilter.filter,
      itemTag,
      showDisabled: Boolean(query.options?.showDisabledItems),
      ...groupids?.length && !hostids.length ? { groupids } : {}
    },
    signal
  );
  let rows = rowsOf$1(page).filter(
    (r) => matchesZabbixFilter(String(r.name || ""), itemFilter.filter) || matchesZabbixFilter(String(r.key_ || ""), itemFilter.filter)
  );
  rows.sort(
    (a, b) => Number(b.lastclock || 0) - Number(a.lastclock || 0)
  );
  if (rows.length > MAX_RESOLVED_ITEMS) {
    rows = rows.slice(0, MAX_RESOLVED_ITEMS);
  }
  return rows;
}
function isSecretMacro(row) {
  const t = String(row.type ?? "0");
  if (t === "1" || t === "2") return true;
  if ((row.value == null || row.value === "") && String(row.macro || "").includes("SECRET"))
    return true;
  return false;
}
function maskMacroValue(row) {
  if (isSecretMacro(row)) {
    return { value: "******", masked: true, secret: true };
  }
  return { value: String(row.value ?? ""), masked: false, secret: false };
}
async function executeMacrosQuery(ctx) {
  assertBoundedHostScope(ctx.query, ctx.scopedVars);
  const hostF = interpolateFilter(ctx.query.host, ctx.scopedVars);
  const groupF = interpolateFilter(ctx.query.group, ctx.scopedVars);
  const groupAll = isMatchAllZabbixFilter(groupF.filter) && !groupF.ids?.length;
  const hostAll = isMatchAllZabbixFilter(hostF.filter) && !hostF.ids?.length;
  const groups = groupAll ? [] : await resolveGroups(ctx.api, ctx.query, ctx.scopedVars, ctx.signal);
  let hosts = [];
  if (!hostAll) {
    hosts = await resolveHosts(
      ctx.api,
      ctx.query,
      ctx.scopedVars,
      groups.map((g) => String(g.groupid)),
      ctx.signal
    );
  }
  const macroFilter = interpolateFilter(ctx.query.macro, ctx.scopedVars);
  const page = await ctx.api.getMacros(
    hosts.map((h) => String(h.hostid)),
    macroFilter.filter,
    ctx.signal
  );
  const rows = Array.isArray(page) ? page : page.rows || [];
  const hostMap = new Map(hosts.map((h) => [String(h.hostid), h]));
  rows.map((r) => {
    const m = maskMacroValue(r);
    return { macro: r.macro, type: r.type, masked: m.masked };
  });
  return [
    createDataFrame({
      refId: ctx.query.refId,
      fields: [
        {
          name: "Host",
          type: "string",
          values: rows.map(
            (r) => String(
              hostMap.get(String(r.hostid))?.name || r.hostid || (r.hostid ? "" : "Global")
            )
          )
        },
        {
          name: "HostId",
          type: "string",
          values: rows.map((r) => String(r.hostid ?? ""))
        },
        {
          name: "MacroId",
          type: "string",
          values: rows.map(
            (r) => String(r.hostmacroid || r.globalmacroid || r.macroid || "")
          )
        },
        {
          name: "Macro",
          type: "string",
          values: rows.map((r) => String(r.macro ?? ""))
        },
        {
          name: "Value",
          type: "string",
          values: rows.map((r) => maskMacroValue(r).value)
        },
        {
          name: "Type",
          type: "string",
          values: rows.map((r) => String(r.type ?? "0"))
        },
        {
          name: "Description",
          type: "string",
          values: rows.map((r) => String(r.description ?? ""))
        },
        {
          name: "Masked",
          type: "boolean",
          values: rows.map((r) => maskMacroValue(r).masked)
        },
        {
          name: "Scope",
          type: "string",
          values: rows.map(
            (r) => r.globalmacroid || !r.hostid && r.hostmacroid == null ? "global" : "host"
          )
        }
      ]
    })
  ];
}
function parseZabbixVariableQuery(query) {
  const t = String(query || "").trim();
  if (/^hostgroup(\.get)?$/i.test(t)) return { queryType: "group" };
  if (/^host(\.get)?$/i.test(t) && !/^hostgroup/i.test(t))
    return { queryType: "host" };
  if (/^item(\.get)?$/i.test(t)) return { queryType: "item" };
  if (/^application(\.get)?$/i.test(t)) return { queryType: "application" };
  if (/^proxy(\.get)?$/i.test(t)) return { queryType: "proxy" };
  if (/^service(\.get)?$/i.test(t)) return { queryType: "service" };
  if (/^sla(\.get)?$/i.test(t)) return { queryType: "sla" };
  if (/^trigger(\.get)?$/i.test(t)) return { queryType: "trigger" };
  if (/^usermacro(\.get)?$/i.test(t) || /^macro$/i.test(t))
    return { queryType: "macro" };
  if (t.startsWith("{") && t.endsWith("}")) {
    try {
      return JSON.parse(t);
    } catch {
    }
  }
  const [kind, ...rest] = t.split(":");
  if (kind === "group") return { queryType: "group", filter: rest.join(":") };
  if (kind === "host")
    return {
      queryType: "host",
      group: rest[0],
      filter: rest.slice(1).join(":")
    };
  if (kind === "application")
    return {
      queryType: "application",
      group: rest[0],
      host: rest[1],
      filter: rest.slice(2).join(":")
    };
  if (kind === "item")
    return {
      queryType: "item",
      group: rest[0],
      host: rest[1],
      filter: rest.slice(2).join(":")
    };
  if (kind === "itemTag")
    return { queryType: "itemTag", filter: rest.join(":") };
  if (kind === "macro") return { queryType: "macro", filter: rest.join(":") };
  if (kind === "proxy") return { queryType: "proxy", filter: rest.join(":") };
  if (kind === "service")
    return { queryType: "service", filter: rest.join(":") };
  if (kind === "sla") return { queryType: "sla", filter: rest.join(":") };
  if (kind === "trigger")
    return { queryType: "trigger", filter: rest.join(":") };
  if (kind === "itemValues")
    return {
      queryType: "itemValues",
      item: rest[0],
      filter: rest.slice(1).join(":")
    };
  if (kind === "lldRule" || kind === "discoveryRule")
    return {
      queryType: "lldRule",
      host: rest[0],
      filter: rest.slice(1).join(":")
    };
  if (kind === "itemPrototype" || kind === "prototype")
    return {
      queryType: "itemPrototype",
      item: rest[0],
      filter: rest.slice(1).join(":")
    };
  return { queryType: "group", filter: t };
}
function splitTemplateQuery(query) {
  const t = String(query || "").trim();
  if (!t) return [];
  const braced = t.match(/\{[^}]*\}/g);
  if (braced?.length) return braced.map((s) => s.slice(1, -1));
  if (t.includes(".") && !t.includes(":") && !t.startsWith("/")) {
    return t.split(".");
  }
  return [t];
}
function parseLegacyVariableQuery(query) {
  const raw = String(query || "").trim();
  if (!raw) return { queryType: "group", filter: "" };
  if (raw.startsWith("{") && raw.endsWith("}") && raw.includes("queryType")) {
    try {
      return JSON.parse(raw);
    } catch {
    }
  }
  const isBrace = /\{[^}]+\}/.test(raw);
  const isDotted = !isBrace && raw.includes(".") && !raw.includes(":") && !/^hostgroup|^host\.|^item/i.test(raw);
  if (!isBrace && !isDotted) {
    return parseZabbixVariableQuery(raw);
  }
  const parts = splitTemplateQuery(raw).map((p) => p === "*" ? "/.*/" : p);
  if (parts.length >= 4) {
    return {
      queryType: "item",
      group: parts[0] || "/.*/",
      host: parts[1] || "/.*/",
      application: parts[2] || "/.*/",
      filter: parts[3] || "/.*/",
      legacy: true,
      legacyRaw: raw
    };
  }
  if (parts.length === 3) {
    return {
      queryType: "application",
      group: parts[0] || "/.*/",
      host: parts[1] || "/.*/",
      filter: parts[2] || "/.*/",
      legacy: true,
      legacyRaw: raw
    };
  }
  if (parts.length === 2) {
    return {
      queryType: "host",
      group: parts[0] || "/.*/",
      filter: parts[1] || "/.*/",
      legacy: true,
      legacyRaw: raw
    };
  }
  return {
    queryType: "group",
    filter: parts[0] || "/.*/",
    legacy: true,
    legacyRaw: raw
  };
}
function rowsOf(page) {
  if (Array.isArray(page)) return page;
  return page?.rows || [];
}
async function executeZabbixVariableQuery(api, query, scopedVars = {}, signal) {
  const classicMethod = typeof query === "string" && /\.get$/i.test(String(query).trim());
  const q = typeof query === "string" ? parseZabbixVariableQuery(query) : query;
  const preferId = classicMethod || Boolean(q.preferId);
  const base = { ...DEFAULT_ZABBIX_QUERY };
  const filter2 = interpolateZabbixValue(q.filter || "", scopedVars);
  if (q.queryType === "group") {
    base.group = { filter: filter2 };
    const rows = await resolveGroups(api, base, scopedVars, signal);
    return rows.map((r) => ({
      text: r.name,
      value: preferId ? String(r.groupid ?? r.name) : String(r.name),
      id: r.groupid
    }));
  }
  if (q.queryType === "host") {
    base.group = { filter: interpolateZabbixValue(q.group || "", scopedVars) };
    base.host = { filter: filter2 };
    const groups = await resolveGroups(api, base, scopedVars, signal);
    const hosts = await resolveHosts(
      api,
      base,
      scopedVars,
      groups.map((g) => g.groupid),
      signal
    );
    return hosts.map((h) => ({
      text: String(h.name || h.host),
      value: preferId ? String(h.hostid ?? h.name ?? h.host) : String(h.name || h.host),
      id: String(h.hostid)
    }));
  }
  if (q.queryType === "application") {
    base.group = { filter: interpolateZabbixValue(q.group || "", scopedVars) };
    base.host = { filter: interpolateZabbixValue(q.host || "", scopedVars) };
    base.application = { filter: filter2 };
    const groups = await resolveGroups(api, base, scopedVars, signal);
    const hosts = await resolveHosts(
      api,
      base,
      scopedVars,
      groups.map((g) => g.groupid),
      signal
    );
    const appsPage = await api.getApplications(
      hosts.map((h) => String(h.hostid)),
      base.application.filter,
      signal
    );
    return rowsOf(appsPage).filter(
      (a) => matchesZabbixFilter(String(a.name || ""), base.application.filter)
    ).map((a) => ({
      text: String(a.name),
      value: String(a.name),
      id: String(a.applicationid)
    }));
  }
  if (q.queryType === "item" || q.queryType === "itemTag" || q.queryType === "hostTag") {
    base.group = { filter: interpolateZabbixValue(q.group || "", scopedVars) };
    base.host = { filter: interpolateZabbixValue(q.host || "", scopedVars) };
    base.application = {
      filter: interpolateZabbixValue(q.application || "", scopedVars)
    };
    base.item = { filter: q.queryType === "item" ? filter2 : "" };
    if (q.showDisabled)
      base.options = { ...base.options, showDisabledItems: true };
    const groups = await resolveGroups(api, base, scopedVars, signal);
    const hosts = await resolveHosts(
      api,
      base,
      scopedVars,
      groups.map((g) => g.groupid),
      signal
    );
    const items = await resolveItems(
      api,
      base,
      scopedVars,
      hosts.map((h) => String(h.hostid)),
      [],
      signal
    );
    if (q.queryType === "itemTag" || q.queryType === "hostTag") {
      const seen = /* @__PURE__ */ new Set();
      const out = [];
      for (const it of items) {
        for (const tag of it.tags || []) {
          const pair = `${tag.tag}:${tag.value ?? ""}`;
          if (seen.has(pair)) continue;
          if (filter2 && !matchesZabbixFilter(pair, filter2) && !matchesZabbixFilter(tag.tag, filter2))
            continue;
          seen.add(pair);
          out.push({ text: pair, value: pair, id: pair });
        }
      }
      return out;
    }
    return items.map((i) => ({
      text: String(i.name),
      value: preferId ? String(i.itemid) : String(i.name),
      id: String(i.itemid)
    }));
  }
  if (q.queryType === "macro") {
    base.group = { filter: interpolateZabbixValue(q.group || "", scopedVars) };
    base.host = { filter: interpolateZabbixValue(q.host || "", scopedVars) };
    const groups = await resolveGroups(api, base, scopedVars, signal);
    const hosts = await resolveHosts(
      api,
      base,
      scopedVars,
      groups.map((g) => g.groupid),
      signal
    );
    const page = await api.getMacros(
      hosts.map((h) => String(h.hostid)),
      filter2,
      signal
    );
    return rowsOf(page).filter(
      (m) => !filter2 || matchesZabbixFilter(String(m.macro || ""), filter2)
    ).map((m) => {
      const masked = maskMacroValue(m);
      return {
        text: String(m.macro),
        // never expose secret values as selectable value
        value: masked.secret ? String(m.macro) : String(m.macro),
        id: String(m.hostmacroid || m.globalmacroid || m.macro)
      };
    });
  }
  if (q.queryType === "proxy") {
    const page = await api.getProxies(filter2, signal);
    return rowsOf(page).filter(
      (p) => !filter2 || matchesZabbixFilter(String(p.name || p.host || ""), filter2)
    ).map((p) => {
      const name = String(p.name || p.host || p.proxyid);
      return {
        text: name,
        value: preferId ? String(p.proxyid) : name,
        id: String(p.proxyid)
      };
    });
  }
  if (q.queryType === "service") {
    const page = await api.getServices(signal);
    return rowsOf(page).filter(
      (s) => !filter2 || matchesZabbixFilter(String(s.name || ""), filter2)
    ).map((s) => ({
      text: String(s.name),
      value: preferId ? String(s.serviceid) : String(s.name),
      id: String(s.serviceid)
    }));
  }
  if (q.queryType === "sla") {
    const page = await api.getSlas(q.serviceids || [], filter2, signal);
    return rowsOf(page).filter(
      (s) => !filter2 || matchesZabbixFilter(String(s.name || s.slaid || ""), filter2)
    ).map((s) => ({
      text: String(s.name || s.slaid),
      value: preferId ? String(s.slaid) : String(s.name || s.slaid),
      id: String(s.slaid)
    }));
  }
  if (q.queryType === "trigger") {
    base.group = { filter: interpolateZabbixValue(q.group || "", scopedVars) };
    base.host = { filter: interpolateZabbixValue(q.host || "", scopedVars) };
    const groups = await resolveGroups(api, base, scopedVars, signal);
    const hosts = await resolveHosts(
      api,
      base,
      scopedVars,
      groups.map((g) => g.groupid),
      signal
    );
    const result = await api.getTriggers(
      {
        hostids: hosts.map((h) => String(h.hostid)),
        groupids: groups.map((g) => g.groupid),
        search: filter2 ? { description: filter2 } : void 0,
        output: ["triggerid", "description"]
      },
      signal
    );
    const rows = typeof result === "number" ? [] : Array.isArray(result) ? result : result.rows || [];
    return rows.map((t) => ({
      text: String(t.description || t.triggerid),
      value: preferId ? String(t.triggerid) : String(t.description || t.triggerid),
      id: String(t.triggerid)
    }));
  }
  if (q.queryType === "itemValues") {
    const itemids = String(q.item || "").split(",").map((s) => s.trim()).filter(Boolean);
    if (!itemids.length) return [];
    const items = await api.getItemsByIds(itemids, signal);
    const limit = Math.min(1e3, Math.max(1, Number(q.limit) || 100));
    const to = Number(q.to) || Math.floor(Date.now() / 1e3);
    const from = Number(q.from) || to - 3600;
    const out = [];
    const seen = /* @__PURE__ */ new Set();
    for (const item of items) {
      const hist = await api.getHistory(
        [item.itemid],
        Number(item.value_type || 0),
        from,
        to,
        signal,
        limit
      );
      for (const p of hist || []) {
        const raw = p.value == null ? "" : String(p.value);
        const key = `${item.itemid}:${p.clock}:${p.ns ?? "0"}`;
        if (seen.has(raw) && raw !== "0") {
          continue;
        }
        if (seen.has(raw) && raw === "0") {
          if (out.some((o) => o.value === "0")) continue;
        }
        if (raw !== "0") seen.add(raw);
        else seen.add("0");
        if (filter2 && !matchesZabbixFilter(raw, filter2)) continue;
        out.push({
          text: raw,
          value: raw,
          id: key
        });
        if (out.length >= limit) break;
      }
      if (out.length >= limit) break;
    }
    return out;
  }
  if (q.queryType === "lldRule") {
    base.group = { filter: interpolateZabbixValue(q.group || "", scopedVars) };
    base.host = { filter: interpolateZabbixValue(q.host || "", scopedVars) };
    const groups = await resolveGroups(api, base, scopedVars, signal);
    const hosts = await resolveHosts(
      api,
      base,
      scopedVars,
      groups.map((g) => g.groupid),
      signal
    );
    const page = await api.getDiscoveryRules(
      hosts.map((h) => String(h.hostid)),
      signal
    );
    return rowsOf(page).filter(
      (r) => !filter2 || matchesZabbixFilter(String(r.name || r.key_ || ""), filter2)
    ).map((r) => ({
      text: String(r.name || r.key_),
      value: preferId ? String(r.itemid) : String(r.name || r.key_),
      id: String(r.itemid)
    }));
  }
  if (q.queryType === "itemPrototype") {
    const ruleId = interpolateZabbixValue(q.item || q.ruleId || "", scopedVars);
    if (!ruleId) return [];
    const page = await api.getItemPrototypes(ruleId, signal);
    return rowsOf(page).filter(
      (r) => !filter2 || matchesZabbixFilter(String(r.name || r.key_ || ""), filter2)
    ).map((r) => ({
      text: String(r.name || r.key_),
      value: preferId ? String(r.itemid) : String(r.key_ || r.name),
      id: String(r.itemid)
    }));
  }
  return [];
}
const _hoisted_1$s = {
  class: "var-qe",
  "data-testid": "zabbix-variable-query-editor"
};
const _hoisted_2$n = {
  key: 0,
  class: "legacy",
  "data-testid": "zabbix-var-legacy",
  role: "status"
};
const _hoisted_3$j = {
  key: 0,
  class: "row"
};
const _sfc_main$t = /* @__PURE__ */ defineComponent({
  __name: "VariableQueryEditor",
  props: {
    query: {},
    onChange: { type: Function },
    datasource: {}
  },
  setup(__props) {
    const props = __props;
    const isLegacyString = computed(
      () => typeof props.query === "string" && isLegacyRaw(String(props.query))
    );
    function isLegacyRaw(t) {
      const s = t.trim();
      if (!s) return false;
      if (/\{[^}]+\}/.test(s)) return true;
      if (s.includes(".") && !s.includes(":") && !s.startsWith("{")) return true;
      return false;
    }
    function asObject() {
      if (typeof props.query === "string") {
        if (isLegacyRaw(props.query))
          return parseLegacyVariableQuery(props.query);
        return parseZabbixVariableQuery(props.query);
      }
      if (props.query && typeof props.query === "object") {
        const q = props.query;
        if (q.queryType) return { ...q };
        if (typeof q.query === "string") {
          if (isLegacyRaw(q.query)) return parseLegacyVariableQuery(q.query);
          return parseZabbixVariableQuery(q.query);
        }
      }
      return { queryType: "group", filter: "" };
    }
    const model = computed(() => asObject());
    const queryType = computed(() => String(model.value.queryType || "group"));
    const legacyReadonly = computed(
      () => Boolean(model.value.legacy || isLegacyString.value)
    );
    function emitPatch(partial) {
      if (legacyReadonly.value) return;
      props.onChange({
        ...model.value,
        ...partial,
        legacy: void 0,
        legacyRaw: void 0
      });
    }
    const typeOptions = [
      { label: "Group / 主机组", value: "group" },
      { label: "Host / 主机", value: "host" },
      { label: "Application / 应用集", value: "application" },
      { label: "Item Tag / 监控项标签", value: "itemTag" },
      { label: "Item / 监控项", value: "item" },
      { label: "Item values / 监控项值", value: "itemValues" },
      { label: "Host Tag / 主机标签", value: "hostTag" },
      { label: "Proxy / 代理", value: "proxy" },
      { label: "Service / 服务", value: "service" },
      { label: "SLA", value: "sla" },
      { label: "Trigger / 触发器", value: "trigger" }
    ];
    const showGroup = computed(
      () => [
        "group",
        "host",
        "application",
        "item",
        "itemTag",
        "hostTag",
        "itemValues",
        "trigger"
      ].includes(queryType.value)
    );
    const showHost = computed(
      () => [
        "host",
        "application",
        "item",
        "itemTag",
        "hostTag",
        "itemValues",
        "trigger"
      ].includes(queryType.value)
    );
    const showApplication = computed(
      () => ["application", "item", "itemValues"].includes(queryType.value)
    );
    const showItemTag = computed(
      () => queryType.value === "itemTag" || queryType.value === "item"
    );
    const showItem = computed(
      () => queryType.value === "item" || queryType.value === "itemValues"
    );
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$s, [
        legacyReadonly.value ? (openBlock(), createElementBlock("div", _hoisted_2$n, [
          _cache[7] || (_cache[7] = createElementVNode(
            "strong",
            null,
            "Legacy Query（只读）",
            -1
            /* CACHED */
          )),
          createElementVNode(
            "code",
            null,
            toDisplayString(model.value.legacyRaw || (typeof __props.query === "string" ? __props.query : "")),
            1
            /* TEXT */
          ),
          _cache[8] || (_cache[8] = createElementVNode(
            "p",
            null,
            " 旧版点路径 / 花括号语法已解析为只读回显，请新建变量迁移到结构化类型。 ",
            -1
            /* CACHED */
          ))
        ])) : createCommentVNode("v-if", true),
        _cache[14] || (_cache[14] = createElementVNode(
          "label",
          null,
          "变量类型",
          -1
          /* CACHED */
        )),
        createVNode(unref(GSelect), {
          value: queryType.value,
          options: typeOptions,
          disabled: legacyReadonly.value,
          "test-id": "zabbix-var-type",
          "onUpdate:value": _cache[0] || (_cache[0] = ($event) => emitPatch({ queryType: String($event) }))
        }, null, 8, ["value", "disabled"]),
        showGroup.value ? (openBlock(), createElementBlock(
          Fragment,
          { key: 1 },
          [
            _cache[9] || (_cache[9] = createElementVNode(
              "label",
              null,
              "Group",
              -1
              /* CACHED */
            )),
            createVNode(unref(GInput), {
              "model-value": String(
                model.value.group ?? (queryType.value === "group" ? model.value.filter : "") ?? ""
              ),
              disabled: legacyReadonly.value,
              "test-id": "zabbix-var-group",
              "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => queryType.value === "group" ? emitPatch({ filter: String($event) }) : emitPatch({ group: String($event) }))
            }, null, 8, ["model-value", "disabled"])
          ],
          64
          /* STABLE_FRAGMENT */
        )) : createCommentVNode("v-if", true),
        showHost.value ? (openBlock(), createElementBlock(
          Fragment,
          { key: 2 },
          [
            _cache[10] || (_cache[10] = createElementVNode(
              "label",
              null,
              "Host",
              -1
              /* CACHED */
            )),
            createVNode(unref(GInput), {
              "model-value": String(model.value.host ?? (queryType.value === "host" ? model.value.filter : "") ?? ""),
              disabled: legacyReadonly.value,
              "test-id": "zabbix-var-host",
              "onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => queryType.value === "host" ? emitPatch({ filter: String($event) }) : emitPatch({ host: String($event) }))
            }, null, 8, ["model-value", "disabled"])
          ],
          64
          /* STABLE_FRAGMENT */
        )) : createCommentVNode("v-if", true),
        showApplication.value ? (openBlock(), createElementBlock(
          Fragment,
          { key: 3 },
          [
            _cache[11] || (_cache[11] = createElementVNode(
              "label",
              null,
              "Application",
              -1
              /* CACHED */
            )),
            createVNode(unref(GInput), {
              "model-value": String(
                model.value.application ?? (queryType.value === "application" ? model.value.filter : "") ?? ""
              ),
              disabled: legacyReadonly.value,
              "test-id": "zabbix-var-application",
              "onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => queryType.value === "application" ? emitPatch({ filter: String($event) }) : emitPatch({ application: String($event) }))
            }, null, 8, ["model-value", "disabled"])
          ],
          64
          /* STABLE_FRAGMENT */
        )) : createCommentVNode("v-if", true),
        showItemTag.value ? (openBlock(), createElementBlock(
          Fragment,
          { key: 4 },
          [
            _cache[12] || (_cache[12] = createElementVNode(
              "label",
              null,
              "Item Tag",
              -1
              /* CACHED */
            )),
            createVNode(unref(GInput), {
              "model-value": String(
                model.value.itemTag ?? (queryType.value === "itemTag" ? model.value.filter : "") ?? ""
              ),
              disabled: legacyReadonly.value,
              "test-id": "zabbix-var-item-tag",
              "onUpdate:modelValue": _cache[4] || (_cache[4] = ($event) => queryType.value === "itemTag" ? emitPatch({ filter: String($event) }) : emitPatch({ itemTag: String($event) }))
            }, null, 8, ["model-value", "disabled"])
          ],
          64
          /* STABLE_FRAGMENT */
        )) : createCommentVNode("v-if", true),
        showItem.value ? (openBlock(), createElementBlock(
          Fragment,
          { key: 5 },
          [
            createElementVNode(
              "label",
              null,
              toDisplayString(queryType.value === "itemValues" ? "Item / Item id" : "Item"),
              1
              /* TEXT */
            ),
            createVNode(unref(GInput), {
              "model-value": String(
                queryType.value === "itemValues" ? model.value.item ?? model.value.filter ?? "" : model.value.filter ?? ""
              ),
              disabled: legacyReadonly.value,
              "test-id": "zabbix-var-item",
              "onUpdate:modelValue": _cache[5] || (_cache[5] = ($event) => queryType.value === "itemValues" ? emitPatch({ item: String($event) }) : emitPatch({ filter: String($event) }))
            }, null, 8, ["model-value", "disabled"]),
            queryType.value === "item" ? (openBlock(), createElementBlock("label", _hoisted_3$j, [
              createVNode(unref(_sfc_main$19), {
                checked: Boolean(model.value.showDisabled),
                disabled: legacyReadonly.value,
                "test-id": "zabbix-var-show-disabled",
                "onUpdate:checked": _cache[6] || (_cache[6] = ($event) => emitPatch({ showDisabled: $event }))
              }, null, 8, ["checked", "disabled"]),
              _cache[13] || (_cache[13] = createTextVNode(
                " 显示已禁用 ",
                -1
                /* CACHED */
              ))
            ])) : createCommentVNode("v-if", true)
          ],
          64
          /* STABLE_FRAGMENT */
        )) : createCommentVNode("v-if", true)
      ]);
    };
  }
});
const VariableQueryEditor$1 = /* @__PURE__ */ _export_sfc(_sfc_main$t, [["__scopeId", "data-v-d3cd6955"]]);
const _hoisted_1$r = {
  class: "anno-qe",
  "data-testid": "zabbix-annotation-query-editor"
};
const _hoisted_2$m = { class: "row" };
const _hoisted_3$i = { class: "row" };
const _hoisted_4$e = { class: "row" };
const _sfc_main$s = /* @__PURE__ */ defineComponent({
  __name: "AnnotationQueryEditor",
  props: {
    annotation: {},
    onChange: { type: Function },
    datasource: {},
    variables: {}
  },
  setup(__props) {
    const SEVERITY_LABELS = [
      { label: "Not classified", value: 0 },
      { label: "Information", value: 1 },
      { label: "Warning", value: 2 },
      { label: "Average", value: 3 },
      { label: "High", value: 4 },
      { label: "Disaster", value: 5 }
    ];
    const props = __props;
    const prepared = computed(
      () => prepareZabbixAnnotation(props.annotation || {})
    );
    const target = computed(
      () => prepared.value.target || {}
    );
    const options = computed(
      () => target.value.options || {}
    );
    function patchTarget(partial) {
      const nextTarget = {
        ...target.value,
        ...partial,
        options: {
          ...options.value,
          ...partial.options || {}
        }
      };
      props.onChange({
        ...props.annotation,
        name: props.annotation.name,
        enable: props.annotation.enable,
        iconColor: props.annotation.iconColor,
        target: nextTarget
      });
    }
    function filterOf(key) {
      const f = target.value[key];
      if (f && typeof f === "object") return String(f.filter || "");
      return String(f || "");
    }
    function setFilter(key, value) {
      patchTarget({ [key]: { filter: value } });
    }
    function setOption(key, value) {
      patchTarget({ options: { ...options.value, [key]: value } });
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$r, [
        createVNode(InlineFieldRow, null, {
          default: withCtx(() => [
            createVNode(InlineField, {
              label: "Group",
              "label-width": 12,
              grow: ""
            }, {
              default: withCtx(() => [
                createVNode(MetricPicker, {
                  value: filterOf("group"),
                  variables: __props.variables,
                  "test-id": "zabbix-anno-group",
                  placeholder: "Group",
                  "onUpdate:value": _cache[0] || (_cache[0] = ($event) => setFilter("group", $event))
                }, null, 8, ["value", "variables"])
              ]),
              _: 1
              /* STABLE */
            }),
            createVNode(InlineField, {
              label: "Host",
              "label-width": 12,
              grow: ""
            }, {
              default: withCtx(() => [
                createVNode(MetricPicker, {
                  value: filterOf("host"),
                  variables: __props.variables,
                  "test-id": "zabbix-anno-host",
                  placeholder: "Host",
                  "onUpdate:value": _cache[1] || (_cache[1] = ($event) => setFilter("host", $event))
                }, null, 8, ["value", "variables"])
              ]),
              _: 1
              /* STABLE */
            })
          ]),
          _: 1
          /* STABLE */
        }),
        createVNode(InlineFieldRow, null, {
          default: withCtx(() => [
            createVNode(InlineField, {
              label: "Application",
              "label-width": 12,
              grow: ""
            }, {
              default: withCtx(() => [
                createVNode(MetricPicker, {
                  value: filterOf("application"),
                  variables: __props.variables,
                  "test-id": "zabbix-anno-application",
                  placeholder: "Application",
                  "onUpdate:value": _cache[2] || (_cache[2] = ($event) => setFilter("application", $event))
                }, null, 8, ["value", "variables"])
              ]),
              _: 1
              /* STABLE */
            }),
            createVNode(InlineField, {
              label: "Trigger",
              "label-width": 12,
              grow: ""
            }, {
              default: withCtx(() => [
                createVNode(MetricPicker, {
                  value: filterOf("trigger"),
                  variables: __props.variables,
                  "test-id": "zabbix-anno-trigger",
                  placeholder: "Trigger",
                  "onUpdate:value": _cache[3] || (_cache[3] = ($event) => setFilter("trigger", $event))
                }, null, 8, ["value", "variables"])
              ]),
              _: 1
              /* STABLE */
            })
          ]),
          _: 1
          /* STABLE */
        }),
        createVNode(InlineFieldRow, null, {
          default: withCtx(() => [
            createVNode(InlineField, {
              label: "Min severity",
              "label-width": 12
            }, {
              default: withCtx(() => [
                createVNode(unref(GSelect), {
                  value: options.value.minSeverity ?? 0,
                  options: SEVERITY_LABELS,
                  "test-id": "zabbix-anno-min-severity",
                  "onUpdate:value": _cache[4] || (_cache[4] = ($event) => setOption("minSeverity", Number($event)))
                }, null, 8, ["value"])
              ]),
              _: 1
              /* STABLE */
            })
          ]),
          _: 1
          /* STABLE */
        }),
        createElementVNode("label", _hoisted_2$m, [
          createVNode(unref(_sfc_main$19), {
            checked: Boolean(options.value.showOkEvents),
            "test-id": "zabbix-anno-show-ok",
            "onUpdate:checked": _cache[5] || (_cache[5] = ($event) => setOption("showOkEvents", $event))
          }, null, 8, ["checked"]),
          _cache[8] || (_cache[8] = createTextVNode(
            " 显示 OK 事件 ",
            -1
            /* CACHED */
          ))
        ]),
        createElementVNode("label", _hoisted_3$i, [
          createVNode(unref(_sfc_main$19), {
            checked: Boolean(options.value.hideAcknowledged),
            "test-id": "zabbix-anno-hide-ack",
            "onUpdate:checked": _cache[6] || (_cache[6] = ($event) => setOption("hideAcknowledged", $event))
          }, null, 8, ["checked"]),
          _cache[9] || (_cache[9] = createTextVNode(
            " 隐藏已确认 ",
            -1
            /* CACHED */
          ))
        ]),
        createElementVNode("label", _hoisted_4$e, [
          createVNode(unref(_sfc_main$19), {
            checked: Boolean(options.value.showHostname),
            "test-id": "zabbix-anno-show-hostname",
            "onUpdate:checked": _cache[7] || (_cache[7] = ($event) => setOption("showHostname", $event))
          }, null, 8, ["checked"]),
          _cache[10] || (_cache[10] = createTextVNode(
            " 显示主机名 ",
            -1
            /* CACHED */
          ))
        ])
      ]);
    };
  }
});
const AnnotationQueryEditor$1 = /* @__PURE__ */ _export_sfc(_sfc_main$s, [["__scopeId", "data-v-6a0e5f1b"]]);
const MAX_ENTRIES$1 = 500;
function stableSerialize$1(value) {
  if (value === void 0) return "undefined";
  if (value === null || typeof value !== "object") return JSON.stringify(value);
  if (Array.isArray(value)) return `[${value.map(stableSerialize$1).join(",")}]`;
  const obj = value;
  const keys = Object.keys(obj).filter((k) => obj[k] !== void 0).sort();
  return `{${keys.map((k) => `${JSON.stringify(k)}:${stableSerialize$1(obj[k])}`).join(",")}}`;
}
function serializeZabbixCacheKey(key) {
  return stableSerialize$1({
    uid: key.uid,
    majorVersion: key.majorVersion,
    method: key.method,
    params: key.params || {}
  });
}
class ZabbixMetadataCache {
  entries = /* @__PURE__ */ new Map();
  inflight = /* @__PURE__ */ new Map();
  load(key, ttlMs, consumerSignal, loader) {
    const serialized = serializeZabbixCacheKey(key);
    const now = Date.now();
    const hit = this.entries.get(serialized);
    if (hit && hit.expiresAt > now) {
      hit.lastAccess = now;
      return Promise.resolve(hit.value);
    }
    const existing = this.inflight.get(serialized);
    if (existing) {
      existing.consumers += 1;
      return this.bindConsumer(existing, consumerSignal);
    }
    const controller = new AbortController();
    const inflight = {
      key: serialized,
      controller,
      consumers: 1,
      promise: Promise.resolve().then(() => {
        if (controller.signal.aborted) {
          throw new DOMException("Aborted", "AbortError");
        }
        return loader(controller.signal);
      }).then((value) => {
        if (controller.signal.aborted) {
          throw new DOMException("Aborted", "AbortError");
        }
        this.entries.set(serialized, {
          key: serialized,
          uid: key.uid,
          method: key.method,
          expiresAt: Date.now() + Math.max(0, ttlMs),
          lastAccess: Date.now(),
          value
        });
        this.evictIfNeeded();
        return value;
      }).finally(() => {
        this.inflight.delete(serialized);
      })
    };
    this.inflight.set(serialized, inflight);
    if (consumerSignal?.aborted) {
      inflight.consumers -= 1;
      if (inflight.consumers <= 0) inflight.controller.abort();
      return Promise.reject(new DOMException("Aborted", "AbortError"));
    }
    return this.bindConsumer(inflight, consumerSignal);
  }
  bindConsumer(inflight, signal) {
    return new Promise((resolve, reject) => {
      let settled = false;
      const onAbort = () => {
        if (settled) return;
        settled = true;
        inflight.consumers -= 1;
        if (inflight.consumers <= 0) inflight.controller.abort();
        reject(new DOMException("Aborted", "AbortError"));
      };
      if (signal) {
        if (signal.aborted) {
          onAbort();
          return;
        }
        signal.addEventListener("abort", onAbort, { once: true });
      }
      inflight.promise.then(
        (v) => {
          if (settled) return;
          settled = true;
          signal?.removeEventListener("abort", onAbort);
          resolve(v);
        },
        (e) => {
          if (settled) return;
          settled = true;
          signal?.removeEventListener("abort", onAbort);
          reject(e);
        }
      );
    });
  }
  invalidate(uid, methods) {
    const set = new Set(methods);
    for (const [k, entry] of this.entries) {
      if (entry.uid === uid && set.has(entry.method)) this.entries.delete(k);
    }
  }
  clearUid(uid) {
    for (const [k, entry] of this.entries) {
      if (entry.uid === uid) this.entries.delete(k);
    }
    for (const [k, flight] of this.inflight) {
      if (k.includes(`"uid":${JSON.stringify(uid)}`) || k.includes(`"uid":"${uid}"`)) {
        flight.controller.abort();
        this.inflight.delete(k);
      }
    }
  }
  clear() {
    this.entries.clear();
    for (const flight of this.inflight.values()) flight.controller.abort();
    this.inflight.clear();
  }
  evictIfNeeded() {
    while (this.entries.size > MAX_ENTRIES$1) {
      let oldestKey = "";
      let oldest = Infinity;
      for (const [k, v] of this.entries) {
        if (v.lastAccess < oldest) {
          oldest = v.lastAccess;
          oldestKey = k;
        }
      }
      if (!oldestKey) break;
      this.entries.delete(oldestKey);
    }
  }
}
const READ_METHOD_LIST = [
  "alert.get",
  "apiinfo.version",
  "application.get",
  "discoveryrule.get",
  "event.get",
  "history.get",
  "host.get",
  "hostgroup.get",
  "item.get",
  "itemprototype.get",
  "problem.get",
  "proxy.get",
  "script.get",
  "service.get",
  "service.getsla",
  "sla.get",
  "sla.getsli",
  "trend.get",
  "trigger.get",
  "user.get",
  "usermacro.get",
  "valuemap.get"
];
const WRITE_METHOD_LIST = [
  "event.acknowledge",
  "script.execute"
];
const READ_METHODS = new Set(READ_METHOD_LIST);
const WRITE_METHODS = new Set(WRITE_METHOD_LIST);
function assertAllowedZabbixMethod(method) {
  if (!READ_METHODS.has(method) && !WRITE_METHODS.has(method)) {
    throw new Error(`Zabbix API method is not allowed: ${method}`);
  }
}
function parseZabbixVersion(version) {
  const parts = String(version || "0").split(".").map((x) => Number(x) || 0);
  return { major: parts[0] || 0, minor: parts[1] || 0, patch: parts[2] || 0 };
}
function getZabbixVersionCapabilities(version, overrides) {
  const { major, minor } = parseZabbixVersion(version);
  const ge = (maj, min = 0) => major > maj || major === maj && minor >= min;
  const supportsApiToken = ge(5, 4);
  const loginUserField = ge(5, 4) ? "username" : "user";
  const authCandidates = supportsApiToken ? ge(7, 0) ? ["body", "header"] : ["body"] : [];
  const triggerHostGroupsField = ge(7, 0) ? "selectHostGroups" : "selectGroups";
  const acknowledgesField = ge(7, 0) ? "selectAcknowledges" : "select_acknowledges";
  const proxyNameField = ge(7, 0) ? "name" : "host";
  const hostProxyIdField = ge(7, 0) ? "proxyid" : "proxy_hostid";
  const hostgroupRealHostsField = ge(6, 0) ? "with_hosts" : "real_hosts";
  const supportsApplications = !ge(5, 4);
  const supportsItemTags = ge(5, 4);
  const slaApi = ge(6, 0) ? "sla" : "legacy";
  return {
    version: String(version),
    major,
    minor,
    supportsApiToken,
    loginUserField,
    authCandidates,
    selectedAuthPlacement: overrides?.selectedAuthPlacement,
    triggerHostGroupsField,
    acknowledgesField,
    proxyNameField,
    hostProxyIdField,
    hostgroupRealHostsField,
    supportsApplications,
    supportsItemTags,
    slaApi
  };
}
function buildVersionedAuthRequest(caps2, method, params, token, id = 1, placementOverride) {
  const body = { jsonrpc: "2.0", id, method, params };
  const headers = {};
  if (!token)
    return { body, headers, placement: void 0 };
  if (!caps2.supportsApiToken) {
    return {
      body,
      headers,
      placement: void 0,
      rejected: true
    };
  }
  const placement = placementOverride || caps2.selectedAuthPlacement || caps2.authCandidates[0] || "body";
  if (placement === "header") {
    headers.Authorization = `Bearer ${token}`;
  } else {
    body.auth = token;
  }
  return { body, headers, placement };
}
function normalizeZabbixUrl(url) {
  const baseUrl2 = String(url || "").replace(/\/$/, "");
  const proxied = baseUrl2.startsWith("/zabbix-api") || baseUrl2.includes("api_jsonrpc.php");
  return { baseUrl: baseUrl2, path: proxied ? "" : "/api_jsonrpc.php" };
}
function buildAuthenticatedRequest(version, method, params, token, id = 1, placement) {
  const caps2 = getZabbixVersionCapabilities(
    version,
    placement ? { selectedAuthPlacement: placement } : void 0
  );
  const built = buildVersionedAuthRequest(
    caps2,
    method,
    params,
    token,
    id,
    placement
  );
  return { body: built.body, headers: built.headers };
}
class ZabbixRpcClient {
  url;
  uid;
  timeoutMs;
  maxBodyBytes;
  versionCache = null;
  tokenCache = null;
  nextId = 1;
  credential;
  forceNetwork;
  authPlacement = null;
  capsCache = null;
  authPlacementOverride = "auto";
  authPlacementPromise = null;
  constructor(opts) {
    this.url = opts.url;
    this.uid = opts.uid;
    this.timeoutMs = opts.timeoutMs ?? 3e4;
    this.maxBodyBytes = opts.maxBodyBytes ?? 1e7;
    this.credential = opts.credential;
    this.forceNetwork = opts.forceNetwork ?? true;
  }
  async getVersion(signal) {
    if (this.versionCache) return this.versionCache;
    const version = await this.rawCall(
      "apiinfo.version",
      {},
      null,
      signal
    );
    const vs = typeof version === "string" ? version : Array.isArray(version) ? "" : String(version ?? "");
    this.versionCache = vs && /^\d+/.test(vs) ? vs : "6.0.0";
    this.capsCache = getZabbixVersionCapabilities(this.versionCache, {
      selectedAuthPlacement: this.authPlacement || void 0
    });
    return this.versionCache;
  }
  getCapabilities() {
    return this.capsCache;
  }
  setAuthPlacementOverride(placement) {
    this.authPlacementOverride = placement;
    this.authPlacement = placement === "auto" ? null : placement;
    this.authPlacementPromise = null;
  }
  /** Probe hostgroup.get limit=1 to choose body vs header auth for the current token. */
  async resolveAuthPlacement(token, signal) {
    if (this.authPlacementOverride !== "auto" && this.authPlacement)
      return this.authPlacement;
    if (this.authPlacement) return this.authPlacement;
    if (this.authPlacementPromise) return this.authPlacementPromise;
    this.authPlacementPromise = this.doResolveAuthPlacement(token, signal).catch((error) => {
      this.authPlacementPromise = null;
      throw error;
    });
    return this.authPlacementPromise;
  }
  async doResolveAuthPlacement(token, signal) {
    if (this.authPlacementOverride !== "auto" && this.authPlacement)
      return this.authPlacement;
    if (this.authPlacement) return this.authPlacement;
    const version = await this.getVersion(signal);
    const caps2 = getZabbixVersionCapabilities(version);
    if (!caps2.supportsApiToken) {
      throw new DataSourceError(
        "AUTH_REQUIRED",
        "当前 Zabbix 版本不支持 API token"
      );
    }
    const candidates = caps2.authCandidates.length ? caps2.authCandidates : ["body"];
    let lastErr;
    for (const placement of candidates) {
      try {
        await this.rawCall(
          "hostgroup.get",
          { limit: 1, output: ["groupid"] },
          token,
          signal,
          version,
          placement
        );
        this.authPlacement = placement;
        this.capsCache = getZabbixVersionCapabilities(version, {
          selectedAuthPlacement: placement
        });
        return placement;
      } catch (e) {
        lastErr = e;
      }
    }
    throw lastErr instanceof DataSourceError ? lastErr : new DataSourceError("AUTH_REQUIRED", "无法确定 API token 认证位置");
  }
  async call(method, params = {}, signal) {
    assertAllowedZabbixMethod(method);
    if (method !== "apiinfo.version") {
      await this.ensureToken("6.0.0", signal);
    }
    const version = method === "apiinfo.version" ? "6.0.0" : await this.getVersion(signal);
    const token = method === "apiinfo.version" ? null : await this.ensureToken(version, signal);
    let placement;
    if (token) {
      const cred = this.credential === void 0 ? await getRuntimeCredential(this.uid) : this.credential;
      if (cred && (cred.kind === "bearer" || cred.kind === "apiKey")) {
        placement = await this.resolveAuthPlacement(token, signal);
      }
    }
    return this.rawCall(method, params, token, signal, version, placement);
  }
  async callWithFallback(method, params, fallback, timeoutMs, signal) {
    const ac = new AbortController();
    const timer = setTimeout(() => ac.abort(), Math.max(1, timeoutMs));
    const onOuterAbort = () => ac.abort();
    signal?.addEventListener("abort", onOuterAbort);
    try {
      return await this.call(method, params, ac.signal);
    } catch (e) {
      const isAbort = e?.name === "AbortError" || e?.code === "ERR_CANCELED";
      if (isAbort) return fallback;
      throw e;
    } finally {
      clearTimeout(timer);
      signal?.removeEventListener("abort", onOuterAbort);
    }
  }
  async ensureToken(version, signal) {
    if (this.tokenCache) return this.tokenCache;
    const cred = this.credential === void 0 ? await getRuntimeCredential(this.uid) : this.credential;
    if (!cred) {
      throw new DataSourceError(
        "AUTH_REQUIRED",
        "Zabbix 需要 runtime credential（token 或用户名密码）"
      );
    }
    if (cred.kind === "bearer" || cred.kind === "apiKey") {
      this.tokenCache = cred.value || null;
      if (!this.tokenCache) {
        throw new DataSourceError("AUTH_REQUIRED", "Zabbix API token 为空");
      }
      return this.tokenCache;
    }
    if (cred.kind === "basic" && cred.username && cred.password) {
      this.tokenCache = await this.login(
        version,
        cred.username,
        cred.password,
        signal
      );
      return this.tokenCache;
    }
    throw new DataSourceError(
      "AUTH_REQUIRED",
      "Zabbix 凭据类型不受支持或字段不完整"
    );
  }
  async login(version, username, password, signal) {
    const caps2 = getZabbixVersionCapabilities(version);
    const primaryField = caps2.loginUserField;
    const primary = primaryField === "username" ? { username, password } : { user: username, password };
    try {
      return await this.rawCall(
        "user.login",
        primary,
        null,
        signal,
        version
      );
    } catch (e) {
      const msg = e instanceof Error ? e.message : String(e);
      const details = e instanceof DataSourceError ? JSON.stringify(e.details ?? {}) : "";
      if (/unexpected parameter|invalid parameter|unknown parameter|deprecated/i.test(
        `${msg} ${details}`
      )) {
        const alt = primaryField === "username" ? { user: username, password } : { username, password };
        return this.rawCall("user.login", alt, null, signal, version);
      }
      throw e;
    }
  }
  async rawCall(method, params, token, signal, version = "6.0.0", placement) {
    if (method !== "user.login" && method !== "apiinfo.version") {
      assertAllowedZabbixMethod(method);
    }
    const id = this.nextId++;
    const { baseUrl: baseUrl2, path } = normalizeZabbixUrl(this.url);
    const { body, headers } = buildAuthenticatedRequest(
      version,
      method,
      params,
      token,
      id,
      placement
    );
    try {
      const res = await datasourceHttp({
        baseUrl: baseUrl2,
        path,
        method: "POST",
        body,
        headers,
        uid: this.uid,
        signal,
        timeoutMs: this.timeoutMs,
        maxBodyBytes: this.maxBodyBytes,
        credential: null,
        forceNetwork: this.forceNetwork,
        isWrite: false,
        idempotent: method === "apiinfo.version" || method.endsWith(".get")
      });
      const data = res.data;
      if (!data || typeof data !== "object") {
        throw new DataSourceError(
          "INVALID_RESPONSE",
          "Zabbix 返回无效 JSON-RPC 响应"
        );
      }
      if (data.error) {
        const message = [data.error.message, data.error.data].filter(Boolean).join(" — ") || "Zabbix RPC error";
        throw withDataSourceContext(
          new DataSourceError("UPSTREAM_ERROR", message, {
            upstreamCode: data.error.code
          }),
          {
            uid: this.uid,
            endpoint: `${baseUrl2}${path}`,
            upstreamCode: data.error.code
          }
        );
      }
      if (data.id != null && data.id !== id) {
        throw new DataSourceError(
          "INVALID_RESPONSE",
          "Zabbix JSON-RPC id 不匹配"
        );
      }
      if (!("result" in data)) {
        throw new DataSourceError(
          "INVALID_RESPONSE",
          "Zabbix JSON-RPC 缺少 result"
        );
      }
      return data.result;
    } catch (e) {
      if (e instanceof DataSourceError) {
        throw withDataSourceContext(e, {
          uid: this.uid,
          endpoint: `${baseUrl2}${path}`
        });
      }
      throw withDataSourceContext(e, {
        uid: this.uid,
        endpoint: `${baseUrl2}${path}`
      });
    }
  }
}
function splitKeyParams(key) {
  const s = String(key || "");
  const open = s.indexOf("[");
  const close = s.lastIndexOf("]");
  if (open < 0 || close <= open) return [];
  const body = s.slice(open + 1, close);
  const parts = [];
  let cur = "";
  let depth = 0;
  let quote = null;
  for (let i = 0; i < body.length; i++) {
    const ch = body[i];
    if (quote) {
      if (ch === quote) quote = null;
      cur += ch;
      continue;
    }
    if (ch === '"' || ch === "'") {
      quote = ch;
      cur += ch;
      continue;
    }
    if (ch === "[") {
      depth++;
      cur += ch;
      continue;
    }
    if (ch === "]") {
      depth = Math.max(0, depth - 1);
      cur += ch;
      continue;
    }
    if (ch === "," && depth === 0) {
      parts.push(stripQuotes(cur.trim()));
      cur = "";
      continue;
    }
    cur += ch;
  }
  if (cur.length || body.endsWith(",")) parts.push(stripQuotes(cur.trim()));
  return parts;
}
function stripQuotes(v) {
  if (v.startsWith('"') && v.endsWith('"') || v.startsWith("'") && v.endsWith("'")) {
    return v.slice(1, -1);
  }
  return v;
}
function expandItemName(name, key) {
  const params = splitKeyParams(key);
  return String(name || "").replace(/\$([1-9])/g, (_, d) => {
    const idx = Number(d) - 1;
    return params[idx] != null ? params[idx] : `$${d}`;
  });
}
function expandItems(items) {
  return (items || []).map((it) => ({
    ...it,
    name: expandItemName(String(it.name || ""), String(it.key_ || ""))
  }));
}
function majorOf(version) {
  return Number(String(version).split(".")[0] || 6);
}
function minorOf(version) {
  return Number(String(version).split(".")[1] || 0);
}
function pageResult(rows, limit) {
  const list = Array.isArray(rows) ? rows : [];
  const truncated = limit > 0 && list.length >= limit;
  return {
    rows: list,
    complete: !truncated,
    truncated,
    limit
  };
}
function normalizeTriggerHostGroups(rows) {
  if (!Array.isArray(rows)) return [];
  return rows.map((row) => {
    if (row.hostgroups != null) {
      return { ...row, groups: row.hostgroups };
    }
    return row;
  });
}
const ITEM_OUTPUT = [
  "itemid",
  "name",
  "key_",
  "hostid",
  "value_type",
  "units",
  "delay",
  "status",
  "state",
  "valuemapid",
  "lastvalue",
  "lastclock"
];
class ZabbixApi {
  versionPromise = null;
  transport;
  uid;
  cache;
  metadataTtlMs;
  metadataPageLimit;
  /** Short in-flight/result cache so duplicate panels share trend/history RPCs. */
  trendHistoryCache = /* @__PURE__ */ new Map();
  static TREND_HISTORY_TTL_MS = 15e3;
  cachedTrendHistory(key, run) {
    const now = Date.now();
    const hit = this.trendHistoryCache.get(key);
    if (hit && now - hit.at < ZabbixApi.TREND_HISTORY_TTL_MS) {
      return hit.promise;
    }
    const promise = run().catch((e) => {
      this.trendHistoryCache.delete(key);
      throw e;
    });
    this.trendHistoryCache.set(key, { at: now, promise });
    return promise;
  }
  constructor(transportOrOpts) {
    if (typeof transportOrOpts.transport !== "undefined" && !transportOrOpts.call) {
      const opts = transportOrOpts;
      this.transport = opts.transport;
      this.uid = opts.uid || "";
      this.cache = opts.cache;
      this.metadataTtlMs = opts.metadataTtlMs ?? 36e5;
      this.metadataPageLimit = opts.metadataPageLimit ?? 1e3;
    } else {
      this.transport = transportOrOpts;
      this.uid = "";
      this.metadataTtlMs = 36e5;
      this.metadataPageLimit = 1e3;
    }
  }
  get pageLimit() {
    return this.metadataPageLimit;
  }
  get metaTimeoutMs() {
    return Math.max(5e3, Math.floor(this.metadataTtlMs / 3));
  }
  cachedCall(method, params, signal, fallback) {
    const run = (sharedSignal) => {
      const sig = sharedSignal ?? signal;
      if (fallback !== void 0) {
        return this.transport.callWithFallback(
          method,
          params,
          fallback,
          this.metaTimeoutMs,
          sig
        );
      }
      return this.transport.call(method, params, sig);
    };
    if (!this.cache || !this.uid) {
      return run(signal);
    }
    return this.version(signal).then((version) => {
      const majorVersion = Number(String(version).split(".")[0] || 6);
      return this.cache.load(
        { uid: this.uid, majorVersion, method, params },
        this.metadataTtlMs,
        signal,
        (sharedSignal) => run(sharedSignal)
      );
    });
  }
  version(signal) {
    if (!this.versionPromise) {
      this.versionPromise = this.transport.getVersion(signal).catch((error) => {
        this.versionPromise = null;
        throw error;
      });
    }
    return this.versionPromise;
  }
  async ver(signal) {
    return this.version(signal);
  }
  async getGroups(filter2, signal) {
    const params = {
      output: ["groupid", "name"],
      sortfield: "name",
      limit: this.metadataPageLimit
    };
    const search = toApiSearchString(filter2);
    if (search) params.search = { name: search };
    const rows = await this.cachedCall("hostgroup.get", params, signal, []);
    return pageResult(rows, this.metadataPageLimit);
  }
  async getHosts(groupids, filter2, hostTags = [], signal, evaltype = 0) {
    const version = await this.ver(signal);
    const caps2 = getZabbixVersionCapabilities(version);
    const params = {
      // Keep host list light — selectInventory/Interfaces extend freezes UI on large fleets
      output: [
        "hostid",
        "name",
        "host",
        "status",
        "maintenance_status",
        caps2.hostProxyIdField
      ],
      sortfield: "name",
      limit: this.metadataPageLimit,
      // Enabled + monitored only — alphabetical "111/1111" junk hosts often have 0 items.
      monitored: true,
      filter: { status: 0 }
    };
    if (groupids?.length) params.groupids = groupids;
    const search = toApiSearchString(filter2);
    if (search) params.search = { name: search };
    if (!search && !hostTags?.length) {
      params.with_monitored_items = true;
    }
    if (hostTags?.length) {
      params.tags = hostTags.map((t) => ({
        tag: t.tag,
        value: t.value,
        operator: t.operator
      }));
      params.evaltype = evaltype === 2 ? 2 : 0;
    }
    const rows = await this.cachedCall("host.get", params, signal, []);
    return pageResult(rows, this.metadataPageLimit);
  }
  async getApplications(hostids, filter2, signal) {
    const version = await this.ver(signal);
    const caps2 = getZabbixVersionCapabilities(version);
    if (!caps2.supportsApplications) {
      return pageResult([], this.metadataPageLimit);
    }
    const params = {
      output: "extend",
      sortfield: "name",
      limit: this.metadataPageLimit
    };
    if (hostids?.length) params.hostids = hostids;
    const search = toApiSearchString(filter2);
    if (search) params.search = { name: search };
    const rows = await this.cachedCall(
      "application.get",
      params,
      signal,
      []
    );
    return pageResult(rows, this.metadataPageLimit);
  }
  async getDiscoveryRules(hostids, signal) {
    const params = {
      output: ["itemid", "name", "key_"],
      limit: this.metadataPageLimit
    };
    if (hostids?.length) params.hostids = hostids;
    const rows = await this.cachedCall(
      "discoveryrule.get",
      params,
      signal
    );
    return pageResult(rows, this.metadataPageLimit);
  }
  async getItemPrototypes(discoveryRuleId, signal) {
    const params = {
      output: ["itemid", "name", "key_"],
      limit: this.metadataPageLimit
    };
    if (discoveryRuleId) params.discoveryids = [discoveryRuleId];
    const rows = await this.cachedCall(
      "itemprototype.get",
      params,
      signal
    );
    return pageResult(rows, this.metadataPageLimit);
  }
  /**
   * Discovered items for LLD: always request selectItemDiscovery:'extend'.
   * Matching uses itemDiscovery.parent_itemid against selected prototype itemids
   * when provided; otherwise prototypeKeys match exact key_ of prototypes only when
   * parent relation is missing (INVALID_RESPONSE if relation required).
   */
  async getDiscoveredItems(hostids, discoveryRuleId, keyPrefixes, signal, opts) {
    const params = {
      output: "extend",
      selectTags: "extend",
      selectHosts: ["hostid", "name", "host"],
      selectItemDiscovery: "extend",
      limit: this.metadataPageLimit
    };
    if (hostids?.length) params.hostids = hostids;
    if (discoveryRuleId) params.discoveryids = [discoveryRuleId];
    const items = await this.transport.call("item.get", params, signal) || [];
    const prototypeIds = (opts?.prototypeIds || []).map(String).filter(Boolean);
    if (prototypeIds.length) {
      const matched = items.filter((it) => {
        const parent = String(it.itemDiscovery?.parent_itemid ?? "");
        return parent && prototypeIds.includes(parent);
      });
      const missingRelation = items.length > 0 && matched.length === 0 && items.every((it) => !it.itemDiscovery?.parent_itemid);
      if (missingRelation || opts?.requireParentRelation && items.some((it) => !it.itemDiscovery?.parent_itemid)) {
        throw new DataSourceError(
          "INVALID_RESPONSE",
          "discovered items missing itemDiscovery.parent_itemid; cannot match prototypes"
        );
      }
      return matched;
    }
    if (!keyPrefixes?.length) return items;
    return items.filter(
      (it) => keyPrefixes.some((p) => String(it.key_ || "").startsWith(p))
    );
  }
  async getDiscoveryRulesFull(hostids, signal) {
    const params = {
      output: "extend",
      limit: this.metadataPageLimit
    };
    if (hostids?.length) params.hostids = hostids;
    const rows = await this.cachedCall(
      "discoveryrule.get",
      params,
      signal
    );
    return pageResult(rows, this.metadataPageLimit);
  }
  async getItemPrototypesFull(discoveryRuleId, signal) {
    const params = {
      output: "extend",
      limit: this.metadataPageLimit
    };
    if (discoveryRuleId) params.discoveryids = [discoveryRuleId];
    const rows = await this.cachedCall(
      "itemprototype.get",
      params,
      signal
    );
    return pageResult(rows, this.metadataPageLimit);
  }
  async getItems(params, signal) {
    const version = await this.ver(signal);
    const body = {
      output: [...ITEM_OUTPUT],
      selectTags: "extend",
      selectHosts: ["hostid", "name", "host"],
      sortfield: "name",
      webitems: true,
      limit: this.metadataPageLimit,
      monitored: true
    };
    if (params.hostids?.length) body.hostids = params.hostids;
    if (params.groupids?.length) body.groupids = params.groupids;
    if (params.applicationids?.length && (majorOf(version) < 5 || majorOf(version) === 5 && minorOf(version) < 4)) {
      body.applicationids = params.applicationids;
    }
    const rawFilter = String(params.filter || "").trim();
    const searchToken = zabbixFilterToApiSearch(rawFilter);
    if (searchToken) {
      body.search = { name: searchToken, key_: searchToken };
      body.searchByAny = true;
      if (/[*%]/.test(searchToken)) {
        body.searchWildcardsEnabled = true;
      }
    }
    if (!params.showDisabled)
      body.filter = { ...body.filter, status: 0 };
    if (params.valueTypes?.length)
      body.filter = {
        ...body.filter,
        value_type: params.valueTypes
      };
    if (params.itemTag) {
      const [tag, ...rest] = params.itemTag.split(":");
      body.tags = [
        { tag: tag.trim(), value: rest.join(":").trim(), operator: 0 }
      ];
    }
    const cacheKey = `item.get|${JSON.stringify(body)}`;
    const rows = await this.cachedTrendHistory(
      cacheKey,
      () => this.cachedCall("item.get", body, signal, [])
    );
    return pageResult(
      expandItems(rows),
      this.metadataPageLimit
    );
  }
  async getItemsByIds(itemids, signal) {
    if (!itemids?.length) return [];
    const rows = await this.transport.call(
      "item.get",
      {
        itemids,
        output: [...ITEM_OUTPUT],
        selectTags: "extend",
        selectHosts: ["hostid", "name", "host"]
      },
      signal
    );
    return expandItems(rows || []);
  }
  async getHistory(itemids, history, from, to, signal, limit) {
    if (!itemids?.length) return [];
    const ids = [...itemids].map(String).sort();
    const key = `h|${ids.join(",")}|${history}|${from}|${to}|${limit ?? ""}`;
    return this.cachedTrendHistory(key, async () => {
      const params = {
        itemids: ids,
        history,
        time_from: from,
        time_till: to,
        output: ["itemid", "clock", "value", "ns"],
        sortfield: "clock",
        sortorder: "ASC"
      };
      if (limit != null && limit > 0) params.limit = limit;
      return this.transport.call(
        "history.get",
        params,
        signal
      );
    });
  }
  async getTrends(itemids, from, to, signal) {
    if (!itemids?.length) return [];
    const ids = [...itemids].map(String).sort();
    const key = `t|${ids.join(",")}|${from}|${to}`;
    return this.cachedTrendHistory(
      key,
      async () => this.transport.call(
        "trend.get",
        {
          itemids: ids,
          time_from: from,
          time_till: to,
          // Slim columns — extend freezes the browser on multi-item 7d windows.
          output: [
            "itemid",
            "clock",
            "value_min",
            "value_avg",
            "value_max",
            "num"
          ],
          sortfield: "clock",
          sortorder: "ASC",
          // Soft cap; loadHistory downsamples further per series.
          limit: 2e3
        },
        signal
      )
    );
  }
  async getTriggers(params, signal) {
    const version = await this.ver(signal);
    const caps2 = getZabbixVersionCapabilities(version);
    const body = { ...params };
    const groupSelect = body.selectHostGroups ?? body.selectGroups;
    if (groupSelect !== void 0) {
      delete body.selectGroups;
      delete body.selectHostGroups;
      body[caps2.triggerHostGroupsField] = groupSelect;
    }
    if (!body.limit && !body.countOutput) body.limit = this.metadataPageLimit;
    const raw = await this.transport.call("trigger.get", body, signal);
    if (body.countOutput) {
      if (typeof raw === "number") return raw;
      if (typeof raw === "string") return Number(raw) || 0;
      if (Array.isArray(raw)) return raw.length;
      return Number(raw) || 0;
    }
    const normalized = normalizeTriggerHostGroups(raw);
    return pageResult(normalized, Number(body.limit) || this.metadataPageLimit);
  }
  async getProblems(params, signal) {
    const version = await this.ver(signal);
    const body = {
      output: "extend",
      selectTags: "extend",
      sortfield: ["eventid"],
      sortorder: "DESC",
      ...params
    };
    delete body.selectHosts;
    const caps2 = getZabbixVersionCapabilities(version);
    delete body.selectAcknowledges;
    delete body.select_acknowledges;
    body[caps2.acknowledgesField] = "extend";
    return this.transport.call("problem.get", body, signal);
  }
  async getEvents(params, signal) {
    return this.transport.call("event.get", params, signal);
  }
  async getProxies(filter2, signal) {
    const version = await this.ver(signal);
    const caps2 = getZabbixVersionCapabilities(version);
    const nameField = caps2.proxyNameField;
    const params = {
      output: ["proxyid", nameField, "status"],
      limit: this.metadataPageLimit
    };
    if (filter2) params.search = { [nameField]: filter2 };
    const rows = await this.cachedCall("proxy.get", params, signal);
    return pageResult(rows, this.metadataPageLimit);
  }
  async getServices(signal) {
    const rows = await this.cachedCall(
      "service.get",
      { output: "extend", limit: this.metadataPageLimit },
      signal
    );
    return pageResult(rows, this.metadataPageLimit);
  }
  async getSlas(serviceids, filter2, signal) {
    const version = await this.ver(signal);
    if (majorOf(version) >= 6) {
      const params2 = {
        output: "extend",
        limit: this.metadataPageLimit
      };
      if (serviceids?.length) params2.serviceids = serviceids;
      if (filter2) params2.search = { name: filter2 };
      const rows2 = await this.cachedCall("sla.get", params2, signal);
      return pageResult(rows2, this.metadataPageLimit);
    }
    const params = {};
    if (serviceids?.length) params.serviceids = serviceids;
    const rows = await this.transport.call(
      "service.getsla",
      params,
      signal
    );
    return pageResult(rows, this.metadataPageLimit);
  }
  async getSli(params, signal) {
    const version = await this.ver(signal);
    if (majorOf(version) >= 6) {
      return this.transport.call("sla.getsli", params, signal);
    }
    return this.transport.call("service.getsla", params, signal);
  }
  async getMacros(hostids, filter2, signal) {
    const params = {
      output: "extend",
      limit: this.metadataPageLimit
    };
    if (hostids?.length) params.hostids = hostids;
    if (filter2) params.search = { macro: filter2 };
    const rows = await this.cachedCall("usermacro.get", params, signal);
    return pageResult(rows, this.metadataPageLimit);
  }
  async getValueMaps(signal) {
    const rows = await this.cachedCall(
      "valuemap.get",
      {
        output: "extend",
        selectMappings: "extend",
        limit: this.metadataPageLimit
      },
      signal
    );
    return pageResult(rows, this.metadataPageLimit);
  }
  async getCurrentUser(signal) {
    const rows = await this.transport.call("user.get", { output: ["userid", "type", "roleid"] }, signal);
    return rows?.[0] ?? { userid: "" };
  }
  async getScripts(hostid, eventid, signal) {
    const params = {
      output: "extend",
      limit: this.metadataPageLimit
    };
    if (hostid) params.hostid = hostid;
    const rows = await this.cachedCall(
      "script.get",
      params,
      signal
    );
    return pageResult(rows, this.metadataPageLimit);
  }
  async getProblemDetail(eventid, signal) {
    if (!eventid) return null;
    const problems = await this.getProblems({ eventids: [eventid] }, signal);
    const problem = problems?.[0];
    if (!problem) return null;
    const triggerids = problem.objectid ? [String(problem.objectid)] : [];
    const version = await this.ver(signal);
    const caps2 = getZabbixVersionCapabilities(version);
    const triggersPage = triggerids.length ? await this.getTriggers(
      {
        triggerids,
        output: "extend",
        selectHosts: "extend",
        [caps2.triggerHostGroupsField]: "extend",
        selectItems: "extend",
        expandDescription: true,
        expandExpression: true
      },
      signal
    ) : pageResult([], this.metadataPageLimit);
    const triggerRows = typeof triggersPage === "number" ? [] : triggersPage.rows;
    const trigger = triggerRows[0] || {};
    const events = await this.getEvents(
      {
        eventids: [eventid],
        output: "extend",
        [caps2.acknowledgesField]: "extend",
        selectTags: "extend"
      },
      signal
    );
    const alerts = await this.transport.call(
      "alert.get",
      { eventids: [eventid], output: "extend" },
      signal
    );
    const groups = trigger.groups || trigger.hostgroups || [];
    return {
      ...problem,
      description: String(trigger.description ?? problem.name ?? ""),
      expression: String(trigger.expression ?? ""),
      opdata: String(trigger.opdata ?? ""),
      manual_close: trigger.manual_close != null ? String(trigger.manual_close) : problem.manual_close,
      hosts: trigger.hosts || problem.hosts || [],
      groups,
      items: trigger.items || [],
      tags: problem.tags || [],
      acknowledges: events?.[0]?.acknowledges || problem.acknowledges || [],
      events: events || [],
      alerts: alerts || []
    };
  }
  async acknowledgeEvent(payload, signal) {
    return this.transport.call("event.acknowledge", payload, signal);
  }
  async executeScript(payload, signal) {
    return this.transport.call("script.execute", payload, signal);
  }
}
function throwIfAborted(signal) {
  if (signal?.aborted) {
    throw new DataSourceError("CANCELLED", "数据源请求已取消");
  }
}
function historyPoints(itemid, from, to, count = 12) {
  const start = Number(from) || 0;
  const end = Number(to) || start + 3600;
  const step = Math.max(1, Math.floor((end - start) / Math.max(1, count - 1)));
  const points = [];
  for (let i = 0; i < count; i++) {
    const clock = String(start + i * step);
    points.push({ itemid, clock, ns: "0", value: String(10 + i) });
  }
  return points;
}
class OfflineZabbixTransport {
  constructor(scenario = "default") {
    this.scenario = scenario;
  }
  scenario;
  async getVersion(signal) {
    throwIfAborted(signal);
    if (this.scenario === "version-5") return "5.0.0";
    if (this.scenario === "version-6") return "6.0.0";
    if (this.scenario === "version-7") return "7.2.0";
    return "7.2.0";
  }
  async callWithFallback(method, params, fallback, _timeoutMs, signal) {
    try {
      return await this.call(method, params, signal);
    } catch (e) {
      const isAbort = e?.name === "AbortError" || e?.code === "ERR_CANCELED";
      if (isAbort) return fallback;
      throw e;
    }
  }
  async call(method, params = {}, signal) {
    throwIfAborted(signal);
    assertAllowedZabbixMethod(method);
    if (this.scenario === "error") {
      throw new DataSourceError(
        "UPSTREAM_ERROR",
        "offline fixture upstream error",
        { upstreamCode: 500 }
      );
    }
    if (this.scenario === "empty") {
      if (method === "apiinfo.version")
        return await this.getVersion(signal);
      return [];
    }
    switch (method) {
      case "apiinfo.version":
        return await this.getVersion(signal);
      case "hostgroup.get":
        return [
          { groupid: "g1", name: "Linux servers" },
          { groupid: "g2", name: "Windows servers" }
        ];
      case "host.get":
        return [
          { hostid: "h1", name: "web-01", host: "web-01", status: "0" },
          { hostid: "h2", name: "db-01", host: "db-01", status: "0" }
        ];
      case "application.get":
        return [{ applicationid: "a1", name: "CPU", hostid: "h1" }];
      case "item.get": {
        if (this.scenario === "partial") {
          return [
            {
              itemid: "i1",
              name: "CPU util",
              key_: "system.cpu.util",
              hostid: "h1",
              value_type: "0",
              units: "%",
              status: "0"
            }
          ];
        }
        return [
          {
            itemid: "i1",
            name: "CPU util",
            key_: "system.cpu.util",
            hostid: "h1",
            value_type: "0",
            units: "%",
            status: "0",
            tags: [{ tag: "env", value: "prod" }],
            hosts: [{ hostid: "h1", name: "web-01" }]
          },
          {
            itemid: "i2",
            name: "Agent version",
            key_: "agent.version",
            hostid: "h1",
            value_type: "1",
            status: "0"
          },
          {
            itemid: "i3",
            name: "System log",
            key_: "log[/var/log/syslog]",
            hostid: "h1",
            value_type: "2",
            status: "0"
          },
          {
            itemid: "i4",
            name: "Discovered FS",
            key_: "vfs.fs.size[/,pused]",
            hostid: "h1",
            value_type: "0",
            status: "0"
          }
        ];
      }
      case "discoveryrule.get":
        return [
          {
            itemid: "d1",
            name: "Mounted filesystem discovery",
            key_: "vfs.fs.discovery"
          }
        ];
      case "itemprototype.get":
        return [
          {
            itemid: "p1",
            ruleid: "d1",
            name: "Free disk space on {#FSNAME}",
            key_: "vfs.fs.size[{#FSNAME},pfree]"
          }
        ];
      case "history.get": {
        const itemids = params.itemids || ["i1"];
        const from = Number(params.time_from ?? 0);
        const to = Number(params.time_till ?? from + 3600);
        return itemids.flatMap((id) => historyPoints(id, from, to));
      }
      case "trend.get": {
        const itemids = params.itemids || ["i1"];
        const from = Number(params.time_from ?? 0);
        return itemids.map((itemid) => ({
          itemid,
          clock: String(from),
          num: "12",
          value_min: "1",
          value_avg: "5",
          value_max: "9"
        }));
      }
      case "problem.get":
        return [
          {
            eventid: "e1",
            objectid: "t1",
            name: "High CPU",
            severity: "3",
            clock: "1700000000",
            acknowledged: "0",
            hosts: [{ hostid: "h1", name: "web-01" }],
            tags: [{ tag: "scope", value: "availability" }]
          },
          {
            eventid: "e2",
            objectid: "t2",
            name: "Disk full",
            severity: "4",
            clock: "1700001000",
            acknowledged: "1",
            hosts: [{ hostid: "h2", name: "db-01" }],
            tags: []
          }
        ];
      case "event.get":
        return [
          {
            eventid: String(params.eventids?.[0] || "e1"),
            acknowledges: [{ acknowledgeid: "a1", message: "looking" }]
          }
        ];
      case "trigger.get":
        return [
          {
            triggerid: "t1",
            description: "High CPU",
            expression: "{web-01:system.cpu.util.last()}>90",
            opdata: "95%",
            hosts: [{ hostid: "h1", name: "web-01" }],
            groups: [{ groupid: "g1", name: "Linux servers" }],
            items: [
              {
                itemid: "i1",
                name: "CPU util",
                key_: "system.cpu.util",
                hostid: "h1",
                value_type: "0"
              }
            ]
          }
        ];
      case "alert.get":
        return [{ alertid: "al1", subject: "alert" }];
      case "service.get":
        return [{ serviceid: "s1", name: "Web SLA" }];
      case "sla.get":
      case "service.getsla":
        return [{ slaid: "sla1", name: "Availability", serviceid: "s1" }];
      case "sla.getsli":
        return [{ period: "1h", sli: 99.9 }];
      case "usermacro.get":
        return [{ hostmacroid: "m1", macro: "{$CPU.MAX}", value: "90" }];
      case "valuemap.get":
        return [
          {
            valuemapid: "vm1",
            name: "Service state",
            mappings: [{ value: "0", newvalue: "Down" }]
          }
        ];
      case "script.get":
        return [
          { scriptid: "sc1", name: "Ping", type: "0", execute_on: "0" }
        ];
      case "user.get":
        return [{ userid: "u1", type: "3", roleid: "r1" }];
      case "proxy.get":
        return [{ proxyid: "px1", host: "proxy-01", status: "5" }];
      case "event.acknowledge":
        return {
          eventids: params.eventids || [],
          preview: true
        };
      case "script.execute":
        return { response: "offline preview", preview: true };
      default:
        return [];
    }
  }
}
function pointKey(p) {
  return `${p.itemid}|${p.clock}|${p.ns ?? "0"}`;
}
function sortAndDedupeHistory(points) {
  const seen = /* @__PURE__ */ new Set();
  const out = [];
  const sorted = [...points].sort((a, b) => {
    if (a.itemid !== b.itemid)
      return String(a.itemid).localeCompare(String(b.itemid));
    const c = Number(a.clock) - Number(b.clock);
    if (c !== 0) return c;
    return Number(a.ns || 0) - Number(b.ns || 0);
  });
  for (const p of sorted) {
    const k = pointKey(p);
    if (seen.has(k)) continue;
    seen.add(k);
    out.push(p);
  }
  return out;
}
async function fetchHistoryRange(opts) {
  const pageLimit = Math.max(1, Math.floor(opts.pageLimit || 1e4));
  const maxRows = Math.max(1, Math.floor(opts.maxRows || pageLimit));
  const minSliceSec = Math.max(1, Math.floor(opts.minSliceSec ?? 1));
  let requests = 0;
  let truncated = false;
  async function loadSlice(fromSec, toSec) {
    if (opts.signal?.aborted) {
      const err = new Error("Aborted");
      err.name = "AbortError";
      throw err;
    }
    if (fromSec > toSec) return [];
    requests += 1;
    const rows = await opts.getHistory(
      opts.itemids,
      opts.history,
      fromSec,
      toSec,
      opts.signal,
      pageLimit
    ) || [];
    if (rows.length < pageLimit) {
      return rows;
    }
    const span = toSec - fromSec;
    if (span <= minSliceSec) {
      truncated = true;
      return rows.slice(0, pageLimit);
    }
    const mid = fromSec + Math.floor(span / 2);
    const left = await loadSlice(fromSec, mid);
    const right = await loadSlice(mid + 1, toSec);
    return left.concat(right);
  }
  const merged = sortAndDedupeHistory(
    await loadSlice(opts.fromSec, opts.toSec)
  );
  if (merged.length > maxRows) {
    truncated = true;
    return { points: merged.slice(0, maxRows), truncated: true, requests };
  }
  return { points: merged, truncated, requests };
}
async function mapPool(items, concurrency, worker) {
  const limit = Math.max(1, Math.floor(concurrency || 1));
  const results = new Array(items.length);
  let next = 0;
  async function run() {
    while (next < items.length) {
      const i = next++;
      results[i] = await worker(items[i], i);
    }
  }
  await Promise.all(
    Array.from({ length: Math.min(limit, items.length) }, () => run())
  );
  return results;
}
async function* fetchHistoryStream(opts) {
  const batchSize = Math.max(1, Math.floor(opts.batchSize || 25));
  const ids = opts.itemids.map(String);
  const accumulated = [];
  for (let i = 0; i < ids.length; i += batchSize) {
    if (opts.signal?.aborted) {
      const err = new Error("Aborted");
      err.name = "AbortError";
      throw err;
    }
    const batch = ids.slice(i, i + batchSize);
    const page = await opts.fetchBatch(batch) || [];
    accumulated.push(...page);
    const isLast = i + batchSize >= ids.length;
    yield {
      points: accumulated.slice(),
      partial: !isLast,
      batch
    };
  }
}
function clampLimit(n) {
  const v = Number(n ?? 100);
  if (!Number.isFinite(v)) return 100;
  return Math.min(1001, Math.max(1, Math.floor(v)));
}
function buildProblemsRequest(ctx, groupids, hostids, proxyids) {
  const opts = ctx.query.options || {};
  const show = ctx.query.showProblems || "problems";
  const params = {
    limit: clampLimit(opts.limit),
    output: "extend",
    selectTags: "extend"
  };
  if (groupids.length) params.groupids = groupids;
  if (hostids.length) params.hostids = hostids;
  if (proxyids?.length) params.proxyids = proxyids;
  if (opts.severities?.length) params.severities = opts.severities;
  else if (opts.minSeverity != null) {
    params.severities = [0, 1, 2, 3, 4, 5].filter(
      (s) => s >= Number(opts.minSeverity)
    );
  }
  if (opts.acknowledged === 0 || opts.acknowledged === 1) {
    params.acknowledged = Boolean(opts.acknowledged);
  }
  if (opts.hostsInMaintenance === false) params.maintenance = false;
  if (opts.hideAcknowledged) params.acknowledged = false;
  const tagsFilter = interpolateZabbixValue(
    String(ctx.query.tags?.filter || ""),
    ctx.scopedVars
  );
  if (tagsFilter) {
    params.tags = tagsFilter.split(",").map((part) => {
      const [tag, ...rest] = part.split(":");
      return { tag: tag.trim(), value: rest.join(":").trim(), operator: 0 };
    });
    params.evaltype = ctx.query.evaltype === "2" ? 2 : 0;
  }
  const triggerFilter = interpolateFilter(ctx.query.trigger, ctx.scopedVars);
  if (triggerFilter.filter) {
    params.search = { name: triggerFilter.filter };
    if (/[*%]/.test(triggerFilter.filter)) {
      params.searchWildcardsEnabled = true;
    }
  }
  if (opts.useTimeRange || show === "history") {
    params.time_from = Math.floor(
      (ctx.range.from instanceof Date ? ctx.range.from.getTime() : Number(ctx.range.from)) / 1e3
    );
    params.time_till = Math.floor(
      (ctx.range.to instanceof Date ? ctx.range.to.getTime() : Number(ctx.range.to)) / 1e3
    );
  }
  if (opts.sortProblems === "lastchange") {
    params.sortfield = ["eventid"];
  } else if (opts.sortProblems === "priority") {
    params.sortfield = ["severity", "eventid"];
    params.sortorder = "DESC";
  } else {
    params.sortfield = ["eventid"];
    params.sortorder = "DESC";
  }
  if (show === "history") {
    return {
      method: "event.get",
      params: {
        ...params,
        // event.get supports selectHosts; keep slim fields for table display.
        selectHosts: ["hostid", "name", "host"],
        object: 0,
        source: 0,
        value: opts.showOkEvents ? [0, 1] : 1
      }
    };
  }
  return {
    method: "problem.get",
    params: {
      ...params,
      recent: show === "recent"
      // never send selectHosts on problem.get
    }
  };
}
function sortProblems(rows, sortProblems2) {
  const list = [...rows];
  const mode2 = sortProblems2 || "default";
  list.sort((a, b) => {
    if (mode2 === "lastchange") {
      const c = Number(b.clock || 0) - Number(a.clock || 0);
      if (c !== 0) return c;
    } else if (mode2 === "priority") {
      const c = Number(b.severity || 0) - Number(a.severity || 0);
      if (c !== 0) return c;
      const t = Number(b.clock || 0) - Number(a.clock || 0);
      if (t !== 0) return t;
    } else {
      const c = Number(b.severity || 0) - Number(a.severity || 0);
      if (c !== 0) return c;
      const t = Number(b.clock || 0) - Number(a.clock || 0);
      if (t !== 0) return t;
    }
    return String(b.eventid || "").localeCompare(String(a.eventid || ""));
  });
  return list;
}
async function fetchHistoricalItemValues(ctx, rows) {
  const notices = [];
  const values = new Array(rows.length).fill(null);
  const concurrency = Number(ctx.settings.historyConcurrency) || 4;
  await mapPool(
    rows.map((r, index2) => ({ r, index: index2 })),
    concurrency,
    async ({ r, index: index2 }) => {
      try {
        const items = Array.isArray(r.items) ? r.items : [];
        const item = items[0];
        if (!item?.itemid) {
          values[index2] = null;
          return null;
        }
        const vt = Number(item.value_type ?? 0);
        const clock = Number(r.clock || 0);
        if (!clock) {
          values[index2] = null;
          return null;
        }
        const hist = await ctx.api.getHistory(
          [String(item.itemid)],
          vt,
          clock - 1,
          clock + 1,
          ctx.signal,
          1
        );
        const point = (hist || []).find((h) => Number(h.clock) <= clock) || hist?.[0];
        values[index2] = point?.value != null ? String(point.value) : null;
      } catch (e) {
        notices.push(
          `historical item value failed for event ${r.eventid}: ${e instanceof Error ? e.message : String(e)}`
        );
        values[index2] = null;
      }
      return null;
    }
  );
  return { values, notices };
}
async function enrichProblemsWithTriggers(ctx, rows) {
  if (!rows.length) return rows;
  const triggerids = [
    ...new Set(
      rows.map((r) => String(r.objectid || "")).filter((id) => id && id !== "0")
    )
  ];
  if (!triggerids.length) return rows;
  try {
    const page = await ctx.api.getTriggers(
      {
        triggerids,
        output: [
          "triggerid",
          "description",
          "comments",
          "priority",
          "value",
          "status",
          "state",
          "error",
          "url",
          "expression",
          "manual_close"
        ],
        selectHosts: ["hostid", "name", "host", "maintenance_status"],
        selectHostGroups: ["groupid", "name"],
        selectItems: ["itemid", "name", "key_", "lastvalue", "value_type"],
        expandDescription: true,
        limit: Math.min(1e3, Math.max(triggerids.length, 50))
      },
      ctx.signal
    );
    const list = Array.isArray(page) ? page : page?.rows || [];
    const byId2 = new Map(
      list.map((t) => [String(t.triggerid), t])
    );
    return rows.map((r) => {
      const t = byId2.get(String(r.objectid));
      if (!t) return r;
      const hosts = Array.isArray(r.hosts) && r.hosts.length ? r.hosts : t.hosts;
      const groups = Array.isArray(r.groups) && r.groups.length ? r.groups : t.groups || t.hostgroups;
      const items = Array.isArray(r.items) && r.items.length ? r.items : t.items;
      return {
        ...r,
        hosts: hosts || [],
        groups: groups || [],
        items: items || [],
        description: r.description || t.description,
        comments: r.comments || t.comments,
        url: r.url || t.url,
        expression: r.expression || t.expression,
        manual_close: r.manual_close ?? t.manual_close
      };
    });
  } catch {
    return rows;
  }
}
async function executeProblemsQuery(ctx) {
  assertBoundedHostScope(ctx.query, ctx.scopedVars);
  const opts = ctx.query.options || {};
  const show = ctx.query.showProblems || "problems";
  let groupids = [];
  let hostids = [];
  let proxyids = [];
  const needsMeta = Boolean(ctx.query.group?.filter) || Boolean(ctx.query.host?.filter) || Boolean(ctx.query.group?.ids?.length) || Boolean(ctx.query.host?.ids?.length) || Boolean(ctx.query.proxy?.filter) || Boolean(ctx.query.tags?.filter) || Boolean(ctx.query.application?.filter) || Boolean(ctx.query.item?.filter) || Boolean(ctx.query.itemTag?.filter) || Boolean(ctx.query.trigger?.filter);
  if (needsMeta) {
    const hostF = interpolateFilter(ctx.query.host, ctx.scopedVars);
    const groupF = interpolateFilter(ctx.query.group, ctx.scopedVars);
    const groupAll = isMatchAllZabbixFilter(groupF.filter) && !groupF.ids?.length;
    const hostAll = isMatchAllZabbixFilter(hostF.filter) && !hostF.ids?.length;
    const groups = groupAll ? [] : await resolveGroups(ctx.api, ctx.query, ctx.scopedVars, ctx.signal);
    if (!hostAll) {
      const hosts = await resolveHosts(
        ctx.api,
        ctx.query,
        ctx.scopedVars,
        groups.map((g) => g.groupid),
        ctx.signal
      );
      hostids = hosts.map((h) => String(h.hostid));
    }
    groupids = groups.map((g) => g.groupid);
  }
  if (opts.hostProxy || ctx.query.proxy?.filter) {
    const proxyFilter = interpolateFilter(ctx.query.proxy, ctx.scopedVars);
    if (proxyFilter.filter || proxyFilter.ids?.length) {
      const proxies = await ctx.api.getProxies(
        proxyFilter.filter || "",
        ctx.signal
      );
      const rows2 = Array.isArray(proxies) ? proxies : proxies.rows || [];
      proxyids = rows2.map((p) => String(p.proxyid));
      if (proxyFilter.ids?.length) proxyids = proxyFilter.ids.map(String);
    }
  }
  const built = buildProblemsRequest(ctx, groupids, hostids, proxyids);
  let rows = [];
  if (built.method === "event.get") {
    rows = await ctx.api.getEvents(built.params, ctx.signal) || [];
  } else {
    rows = await ctx.api.getProblems(built.params, ctx.signal) || [];
  }
  rows = await enrichProblemsWithTriggers(ctx, rows);
  rows = sortProblems(rows, opts.sortProblems);
  const limit = clampLimit(opts.limit);
  const truncated = rows.length >= limit;
  if (truncated) rows = rows.slice(0, limit);
  let historicalValues = rows.map(() => null);
  let notices = [];
  if (opts.fetchHistoricalItemValue) {
    const enriched = await mapPool(
      rows,
      Number(ctx.settings.historyConcurrency) || 4,
      async (r) => {
        if (r.items?.length) return r;
        if (!r.objectid) return r;
        try {
          const triggers = await ctx.api.getTriggers(
            {
              triggerids: [String(r.objectid)],
              output: ["triggerid"],
              selectItems: [
                "itemid",
                "name",
                "key_",
                "value_type",
                "lastvalue"
              ]
            },
            ctx.signal
          );
          const list = Array.isArray(triggers) ? triggers : triggers?.rows || [];
          return { ...r, items: list[0]?.items || [] };
        } catch {
          return r;
        }
      }
    );
    rows = enriched;
    const hist = await fetchHistoricalItemValues(ctx, rows);
    historicalValues = hist.values;
    notices = hist.notices;
  }
  return [
    createDataFrame({
      refId: ctx.query.refId,
      meta: {
        source: "live",
        datasourceUid: ctx.instance.uid,
        datasourceName: ctx.instance.name,
        preferredVisualisationType: "table",
        truncated,
        mode: show,
        notices: notices.map((text) => ({ severity: "warning", text }))
      },
      fields: [
        {
          name: "eventid",
          type: "string",
          values: rows.map((r) => String(r.eventid ?? ""))
        },
        {
          name: "objectid",
          type: "string",
          values: rows.map((r) => String(r.objectid ?? ""))
        },
        {
          name: "clock",
          type: "time",
          values: rows.map((r) => Number(r.clock || 0) * 1e3)
        },
        {
          name: "r_clock",
          type: "time",
          values: rows.map(
            (r) => r.r_clock ? Number(r.r_clock) * 1e3 : null
          )
        },
        {
          name: "name",
          type: "string",
          values: rows.map((r) => String(r.name ?? ""))
        },
        {
          name: "severity",
          type: "number",
          values: rows.map((r) => Number(r.severity ?? 0))
        },
        {
          name: "acknowledged",
          type: "string",
          values: rows.map((r) => String(r.acknowledged ?? "0"))
        },
        {
          name: "status",
          type: "string",
          values: rows.map((r) => String(r.r_eventid ? "resolved" : "problem"))
        },
        {
          name: "hosts",
          type: "string",
          values: rows.map(
            (r) => (Array.isArray(r.hosts) ? r.hosts : []).map((h) => String(h?.name || h?.host || h?.hostid || "")).filter(Boolean).join(", ")
          )
        },
        {
          name: "groups",
          type: "string",
          values: rows.map(
            (r) => (Array.isArray(r.groups) ? r.groups : []).map((g) => String(g?.name || g?.groupid || "")).filter(Boolean).join(", ")
          )
        },
        {
          name: "items",
          type: "string",
          values: rows.map(
            (r) => (Array.isArray(r.items) ? r.items : []).map((i) => String(i?.name || i?.key_ || i?.itemid || "")).filter(Boolean).slice(0, 5).join(", ")
          )
        },
        {
          name: "tags",
          type: "string",
          values: rows.map(
            (r) => (Array.isArray(r.tags) ? r.tags : []).map(
              (tg) => `${tg?.tag ?? ""}${tg?.value != null && tg?.value !== "" ? ":" + tg.value : ""}`
            ).filter(Boolean).slice(0, 10).join(", ")
          )
        },
        {
          name: "acknowledges",
          type: "string",
          values: rows.map(
            (r) => String(
              (Array.isArray(r.acknowledges) ? r.acknowledges : []).length
            )
          )
        },
        {
          name: "suppression_data",
          type: "string",
          values: rows.map(
            (r) => String(
              (Array.isArray(r.suppression_data) ? r.suppression_data : []).length
            )
          )
        },
        {
          name: "suppressed",
          type: "string",
          values: rows.map((r) => String(r.suppressed ?? "0"))
        },
        {
          name: "manual_close",
          type: "string",
          values: rows.map((r) => String(r.manual_close ?? ""))
        },
        {
          name: "events",
          type: "string",
          values: rows.map(
            (r) => String((Array.isArray(r.events) ? r.events : []).length)
          )
        },
        {
          name: "alerts",
          type: "string",
          values: rows.map(
            (r) => String((Array.isArray(r.alerts) ? r.alerts : []).length)
          )
        },
        {
          name: "opdata",
          type: "string",
          values: rows.map((r) => String(r.opdata ?? ""))
        },
        {
          name: "expression",
          type: "string",
          values: rows.map((r) => String(r.expression ?? ""))
        },
        {
          name: "description",
          type: "string",
          values: rows.map((r) => String(r.description ?? r.name ?? ""))
        },
        {
          name: "historicalItemValue",
          type: "string",
          values: historicalValues
        }
      ]
    })
  ];
}
async function executeAnnotationQuery(args) {
  const ann = args.annotation || {};
  const query = {
    ...DEFAULT_ZABBIX_QUERY,
    refId: "Anno",
    queryType: "5",
    group: { filter: String(ann.group || ann.groupFilter || "") },
    host: { filter: String(ann.host || ann.hostFilter || "") },
    showProblems: ann.showOkEvents ? "history" : "history",
    options: {
      ...DEFAULT_ZABBIX_QUERY.options,
      useTimeRange: true,
      showOkEvents: Boolean(ann.showOkEvents),
      hideAcknowledged: Boolean(ann.hideAcknowledged),
      showHostname: ann.showHostname !== false,
      minSeverity: ann.minSeverity != null ? Number(ann.minSeverity) : void 0,
      limit: Number(ann.limit) || 100
    }
  };
  const ctx = {
    api: args.api,
    instance: args.instance,
    settings: args.settings || {},
    query,
    range: args.range,
    maxDataPoints: 1e3,
    intervalMs: 1e3,
    scopedVars: {},
    signal: args.signal
  };
  const frames = await executeProblemsQuery(ctx);
  const src = frames[0];
  if (!src) return [];
  const n = src.fields[0]?.values?.length || 0;
  const times = [];
  const ends = [];
  const texts = [];
  const tags = [];
  const eventIds = [];
  const severities = [];
  const hosts = [];
  const acked = [];
  const status = [];
  const dsUids = [];
  for (let i = 0; i < n; i++) {
    const get = (name2) => src.fields.find((f) => f.name === name2)?.values?.[i];
    times.push(Number(get("clock") || 0));
    const rClock = get("r_clock");
    ends.push(rClock != null && Number(rClock) > 0 ? Number(rClock) : null);
    const hostRaw = get("hosts");
    let hostLabel = "";
    if (typeof hostRaw === "string" && hostRaw.trim()) {
      const s = hostRaw.trim();
      if (s.startsWith("[")) {
        try {
          const arr = JSON.parse(s);
          hostLabel = arr?.[0]?.name || arr?.[0]?.host || String(arr?.[0] || "");
        } catch {
          hostLabel = s.split(",")[0].trim();
        }
      } else {
        hostLabel = s.split(",")[0].trim();
      }
    } else if (Array.isArray(hostRaw)) {
      hostLabel = String(
        hostRaw[0]?.name || hostRaw[0]?.host || hostRaw[0] || ""
      );
    }
    const name = String(get("name") || "");
    texts.push(
      ann.showHostname !== false && hostLabel ? `${hostLabel}: ${name}` : name
    );
    tags.push(String(get("tags") || ""));
    eventIds.push(String(get("eventid") || ""));
    severities.push(Number(get("severity") || 0));
    hosts.push(hostLabel);
    acked.push(String(get("acknowledged") || "0"));
    status.push(String(get("status") || ""));
    dsUids.push(String(args.instance.uid || ""));
  }
  return [
    createDataFrame({
      fields: [
        { name: "Time", type: "time", values: times },
        { name: "TimeEnd", type: "time", values: ends },
        { name: "Text", type: "string", values: texts },
        { name: "Tags", type: "string", values: tags },
        { name: "EventId", type: "string", values: eventIds },
        { name: "Severity", type: "number", values: severities },
        { name: "Host", type: "string", values: hosts },
        { name: "Acknowledged", type: "string", values: acked },
        { name: "Status", type: "string", values: status },
        { name: "DatasourceUid", type: "string", values: dsUids }
      ]
    })
  ];
}
const ZABBIX_VALUE_TYPES = {
  0: {
    valueType: 0,
    history: 0,
    name: "float",
    fieldType: "number",
    supportsTrends: true
  },
  1: {
    valueType: 1,
    history: 1,
    name: "character",
    fieldType: "string",
    supportsTrends: false
  },
  2: {
    valueType: 2,
    history: 2,
    name: "log",
    fieldType: "string",
    supportsTrends: false
  },
  3: {
    valueType: 3,
    history: 3,
    name: "unsigned",
    fieldType: "number",
    supportsTrends: true
  },
  4: {
    valueType: 4,
    history: 4,
    name: "text",
    fieldType: "string",
    supportsTrends: false
  },
  5: {
    valueType: 5,
    history: 5,
    name: "binary",
    fieldType: "string",
    supportsTrends: false
  }
};
const NAME_TO_CODE = {
  float: 0,
  character: 1,
  log: 2,
  unsigned: 3,
  text: 4,
  binary: 5,
  "0": 0,
  "1": 1,
  "2": 2,
  "3": 3,
  "4": 4,
  "5": 5
};
function resolveValueTypeSpec(input, opts) {
  if (input == null || input === "") {
    if (opts?.allowUnknownAsFloat) return ZABBIX_VALUE_TYPES[0];
    throw new DataSourceError(
      "UNSUPPORTED_CAPABILITY",
      "item value_type is missing"
    );
  }
  if (typeof input === "number" && ZABBIX_VALUE_TYPES[input])
    return ZABBIX_VALUE_TYPES[input];
  const key = String(input).toLowerCase().trim();
  const code = NAME_TO_CODE[key];
  if (code != null && ZABBIX_VALUE_TYPES[code]) return ZABBIX_VALUE_TYPES[code];
  const n = Number(input);
  if (Number.isFinite(n) && ZABBIX_VALUE_TYPES[n]) return ZABBIX_VALUE_TYPES[n];
  if (opts?.allowUnknownAsFloat) return ZABBIX_VALUE_TYPES[0];
  throw new DataSourceError(
    "UNSUPPORTED_CAPABILITY",
    `unsupported Zabbix value_type: ${String(input)}`
  );
}
function mapHistoryRawValue(raw, spec) {
  if (raw == null || raw === "")
    return { value: null, valueRaw: raw == null ? null : "" };
  if (spec.name === "binary") {
    const s2 = String(raw);
    return { value: s2, valueRaw: s2, byteLength: s2.length };
  }
  if (spec.fieldType === "string") {
    const s2 = String(raw);
    return { value: s2, valueRaw: s2 };
  }
  if (typeof raw === "number") {
    if (!Number.isFinite(raw)) return { value: null, valueRaw: String(raw) };
    if (spec.name === "unsigned") {
      const s2 = String(Math.trunc(raw));
      if (!Number.isSafeInteger(raw)) {
        return {
          value: null,
          valueRaw: s2,
          notice: "unsigned exceeds JS safe integer; Value kept null"
        };
      }
      return { value: raw, valueRaw: s2 };
    }
    return { value: raw, valueRaw: String(raw) };
  }
  const s = String(raw).trim();
  if (!s) return { value: null, valueRaw: s };
  if (spec.name === "unsigned") {
    if (/^\d+$/.test(s)) {
      try {
        const bi = BigInt(s);
        if (bi > BigInt(Number.MAX_SAFE_INTEGER) || bi < BigInt(Number.MIN_SAFE_INTEGER)) {
          return {
            value: null,
            valueRaw: s,
            notice: "unsigned exceeds JS safe integer; Value kept null"
          };
        }
        const n2 = Number(bi);
        if (!Number.isSafeInteger(n2)) {
          return {
            value: null,
            valueRaw: s,
            notice: "unsigned exceeds JS safe integer; Value kept null"
          };
        }
        return { value: n2, valueRaw: s };
      } catch {
        return {
          value: null,
          valueRaw: s,
          notice: "unsigned parse failed; Value kept null"
        };
      }
    }
    return {
      value: null,
      valueRaw: s,
      notice: "unsigned parse failed; Value kept null"
    };
  }
  const n = Number(s);
  if (!Number.isFinite(n)) return { value: null, valueRaw: s };
  return { value: n, valueRaw: s };
}
function mapHistoryPoints(pts, spec) {
  const times = [];
  const values = [];
  const valueRaw = [];
  const ns = [];
  const timestamp = [];
  const source = [];
  const severity = [];
  const logeventid = [];
  const notices = [];
  for (const p of pts) {
    times.push(Number(p.clock) * 1e3 + Math.floor(Number(p.ns || 0) / 1e6));
    ns.push(p.ns == null ? null : String(p.ns));
    const raw = p.value_avg ?? p.value;
    const mapped = mapHistoryRawValue(raw, spec);
    if (mapped.notice) notices.push(mapped.notice);
    values.push(mapped.value);
    valueRaw.push(mapped.valueRaw);
    if (spec.name === "log") {
      timestamp.push(p.timestamp == null ? null : String(p.timestamp));
      source.push(p.source == null ? null : String(p.source));
      severity.push(p.severity == null ? null : String(p.severity));
      logeventid.push(p.logeventid == null ? null : String(p.logeventid));
    } else {
      timestamp.push(null);
      source.push(null);
      severity.push(null);
      logeventid.push(null);
    }
  }
  return {
    times,
    values,
    valueRaw,
    ns,
    log: { timestamp, source, severity, logeventid },
    notices,
    fieldType: spec.fieldType
  };
}
function parseIntervalMs(value) {
  const m = String(value || "").trim().match(/^(\d+(?:\.\d+)?)(ms|s|m|h|d|w|M)$/);
  if (!m) throw new DataSourceError("INVALID_QUERY", `非法 interval: ${value}`);
  const n = Number(m[1]);
  const unit = m[2];
  const scale = {
    ms: 1,
    s: 1e3,
    m: 6e4,
    h: 36e5,
    d: 864e5,
    w: 6048e5,
    M: 30 * 864e5
  };
  return n * scale[unit];
}
function finiteNumbers(values) {
  const out = [];
  for (const v of values) {
    if (v == null || v === "") continue;
    const n = typeof v === "number" ? v : Number(v);
    if (Number.isFinite(n)) out.push(n);
  }
  return out;
}
function percentileValue(values, p) {
  const nums = finiteNumbers(values).sort((a, b) => a - b);
  if (!nums.length) return null;
  const pct = Math.min(100, Math.max(0, p));
  const idx = (nums.length - 1) * (pct / 100);
  const lo = Math.floor(idx);
  const hi = Math.ceil(idx);
  if (lo === hi) return nums[lo];
  const w = idx - lo;
  return nums[lo] * (1 - w) + nums[hi] * w;
}
function aggregateValues(values, fn, percentile = 95) {
  if (fn === "percentile") return percentileValue(values, percentile);
  const nums = finiteNumbers(values);
  if (fn === "count") return nums.length;
  if (!nums.length) return null;
  switch (fn) {
    case "avg":
      return nums.reduce((a, b) => a + b, 0) / nums.length;
    case "min":
      return Math.min(...nums);
    case "max":
      return Math.max(...nums);
    case "sum":
      return nums.reduce((a, b) => a + b, 0);
    case "median":
      return percentileValue(nums, 50);
    case "first":
      return nums[0];
    case "last":
      return nums[nums.length - 1];
    default:
      return null;
  }
}
const FUNCTION_STAGES = {
  timeShift: "request",
  trendValue: "request",
  consolidateBy: "request",
  scale: "point",
  offset: "point",
  delta: "point",
  rate: "point",
  movingAverage: "point",
  exponentialMovingAverage: "point",
  percentile: "point",
  removeAboveValue: "point",
  removeBelowValue: "point",
  removeAbovePercentile: "point",
  removeBelowPercentile: "point",
  transformNull: "point",
  groupBy: "series",
  aggregateBy: "series",
  sumSeries: "series",
  percentileAgg: "series",
  top: "series",
  bottom: "series",
  sortSeries: "series",
  minSeries: "series",
  maxSeries: "series",
  avgSeries: "series",
  setAlias: "alias",
  setAliasByRegex: "alias",
  replaceAlias: "alias"
};
function parseTimeShiftMs(raw) {
  const s = String(raw || "0").trim();
  if (!s) return 0;
  if (s.startsWith("+")) return parseIntervalMs(s.slice(1));
  if (s.startsWith("-")) return -parseIntervalMs(s.slice(1));
  return -parseIntervalMs(s);
}
function planQueryFunctions(functions = []) {
  let timeShiftMs = 0;
  let trendValue = "avg";
  let consolidateBy = "";
  const postFetch = [];
  const stageByName = {};
  for (const fn of functions) {
    const stage = FUNCTION_STAGES[fn.name] || "point";
    stageByName[fn.name] = stage;
    if (fn.name === "timeShift") {
      timeShiftMs = parseTimeShiftMs(String(fn.params?.[0] ?? "0"));
      postFetch.push({
        name: "timeShift",
        params: [timeShiftMs === 0 ? "0s" : `${-timeShiftMs}ms`]
      });
      continue;
    }
    if (fn.name === "trendValue") {
      const v = String(
        fn.params?.[0] ?? "avg"
      );
      trendValue = ["avg", "min", "max", "sum", "count"].includes(v) ? v : "avg";
      continue;
    }
    if (fn.name === "consolidateBy") {
      consolidateBy = String(fn.params?.[0] ?? "avg");
      continue;
    }
    postFetch.push(fn);
  }
  return {
    timeShiftMs,
    displayShiftMs: -timeShiftMs,
    trendValue,
    consolidateBy,
    postFetchFunctions: postFetch,
    stageByName
  };
}
function applyPlanToRange(fromMs, toMs2, plan) {
  return {
    fromMs: fromMs + plan.timeShiftMs,
    toMs: toMs2 + plan.timeShiftMs
  };
}
function resolveAlignmentIntervalMs(args) {
  const candidates = [];
  if (args.intervalMs && args.intervalMs > 0)
    candidates.push(Math.floor(args.intervalMs));
  const range = Math.max(0, args.rangeToMs - args.rangeFromMs);
  const mdp = args.maxDataPoints && args.maxDataPoints > 0 ? args.maxDataPoints : 0;
  if (mdp > 0 && range > 0)
    candidates.push(Math.max(1, Math.floor(range / mdp)));
  if (args.itemDelay) {
    try {
      const d = String(args.itemDelay).trim();
      if (/^\d+$/.test(d)) candidates.push(Number(d) * 1e3);
      else candidates.push(parseIntervalMs(d));
    } catch {
    }
  }
  if (!candidates.length) {
    return range > 0 ? Math.max(1e3, Math.floor(range / 100)) : 1e3;
  }
  if (args.intervalMs && args.intervalMs > 0) {
    return Math.max(1, Math.floor(args.intervalMs));
  }
  return Math.max(1, Math.min(...candidates));
}
function sanitizeTagName(name) {
  return name.replace(/[^A-Za-z0-9_]/g, "_");
}
function aliasContext(series) {
  const host = series.item.hosts?.[0];
  const ctx = {
    __zbx_host_name: String(host?.name || host?.host || ""),
    __zbx_host_id: String(host?.hostid || series.item.hostid || ""),
    __zbx_item_name: String(series.item.name || ""),
    __zbx_item_id: String(series.item.itemid || ""),
    __zbx_item_key: String(series.item.key_ || "")
  };
  const tagMap = /* @__PURE__ */ new Map();
  for (const t of series.item.tags || []) {
    if (!t.tag) continue;
    const key = sanitizeTagName(t.tag);
    const list = tagMap.get(key) || [];
    list.push(String(t.value ?? ""));
    tagMap.set(key, list);
  }
  for (const [k, vals] of tagMap) {
    ctx[`__zbx_item_tag_${k}`] = vals.join(", ");
  }
  return ctx;
}
function expand(template, ctx) {
  return String(template || "").replace(
    /\$([A-Za-z_][\w]*)/g,
    (token, name) => name in ctx ? ctx[name] : token
  );
}
function applyAliasFunction(series, name, params) {
  const ctx = aliasContext(series);
  const current = series.name || series.item.name || series.item.key_;
  if (name === "setAlias") {
    return { ...series, name: expand(String(params[0] ?? ""), ctx) };
  }
  if (name === "setAliasByRegex") {
    try {
      const re = new RegExp(String(params[0] ?? ""));
      const repl = String(params[1] ?? "");
      return { ...series, name: expand(current.replace(re, repl), ctx) };
    } catch {
      throw new DataSourceError("INVALID_QUERY", "setAliasByRegex 正则无效");
    }
  }
  if (name === "replaceAlias") {
    try {
      const re = new RegExp(String(params[0] ?? ""), "g");
      return {
        ...series,
        name: expand(current.replace(re, String(params[1] ?? "")), ctx)
      };
    } catch {
      throw new DataSourceError("INVALID_QUERY", "replaceAlias 正则无效");
    }
  }
  return series;
}
function bucketSeries(series, intervalMs, fn) {
  if (intervalMs <= 0) return series;
  const buckets = /* @__PURE__ */ new Map();
  for (const p of series.points) {
    const key = Math.floor(p.time / intervalMs) * intervalMs;
    const list = buckets.get(key) || [];
    list.push(
      typeof p.value === "number" ? p.value : p.value == null ? null : Number(p.value)
    );
    buckets.set(key, list);
  }
  const points = [...buckets.entries()].sort((a, b) => a[0] - b[0]).map(([time, values]) => ({ time, value: aggregateValues(values, fn) }));
  return { ...series, points };
}
function alignSeries(series, fromMs, toMs2, intervalMs) {
  if (intervalMs <= 0) return series;
  const map = /* @__PURE__ */ new Map();
  for (const p of series.points) {
    const key = Math.floor(p.time / intervalMs) * intervalMs;
    if (!map.has(key)) map.set(key, p.value);
  }
  const points = [];
  for (let t = Math.floor(fromMs / intervalMs) * intervalMs; t <= toMs2; t += intervalMs) {
    points.push({ time: t, value: map.has(t) ? map.get(t) : null });
  }
  return { ...series, points };
}
function consolidateSeries(series, maxDataPoints, fn) {
  const max = Math.max(2, maxDataPoints || 2);
  if (series.points.length <= max) return series;
  const first = series.points[0].time;
  const last = series.points[series.points.length - 1].time;
  const intervalMs = Math.max(1, Math.ceil((last - first) / max));
  return bucketSeries(series, intervalMs, fn);
}
function buildValueMapLookup(valueMaps) {
  const map = /* @__PURE__ */ new Map();
  for (const vm of valueMaps || []) {
    const id = String(vm.valuemapid || "");
    if (!id) continue;
    map.set(id, [...vm.mappings || []]);
  }
  return map;
}
function mapSeriesValue(raw, valuemapid, lookup) {
  if (raw == null || !valuemapid) return raw;
  const table = lookup.get(String(valuemapid));
  if (!table) return raw;
  if (!Array.isArray(table)) {
    const key2 = String(raw);
    return key2 in table ? table[key2] : raw;
  }
  const key = String(raw);
  const num = typeof raw === "number" ? raw : Number(raw);
  for (const m of table) {
    const type = String(m.type ?? "0");
    if (type === "0" || m.type == null) {
      if (m.value != null && String(m.value) === key) return m.newvalue ?? raw;
      if (m.value && Number.isFinite(num)) {
        const rangeMatch = String(m.value).match(
          /^(-?\d+(?:\.\d+)?)-(-?\d+(?:\.\d+)?)$/
        );
        if (rangeMatch) {
          const lo = Number(rangeMatch[1]);
          const hi = Number(rangeMatch[2]);
          if (num >= lo && num <= hi) return m.newvalue ?? raw;
        }
      }
    }
    if (type === "1" || type === "range") {
      const parts = String(m.value || "").split(/[,:]/);
      if (parts.length >= 2 && Number.isFinite(num)) {
        const lo = Number(parts[0]);
        const hi = Number(parts[1]);
        if (num >= lo && num <= hi) return m.newvalue ?? raw;
      }
    }
    if (type === "2" || type === "regexp") {
      try {
        if (m.value && new RegExp(String(m.value)).test(key))
          return m.newvalue ?? raw;
      } catch {
      }
    }
    if (m.value != null && String(m.value) === key) return m.newvalue ?? raw;
  }
  return raw;
}
function emptyFrame(refId, notice) {
  const frame = createDataFrame({
    refId,
    fields: [
      { name: "Time", type: "time", values: [] },
      { name: "Value", type: "number", values: [] }
    ]
  });
  if (notice)
    frame.meta = { notices: [{ severity: "warning", text: notice }] };
  return frame;
}
function itemLabel(item) {
  const host = item.hosts?.[0]?.name || item.hosts?.[0]?.host || "";
  return host ? `${host}: ${item.name}` : item.name || item.key_;
}
function seriesToDataFrame(series, refId, datasourceUid, valueMaps) {
  const times = series.points.map((p) => p.time);
  let values = series.points.map((p) => p.value);
  if (valueMaps && series.item.valuemapid) {
    values = values.map(
      (v) => mapSeriesValue(v, series.item.valuemapid, valueMaps)
    );
  }
  const asString = values.some((v) => typeof v === "string");
  const display = series.name || itemLabel(series.item);
  const fields = [
    { name: "Time", type: "time", values: times },
    {
      name: "Value",
      type: asString ? "string" : "number",
      values: asString ? values.map((v) => v == null ? null : String(v)) : values.map((v) => v == null || v === "" ? null : Number(v)),
      labels: {
        itemid: series.item.itemid,
        item: series.item.name,
        host: series.item.hosts?.[0]?.name || ""
      },
      config: {
        displayNameFromDS: display,
        ...series.item.units ? { unit: series.item.units } : {}
      }
    }
  ];
  if (series.points.some((p) => p.valueRaw != null && p.valueRaw !== "")) {
    fields.push({
      name: "ValueRaw",
      type: "string",
      values: series.points.map(
        (p) => p.valueRaw == null ? null : String(p.valueRaw)
      )
    });
  }
  if (series.meta?.source === "trend") {
    fields.push(
      {
        name: "TrendMin",
        type: "number",
        values: series.points.map(
          (p) => p.value_min == null ? null : Number(p.value_min)
        )
      },
      {
        name: "TrendAvg",
        type: "number",
        values: series.points.map(
          (p) => p.value_avg == null ? null : Number(p.value_avg)
        )
      },
      {
        name: "TrendMax",
        type: "number",
        values: series.points.map(
          (p) => p.value_max == null ? null : Number(p.value_max)
        )
      },
      {
        name: "TrendNum",
        type: "number",
        values: series.points.map(
          (p) => p.num == null ? null : Number(p.num)
        )
      }
    );
  }
  if (series.points.some(
    (p) => p.logeventid != null || p.source != null || p.severity != null
  )) {
    fields.push(
      {
        name: "timestamp",
        type: "string",
        values: series.points.map((p) => p.timestamp ?? null)
      },
      {
        name: "source",
        type: "string",
        values: series.points.map((p) => p.source ?? null)
      },
      {
        name: "severity",
        type: "string",
        values: series.points.map((p) => p.severity ?? null)
      },
      {
        name: "logeventid",
        type: "string",
        values: series.points.map((p) => p.logeventid ?? null)
      },
      {
        name: "ns",
        type: "string",
        values: series.points.map((p) => p.ns ?? null)
      }
    );
  }
  const frame = createDataFrame({
    refId,
    name: display,
    fields
  });
  frame.meta = {
    ...frame.meta,
    source: "live",
    datasourceUid,
    custom: {
      source: "zabbix",
      itemid: series.item.itemid,
      datasourceUid
    },
    notices: (series.notices || []).map((text) => ({
      severity: "warning",
      text
    }))
  };
  return frame;
}
function seriesListToFrames(series, refId, datasourceUid, valueMaps) {
  return series.map(
    (s) => seriesToDataFrame(s, refId, datasourceUid, valueMaps)
  );
}
function seriesToFrames(series, refId) {
  return seriesListToFrames(series, refId, "");
}
function emptyItem(name) {
  return { itemid: name, name, key_: name, hostid: "", value_type: "0" };
}
function seriesScore(s, fn) {
  const v = aggregateValues(
    s.points.map((p) => p.value),
    fn
  );
  return v == null ? Number.NEGATIVE_INFINITY : v;
}
function sumSeries(list) {
  if (!list.length) return [];
  const indices = list.map((s) => {
    const m = /* @__PURE__ */ new Map();
    for (const p of s.points) m.set(p.time, p.value);
    return m;
  });
  const times = /* @__PURE__ */ new Set();
  for (const s of list) for (const p of s.points) times.add(p.time);
  const sorted = [...times].sort((a, b) => a - b);
  const points = sorted.map((time) => {
    let sum = 0;
    let any = false;
    for (const idx of indices) {
      const v = idx.get(time);
      if (v == null || v === "") continue;
      sum += Number(v);
      any = true;
    }
    return { time, value: any ? sum : null };
  });
  return [
    {
      item: emptyItem("sum"),
      name: "sum",
      points,
      meta: { derived: true, sources: list.map((s) => s.item.itemid) }
    }
  ];
}
function aggregateSeries(list, fn) {
  if (!list.length) return [];
  const indices = list.map((s) => {
    const m = /* @__PURE__ */ new Map();
    for (const p of s.points) m.set(p.time, p.value);
    return m;
  });
  const times = /* @__PURE__ */ new Set();
  for (const s of list) for (const p of s.points) times.add(p.time);
  const sorted = [...times].sort((a, b) => a - b);
  const points = sorted.map((time) => {
    const values = indices.map((idx) => idx.get(time) ?? null);
    return { time, value: aggregateValues(values, fn) };
  });
  return [
    {
      item: emptyItem(fn),
      name: fn,
      points,
      meta: { derived: true, sources: list.map((s) => s.item.itemid) }
    }
  ];
}
function aggregateAcrossSeries(list, interval, fn, percent) {
  if (!list.length) return [];
  const intervalMs = parseIntervalMs(interval || "1m");
  const buckets = /* @__PURE__ */ new Map();
  for (const s of list) {
    for (const p of s.points) {
      const key = Math.floor(p.time / intervalMs) * intervalMs;
      const arr = buckets.get(key) || [];
      arr.push(p.value == null || p.value === "" ? null : Number(p.value));
      buckets.set(key, arr);
    }
  }
  const points = [...buckets.entries()].sort((a, b) => a[0] - b[0]).map(([time, values]) => ({
    time,
    value: fn === "percentile" ? aggregateValues(values, "percentile", percent ?? 95) : aggregateValues(values, fn)
  }));
  return [
    {
      item: emptyItem(
        fn === "percentile" ? `percentileAgg(${percent})` : `aggregateBy(${fn})`
      ),
      name: fn === "percentile" ? `percentileAgg(${percent})` : `aggregateBy(${fn})`,
      points,
      meta: {
        derived: true,
        acrossSeries: true,
        sources: list.map((s) => s.item.itemid)
      }
    }
  ];
}
function percentileAgg(list, interval, percent) {
  return aggregateAcrossSeries(list, interval, "percentile", percent);
}
function aggregateByAcross(list, interval, fn) {
  return aggregateAcrossSeries(list, interval, fn);
}
function topSeries(list, n, by = "avg") {
  const scored = [...list].sort(
    (a, b) => seriesScore(b, by) - seriesScore(a, by)
  );
  return scored.slice(0, Math.max(0, Math.floor(n)));
}
function bottomSeries(list, n, by = "avg") {
  const scored = [...list].sort(
    (a, b) => seriesScore(a, by) - seriesScore(b, by)
  );
  return scored.slice(0, Math.max(0, Math.floor(n)));
}
function sortSeriesList(list, direction = "asc") {
  const dir = direction === "desc" ? -1 : 1;
  return [...list].sort((a, b) => {
    const na = (a.name || a.item.name || "").localeCompare(
      b.name || b.item.name || ""
    );
    if (na !== 0) return na * dir;
    return String(a.item.itemid).localeCompare(String(b.item.itemid)) * dir;
  });
}
function filterByName(list, pattern) {
  const re = new RegExp(pattern);
  return list.filter((s) => re.test(s.name || s.item.name || s.item.key_));
}
function timeShift(list, offsetMs) {
  return list.map((s) => ({
    ...s,
    points: s.points.map((p) => ({
      ...p,
      time: p.time + offsetMs,
      value: p.value
    }))
  }));
}
function clone(series, points = series.points) {
  return { ...series, points: points.map((p) => ({ ...p })) };
}
function transformGroupBy(series, interval, fn) {
  return bucketSeries(series, parseIntervalMs(interval), fn);
}
function transformScale(series, factor) {
  return clone(
    series,
    series.points.map((p) => ({
      time: p.time,
      value: p.value == null || p.value === "" ? null : Number(p.value) * factor
    }))
  );
}
function transformOffset(series, offset) {
  return clone(
    series,
    series.points.map((p) => ({
      time: p.time,
      value: p.value == null || p.value === "" ? null : Number(p.value) + offset
    }))
  );
}
function transformDelta(series) {
  const points = series.points.map((p, i) => {
    if (i === 0 || p.value == null || series.points[i - 1].value == null)
      return { time: p.time, value: null };
    return {
      time: p.time,
      value: Number(p.value) - Number(series.points[i - 1].value)
    };
  });
  return clone(series, points);
}
function transformRate(series) {
  let lastRate = null;
  const points = series.points.map((p, i) => {
    if (i === 0 || p.value == null || series.points[i - 1].value == null)
      return { time: p.time, value: null };
    const dt = (p.time - series.points[i - 1].time) / 1e3;
    if (dt <= 0) return { time: p.time, value: null };
    const curr = Number(p.value);
    const prev = Number(series.points[i - 1].value);
    if (curr < prev) return { time: p.time, value: lastRate };
    const rate = (curr - prev) / dt;
    lastRate = rate;
    return { time: p.time, value: rate };
  });
  return clone(series, points);
}
function transformMovingAverage(series, window2) {
  const w = Math.max(1, Math.floor(window2));
  const points = series.points.map((p, i) => {
    const slice = series.points.slice(Math.max(0, i - w + 1), i + 1).map((x) => x.value);
    return { time: p.time, value: aggregateValues(slice, "avg") };
  });
  return clone(series, points);
}
function transformExponentialMovingAverage(series, window2) {
  const n = Number(window2);
  let alpha2;
  let seedCount;
  if (Number.isFinite(n) && n > 0 && n < 1) {
    alpha2 = n;
    seedCount = Math.max(1, Math.ceil(1 / alpha2));
  } else {
    const w = Math.max(1, n || 1);
    alpha2 = 2 / (w + 1);
    seedCount = Math.max(1, Math.floor(w));
  }
  let prev = null;
  const seed = [];
  const points = series.points.map((p) => {
    if (p.value == null || p.value === "") return { time: p.time, value: null };
    const v = Number(p.value);
    if (prev == null) {
      seed.push(v);
      if (seed.length < seedCount) {
        if (seed.length === 1) {
          prev = v;
          return { time: p.time, value: v };
        }
        const sma2 = seed.reduce((a, b) => a + b, 0) / seed.length;
        prev = sma2;
        return { time: p.time, value: sma2 };
      }
      const sma = seed.reduce((a, b) => a + b, 0) / seed.length;
      prev = sma;
      return { time: p.time, value: sma };
    }
    prev = alpha2 * v + (1 - alpha2) * prev;
    return { time: p.time, value: prev };
  });
  return clone(series, points);
}
function transformPercentile(series, interval, p) {
  return bucketSeries(series, parseIntervalMs(interval), "avg").points ? (() => {
    const intervalMs = parseIntervalMs(interval);
    const buckets = /* @__PURE__ */ new Map();
    for (const pt of series.points) {
      const key = Math.floor(pt.time / intervalMs) * intervalMs;
      const list = buckets.get(key) || [];
      list.push(pt.value == null ? null : Number(pt.value));
      buckets.set(key, list);
    }
    const points = [...buckets.entries()].sort((a, b) => a[0] - b[0]).map(([time, values]) => ({
      time,
      value: aggregateValues(values, "percentile", p)
    }));
    return clone(series, points);
  })() : series;
}
function transformRemoveAboveValue(series, threshold) {
  return clone(
    series,
    series.points.map((p) => ({
      time: p.time,
      value: p.value != null && Number(p.value) > threshold ? null : p.value
    }))
  );
}
function transformRemoveBelowValue(series, threshold) {
  return clone(
    series,
    series.points.map((p) => ({
      time: p.time,
      value: p.value != null && Number(p.value) < threshold ? null : p.value
    }))
  );
}
function transformRemoveAbovePercentile(series, p) {
  const thr = aggregateValues(
    series.points.map((x) => x.value),
    "percentile",
    p
  );
  if (thr == null) return series;
  return transformRemoveAboveValue(series, thr);
}
function transformRemoveBelowPercentile(series, p) {
  const thr = aggregateValues(
    series.points.map((x) => x.value),
    "percentile",
    p
  );
  if (thr == null) return series;
  return transformRemoveBelowValue(series, thr);
}
function transformNull(series, fill) {
  return {
    ...series,
    points: series.points.map((p) => ({
      ...p,
      value: p.value == null || p.value === "" ? fill : p.value
    }))
  };
}
function applyTransformFunction(series, name, params) {
  switch (name) {
    case "groupBy":
      return transformGroupBy(
        series,
        String(params[0] || "1m"),
        String(params[1] || "avg")
      );
    case "scale":
      return transformScale(series, Number(params[0] ?? 1));
    case "offset":
      return transformOffset(series, Number(params[0] ?? 0));
    case "delta":
      return transformDelta(series);
    case "rate":
      return transformRate(series);
    case "movingAverage":
      return transformMovingAverage(series, Number(params[0] ?? 1));
    case "exponentialMovingAverage":
      return transformExponentialMovingAverage(series, Number(params[0] ?? 1));
    case "percentile":
      return transformPercentile(
        series,
        String(params[0] || "1m"),
        Number(params[1] ?? 95)
      );
    case "removeAboveValue":
      return transformRemoveAboveValue(series, Number(params[0]));
    case "removeBelowValue":
      return transformRemoveBelowValue(series, Number(params[0]));
    case "removeAbovePercentile":
      return transformRemoveAbovePercentile(series, Number(params[0] ?? 95));
    case "transformNull":
      return transformNull(series, Number(params[0] ?? 0));
    case "removeBelowPercentile":
      return transformRemoveBelowPercentile(series, Number(params[0] ?? 5));
    default:
      throw new DataSourceError(
        "INVALID_QUERY",
        `未知 transform 函数: ${name}`
      );
  }
}
const POINT_FNS = /* @__PURE__ */ new Set([
  "scale",
  "offset",
  "delta",
  "rate",
  "movingAverage",
  "exponentialMovingAverage",
  "percentile",
  "removeAboveValue",
  "removeBelowValue",
  "removeAbovePercentile",
  "removeBelowPercentile",
  "transformNull"
]);
function runProcessingPipeline(seriesList, opts) {
  let list = seriesList.map((s) => ({
    ...s,
    item: { ...s.item },
    name: s.name || s.item.name,
    notices: [...s.notices || []],
    meta: { ...s.meta || {} }
  }));
  const plan = planQueryFunctions(opts.query.functions || []);
  const functions = opts.functionsOverride || (opts.requestPlanApplied ? plan.postFetchFunctions : (opts.query.functions || []).filter(
    (f) => f.name !== "trendValue" && f.name !== "consolidateBy"
  ));
  const notices = [];
  const nonAlias = functions.filter(
    (f) => !["setAlias", "setAliasByRegex", "replaceAlias"].includes(f.name)
  );
  const aliasFns = functions.filter(
    (f) => ["setAlias", "setAliasByRegex", "replaceAlias"].includes(f.name)
  );
  const ordered = [...nonAlias, ...aliasFns];
  for (const fn of ordered) {
    try {
      if (POINT_FNS.has(fn.name)) {
        if (opts.allowNumericOnly === false) {
          notices.push(`函数 ${fn.name} 已跳过（非数值查询）`);
          continue;
        }
        list = list.map((s) => applyTransformFunction(s, fn.name, fn.params));
        continue;
      }
      if (fn.name === "groupBy") {
        list = list.map((s) => applyTransformFunction(s, "groupBy", fn.params));
        continue;
      }
      if (fn.name === "aggregateBy") {
        list = aggregateByAcross(
          list,
          String(fn.params[0] || "1m"),
          String(fn.params[1] || "avg")
        );
        continue;
      }
      if (fn.name === "sumSeries") {
        list = sumSeries(list);
        continue;
      }
      if (fn.name === "percentileAgg") {
        list = percentileAgg(
          list,
          String(fn.params[0] || "1m"),
          Number(fn.params[1] ?? 95)
        );
        continue;
      }
      if (fn.name === "top") {
        list = topSeries(
          list,
          Number(fn.params[0] ?? 5),
          String(fn.params[1] || "avg")
        );
        continue;
      }
      if (fn.name === "bottom") {
        list = bottomSeries(
          list,
          Number(fn.params[0] ?? 5),
          String(fn.params[1] || "avg")
        );
        continue;
      }
      if (fn.name === "sortSeries") {
        list = sortSeriesList(
          list,
          String(fn.params[0] || "asc") || "asc"
        );
        continue;
      }
      if (fn.name === "minSeries" || fn.name === "maxSeries" || fn.name === "avgSeries") {
        const agg = fn.name.replace("Series", "");
        list = aggregateSeries(list, agg === "avg" ? "avg" : agg);
        continue;
      }
      if (fn.name === "timeShift") {
        const raw = String(fn.params[0] || "0s");
        let signed;
        if (/^-?\d+(\.\d+)?ms$/i.test(raw)) {
          signed = Number(raw.replace(/ms$/i, ""));
        } else if (raw.startsWith("+")) {
          signed = parseIntervalMs(raw.slice(1));
        } else if (raw.startsWith("-")) {
          signed = -parseIntervalMs(raw.slice(1));
        } else {
          signed = -parseIntervalMs(raw);
        }
        list = timeShift(list, signed);
        continue;
      }
      if (fn.name === "setAlias" || fn.name === "setAliasByRegex" || fn.name === "replaceAlias") {
        list = list.map(
          (s) => applyAliasFunction(s, fn.name, fn.params)
        );
        continue;
      }
      if (fn.name === "filterByName" || fn.name === "excludeByName") {
        const pattern = String(fn.params[0] || ".*");
        list = fn.name === "excludeByName" ? list.filter(
          (s) => !new RegExp(pattern).test(s.name || s.item.name)
        ) : filterByName(list, pattern);
        continue;
      }
      if (fn.name === "trendValue" || fn.name === "consolidateBy") {
        continue;
      }
      notices.push(`未知函数 ${fn.name} 已忽略`);
    } catch (e) {
      const msg = e instanceof Error ? e.message : String(e);
      notices.push(msg);
      if (e instanceof DataSourceError && e.code === "INVALID_QUERY") ;
    }
  }
  const consolidateFn = plan.consolidateBy || "avg";
  list = list.map(
    (s) => consolidateSeries(s, opts.maxDataPoints, consolidateFn)
  );
  const disableAlign = opts.disableDataAlignment || opts.query.options?.disableDataAlignment || false;
  if (!disableAlign && list.length) {
    const delay = list[0]?.item?.delay != null ? String(list[0].item.delay) : void 0;
    const intervalMs = resolveAlignmentIntervalMs({
      intervalMs: opts.intervalMs,
      rangeFromMs: opts.rangeFromMs,
      rangeToMs: opts.rangeToMs,
      maxDataPoints: opts.maxDataPoints,
      itemDelay: delay
    });
    list = list.map(
      (s) => alignSeries(s, opts.rangeFromMs, opts.rangeToMs, intervalMs)
    );
  }
  const useMap = Boolean(opts.query.options?.useZabbixValueMapping);
  const referenced = new Set(
    list.map((s) => String(s.item.valuemapid || "")).filter(Boolean)
  );
  const filteredMaps = (opts.valueMaps || []).filter(
    (vm) => referenced.has(String(vm.valuemapid || ""))
  );
  const lookup = useMap ? buildValueMapLookup(filteredMaps) : void 0;
  const frames = seriesListToFrames(
    list,
    opts.query.refId,
    opts.datasourceUid,
    lookup
  );
  if (notices.length && frames[0]) {
    const meta2 = frames[0].meta ||= {};
    meta2.notices = [
      ...meta2.notices || [],
      ...notices.map((text) => ({ severity: "warning", text }))
    ];
  }
  return frames;
}
async function runProcessingPipelineAsync(seriesList, opts, signal) {
  const canYield = typeof window !== "undefined" && typeof requestAnimationFrame === "function";
  function yield_() {
    if (!canYield) return;
    if (signal?.aborted) throw new DOMException("Aborted", "AbortError");
    return new Promise((r) => setTimeout(r, 0));
  }
  let list = seriesList.map((s) => ({
    ...s,
    item: { ...s.item },
    name: s.name || s.item.name,
    notices: [...s.notices || []],
    meta: { ...s.meta || {} }
  }));
  const plan = planQueryFunctions(opts.query.functions || []);
  const functions = opts.functionsOverride || plan.postFetchFunctions;
  const notices = [];
  const nonAlias = functions.filter(
    (f) => !["setAlias", "setAliasByRegex", "replaceAlias"].includes(f.name)
  );
  const aliasFns = functions.filter(
    (f) => ["setAlias", "setAliasByRegex", "replaceAlias"].includes(f.name)
  );
  const ordered = [...nonAlias, ...aliasFns];
  for (const fn of ordered) {
    try {
      if (POINT_FNS.has(fn.name)) {
        if (opts.allowNumericOnly === false) {
          notices.push(`函数 ${fn.name} 已跳过（非数值查询）`);
          continue;
        }
        list = list.map((s) => applyTransformFunction(s, fn.name, fn.params));
        await yield_();
        continue;
      }
      if (fn.name === "groupBy") {
        list = list.map((s) => applyTransformFunction(s, "groupBy", fn.params));
        await yield_();
        continue;
      }
      if (fn.name === "aggregateBy") {
        list = aggregateByAcross(list, String(fn.params[0] || "1m"), String(fn.params[1] || "avg"));
        await yield_();
        continue;
      }
      if (fn.name === "sumSeries") {
        list = sumSeries(list);
        await yield_();
        continue;
      }
      if (fn.name === "percentileAgg") {
        list = percentileAgg(list, String(fn.params[0] || "1m"), Number(fn.params[1] ?? 95));
        await yield_();
        continue;
      }
      if (fn.name === "top") {
        list = topSeries(list, Number(fn.params[0] ?? 5), String(fn.params[1] || "avg"));
        await yield_();
        continue;
      }
      if (fn.name === "bottom") {
        list = bottomSeries(list, Number(fn.params[0] ?? 5), String(fn.params[1] || "avg"));
        await yield_();
        continue;
      }
      if (fn.name === "sortSeries") {
        list = sortSeriesList(list, String(fn.params[0] || "asc") || "asc");
        continue;
      }
      if (fn.name === "minSeries" || fn.name === "maxSeries" || fn.name === "avgSeries") {
        const agg = fn.name.replace("Series", "");
        list = aggregateSeries(list, agg === "avg" ? "avg" : agg);
        await yield_();
        continue;
      }
      if (fn.name === "timeShift") {
        const raw = String(fn.params[0] || "0s");
        let signed;
        if (/^-?\d+(\.\d+)?ms$/i.test(raw)) signed = Number(raw.replace(/ms$/i, ""));
        else if (raw.startsWith("+")) signed = parseIntervalMs(raw.slice(1));
        else if (raw.startsWith("-")) signed = -parseIntervalMs(raw.slice(1));
        else signed = -parseIntervalMs(raw);
        list = timeShift(list, signed);
        continue;
      }
      if (fn.name === "setAlias" || fn.name === "setAliasByRegex" || fn.name === "replaceAlias") {
        list = list.map((s) => applyAliasFunction(s, fn.name, fn.params));
        continue;
      }
      if (fn.name === "filterByName" || fn.name === "excludeByName") {
        const pattern = String(fn.params[0] || ".*");
        list = fn.name === "excludeByName" ? list.filter((s) => !new RegExp(pattern).test(s.name || s.item.name)) : filterByName(list, pattern);
        continue;
      }
      if (fn.name === "trendValue" || fn.name === "consolidateBy") continue;
      notices.push(`未知函数 ${fn.name} 已忽略`);
    } catch (e) {
      const msg = e instanceof Error ? e.message : String(e);
      notices.push(msg);
    }
  }
  if (signal?.aborted) throw new DOMException("Aborted", "AbortError");
  const consolidateFn = plan.consolidateBy || "avg";
  list = list.map((s) => consolidateSeries(s, opts.maxDataPoints, consolidateFn));
  await yield_();
  if (signal?.aborted) throw new DOMException("Aborted", "AbortError");
  const disableAlign = opts.disableDataAlignment || opts.query.options?.disableDataAlignment || false;
  if (!disableAlign && list.length) {
    const delay = list[0]?.item?.delay != null ? String(list[0].item.delay) : void 0;
    const intervalMs = resolveAlignmentIntervalMs({
      intervalMs: opts.intervalMs,
      rangeFromMs: opts.rangeFromMs,
      rangeToMs: opts.rangeToMs,
      maxDataPoints: opts.maxDataPoints,
      itemDelay: delay
    });
    list = list.map((s) => alignSeries(s, opts.rangeFromMs, opts.rangeToMs, intervalMs));
    await yield_();
  }
  if (signal?.aborted) throw new DOMException("Aborted", "AbortError");
  const useMap = Boolean(opts.query.options?.useZabbixValueMapping);
  const referenced = new Set(list.map((s) => String(s.item.valuemapid || "")).filter(Boolean));
  const filteredMaps = (opts.valueMaps || []).filter((vm) => referenced.has(String(vm.valuemapid || "")));
  const lookup = useMap ? buildValueMapLookup(filteredMaps) : void 0;
  const frames = seriesListToFrames(list, opts.query.refId, opts.datasourceUid, lookup);
  if (notices.length && frames[0]) {
    const meta2 = frames[0].meta ||= {};
    meta2.notices = [...meta2.notices || [], ...notices.map((text) => ({ severity: "warning", text }))];
  }
  return frames;
}
const RP_RE = /^[A-Za-z0-9_.:-]+$/;
function assertRetentionPolicy(rp) {
  const v = String(rp || "").trim();
  if (!v) return "";
  if (!RP_RE.test(v)) {
    throw new Error(`invalid Influx retention policy for Direct DB: ${v}`);
  }
  return v;
}
function buildInfluxHistoryQuery(args) {
  for (const id of args.itemids) {
    if (!/^\d+$/.test(id))
      throw new Error(`invalid itemid for Direct DB: ${id}`);
  }
  const rp = assertRetentionPolicy(args.retentionPolicy);
  const prefix = rp ? `"${rp}".` : "";
  const measurement = args.measurement === "history_uint" ? "history_uint" : "history";
  const agg = args.consolidateBy === "min" ? "min" : args.consolidateBy === "max" ? "max" : args.consolidateBy === "sum" ? "sum" : args.consolidateBy === "count" ? "count" : "mean";
  return `SELECT ${agg}("value") FROM ${prefix}"${measurement}" WHERE "itemid" =~ /^${args.itemids.join("|")}$/ AND time >= ${Number(args.fromSec)}s AND time <= ${Number(args.toSec)}s GROUP BY "itemid", time(1m) fill(none)`;
}
function rowsToSeries(rows, items, opts) {
  const byId2 = new Map(items.map((i) => [String(i.itemid), i]));
  const buckets = /* @__PURE__ */ new Map();
  for (const row of rows) {
    const id = String(row.itemid ?? "");
    if (!id) continue;
    const item = byId2.get(id);
    const spec = resolveValueTypeSpec(item?.value_type ?? 0, {
      allowUnknownAsFloat: !item
    });
    const t = Number(row.time);
    const time = !Number.isFinite(t) ? 0 : t < 1e12 ? t * 1e3 : t;
    const mapped = mapHistoryRawValue(row.value, spec);
    const point = {
      time,
      value: mapped.value,
      valueRaw: mapped.valueRaw
    };
    if (row.value_min != null) point.value_min = String(row.value_min);
    if (row.value_avg != null) point.value_avg = String(row.value_avg);
    if (row.value_max != null) point.value_max = String(row.value_max);
    if (row.num != null) point.num = String(row.num);
    const list = buckets.get(id) || [];
    list.push(point);
    buckets.set(id, list);
  }
  return [...buckets.entries()].map(([itemid, points]) => {
    const item = byId2.get(itemid) || {
      itemid,
      name: itemid,
      key_: itemid,
      hostid: "",
      value_type: "0"
    };
    points.sort((a, b) => a.time - b.time);
    return {
      item,
      name: item.name || item.key_ || itemid,
      points,
      meta: { source: opts?.source, itemid },
      notices: []
    };
  });
}
function quoteIds$1(itemids) {
  return itemids.map((id) => {
    if (!/^\d+$/.test(id))
      throw new Error(`invalid itemid for Direct DB: ${id}`);
    return `'${id}'`;
  }).join(",");
}
function aggFn$1(consolidateBy) {
  switch (String(consolidateBy || "avg").toLowerCase()) {
    case "min":
      return "MIN";
    case "max":
      return "MAX";
    case "sum":
      return "SUM";
    case "count":
      return "COUNT";
    case "avg":
    default:
      return "AVG";
  }
}
function historyTable$1(history) {
  return history === 3 ? "history_uint" : "history";
}
function trendsTable$1(history) {
  return history === 3 ? "trends_uint" : "trends";
}
function buildMysqlHistorySQL(args) {
  const ids = quoteIds$1(args.itemids);
  const bucket = Math.max(
    1,
    Math.floor((args.toSec - args.fromSec) / Math.max(1, args.maxDataPoints))
  );
  const agg = aggFn$1(args.consolidateBy);
  const table = historyTable$1(args.history);
  return [
    `SELECT CAST(itemid AS CHAR) AS itemid,`,
    `       (clock DIV ${bucket}) * ${bucket} AS time,`,
    `       CAST(${agg}(value) AS CHAR) AS value`,
    `FROM ${table}`,
    `WHERE itemid IN (${ids})`,
    `  AND clock >= ${Number(args.fromSec)}`,
    `  AND clock <= ${Number(args.toSec)}`,
    `GROUP BY itemid, time`,
    `ORDER BY time ASC`
  ].join("\n");
}
function buildMysqlTrendSQL(args) {
  const ids = quoteIds$1(args.itemids);
  const table = trendsTable$1(args.history);
  const col2 = args.trendValue === "min" ? "value_min" : args.trendValue === "max" ? "value_max" : args.trendValue === "count" ? "num" : args.trendValue === "sum" ? "(value_avg * num)" : "value_avg";
  return [
    `SELECT CAST(itemid AS CHAR) AS itemid,`,
    `       clock AS time,`,
    `       CAST(${col2} AS CHAR) AS value,`,
    `       CAST(value_min AS CHAR) AS value_min,`,
    `       CAST(value_avg AS CHAR) AS value_avg,`,
    `       CAST(value_max AS CHAR) AS value_max,`,
    `       CAST(num AS CHAR) AS num`,
    `FROM ${table}`,
    `WHERE itemid IN (${ids})`,
    `  AND clock >= ${Number(args.fromSec)}`,
    `  AND clock <= ${Number(args.toSec)}`,
    `ORDER BY time ASC`
  ].join("\n");
}
function quoteIds(itemids) {
  return itemids.map((id) => {
    if (!/^\d+$/.test(id))
      throw new Error(`invalid itemid for Direct DB: ${id}`);
    return `'${id}'`;
  }).join(",");
}
function aggFn(consolidateBy) {
  switch (String(consolidateBy || "avg").toLowerCase()) {
    case "min":
      return "MIN";
    case "max":
      return "MAX";
    case "sum":
      return "SUM";
    case "count":
      return "COUNT";
    case "avg":
    default:
      return "AVG";
  }
}
function historyTable(history) {
  return history === 3 ? "history_uint" : "history";
}
function trendsTable(history) {
  return history === 3 ? "trends_uint" : "trends";
}
function buildPostgresHistorySQL(args) {
  const ids = quoteIds(args.itemids);
  const bucket = Math.max(
    1,
    Math.floor((args.toSec - args.fromSec) / Math.max(1, args.maxDataPoints))
  );
  const agg = aggFn(args.consolidateBy);
  const table = historyTable(args.history);
  return [
    `SELECT itemid::text AS itemid,`,
    `       (clock / ${bucket}) * ${bucket} AS time,`,
    `       ${agg}(value)::text AS value`,
    `FROM ${table}`,
    `WHERE itemid IN (${ids})`,
    `  AND clock >= ${Number(args.fromSec)}`,
    `  AND clock <= ${Number(args.toSec)}`,
    `GROUP BY itemid, time`,
    `ORDER BY time ASC`
  ].join("\n");
}
function buildPostgresTrendSQL(args) {
  const ids = quoteIds(args.itemids);
  const table = trendsTable(args.history === 3 ? 3 : 0);
  const col2 = args.trendValue === "min" ? "value_min" : args.trendValue === "max" ? "value_max" : args.trendValue === "count" ? "num" : args.trendValue === "sum" ? "(value_avg * num)" : "value_avg";
  return [
    `SELECT itemid::text AS itemid,`,
    `       clock AS time,`,
    `       ${col2}::text AS value,`,
    `       value_min::text AS value_min,`,
    `       value_avg::text AS value_avg,`,
    `       value_max::text AS value_max,`,
    `       num::text AS num`,
    `FROM ${table}`,
    `WHERE itemid IN (${ids})`,
    `  AND clock >= ${Number(args.fromSec)}`,
    `  AND clock <= ${Number(args.toSec)}`,
    `ORDER BY time ASC`
  ].join("\n");
}
const DIRECT_DB_TYPE_RE = /(postgres|mysql|influx)/i;
const OFFLINE_OR_SEED_TYPE_RE = /(testdata|testData|grafana-testdata|datasource-test|offline|builtin|mock)/i;
function detectDirectDbDialect(type) {
  const t = String(type || "").toLowerCase();
  if (t.includes("postgres")) return "postgres";
  if (t.includes("mysql")) return "mysql";
  if (t.includes("influx")) return "influx";
  return null;
}
function assertSafeIds(ids) {
  if (ids.some((id) => !/^\d+$/.test(id))) {
    throw new DataSourceError(
      "INVALID_QUERY",
      "Direct DB itemid must be numeric"
    );
  }
}
function resolveDirectDbGateway(uid) {
  const key = String(uid || "").trim();
  if (!key) {
    throw new DataSourceError(
      "UNSUPPORTED_CAPABILITY",
      "Direct DB datasource UID is required"
    );
  }
  const matches = listRuntimeDataSources().filter(
    (d) => String(d?.uid || "") === key
  );
  if (matches.length > 1) {
    throw new DataSourceError(
      "UNSUPPORTED_CAPABILITY",
      `Direct DB datasource UID is not unique: ${key}`
    );
  }
  const ds2 = matches[0] || getRuntimeDataSource(key);
  if (!ds2) {
    throw new DataSourceError(
      "UNSUPPORTED_CAPABILITY",
      `Direct DB gateway missing for uid=${key}`
    );
  }
  if (typeof ds2.query !== "function") {
    throw new DataSourceError(
      "UNSUPPORTED_CAPABILITY",
      `Direct DB gateway has no query capability: ${key}`
    );
  }
  const type = String(ds2.type || "");
  if (OFFLINE_OR_SEED_TYPE_RE.test(type) || ds2.offline === true || ds2.builtin === true) {
    throw new DataSourceError(
      "UNSUPPORTED_CAPABILITY",
      `Direct DB refuses offline/seed datasource type=${type || "unknown"}`
    );
  }
  if (ds2.dataMode === "fixture" || ds2.useFixture === true) {
    throw new DataSourceError(
      "UNSUPPORTED_CAPABILITY",
      "Direct DB refuses fixture-mode SQL datasource"
    );
  }
  const dialect = detectDirectDbDialect(type);
  if (!dialect || !DIRECT_DB_TYPE_RE.test(type)) {
    throw new DataSourceError(
      "UNSUPPORTED_CAPABILITY",
      `不支持的 Direct DB 类型: ${type || "unknown"}`
    );
  }
  return { ds: ds2, dialect };
}
function rangeMs$2(ctx) {
  const from = ctx.range.from instanceof Date ? ctx.range.from.getTime() : Number(ctx.range.from);
  const to = ctx.range.to instanceof Date ? ctx.range.to.getTime() : Number(ctx.range.to);
  return { from, to };
}
function numericItemsOnly(items) {
  const out = [];
  for (const item of items) {
    const spec = resolveValueTypeSpec(item.value_type);
    if (spec.valueType !== 0 && spec.valueType !== 3) {
      throw new DataSourceError(
        "UNSUPPORTED_CAPABILITY",
        `Direct DB only supports numeric value_type 0/3, got ${spec.valueType} for item ${item.itemid}`
      );
    }
    out.push(item);
  }
  return out;
}
function buildDirectDbQueryText(args) {
  assertSafeIds(args.itemids);
  if (args.useTrends && args.history !== 0 && args.history !== 3) {
    throw new DataSourceError(
      "UNSUPPORTED_CAPABILITY",
      "trends only for value_type 0/3"
    );
  }
  if (args.dialect === "postgres") {
    return args.useTrends ? buildPostgresTrendSQL({
      itemids: args.itemids,
      fromSec: args.fromSec,
      toSec: args.toSec,
      history: args.history,
      trendValue: args.trendValue
    }) : buildPostgresHistorySQL({
      itemids: args.itemids,
      fromSec: args.fromSec,
      toSec: args.toSec,
      history: args.history,
      consolidateBy: args.consolidateBy,
      maxDataPoints: args.maxDataPoints
    });
  }
  if (args.dialect === "mysql") {
    return args.useTrends ? buildMysqlTrendSQL({
      itemids: args.itemids,
      fromSec: args.fromSec,
      toSec: args.toSec,
      history: args.history,
      trendValue: args.trendValue
    }) : buildMysqlHistorySQL({
      itemids: args.itemids,
      fromSec: args.fromSec,
      toSec: args.toSec,
      history: args.history,
      consolidateBy: args.consolidateBy,
      maxDataPoints: args.maxDataPoints
    });
  }
  return buildInfluxHistoryQuery({
    itemids: args.itemids,
    fromSec: args.fromSec,
    toSec: args.toSec,
    retentionPolicy: args.retentionPolicy,
    measurement: args.history === 3 ? "history_uint" : "history",
    consolidateBy: args.consolidateBy
  });
}
function framesToRows(frames) {
  const rows = [];
  for (const frame of frames || []) {
    const fields = frame.fields || [];
    const itemField = fields.find((f) => /itemid/i.test(f.name));
    const timeField = fields.find((f) => f.name === "Time" || /^(time|clock)$/i.test(f.name)) || fields.find((f) => f.type === "time");
    const valueField = fields.find((f) => f.name === "Value" || /^value$/i.test(f.name)) || fields.find(
      (f) => /value/i.test(f.name) && !/itemid|min|max|avg|num/i.test(f.name)
    );
    const minF = fields.find((f) => /value_min/i.test(f.name));
    const avgF = fields.find((f) => /value_avg/i.test(f.name));
    const maxF = fields.find((f) => /value_max/i.test(f.name));
    const numF = fields.find((f) => /^num$/i.test(f.name));
    const n = Math.max(
      timeField?.values?.length || 0,
      valueField?.values?.length || 0,
      itemField?.values?.length || 0
    );
    const labelItemid = frame.name || valueField?.labels?.itemid;
    for (let i = 0; i < n; i++) {
      rows.push({
        itemid: String(itemField?.values?.[i] ?? labelItemid ?? ""),
        time: timeField?.values?.[i],
        value: valueField?.values?.[i],
        value_min: minF?.values?.[i],
        value_avg: avgF?.values?.[i],
        value_max: maxF?.values?.[i],
        num: numF?.values?.[i]
      });
    }
  }
  return rows;
}
async function resolveDirectDbItems(ctx) {
  if (String(ctx.query.queryType) === "3" || ctx.query.itemids) {
    const ids = String(ctx.query.itemids || "").split(",").map((s) => s.trim()).filter(Boolean);
    assertSafeIds(ids);
    if (!ids.length) return [];
    const items2 = await ctx.api.getItemsByIds(ids, ctx.signal);
    return numericItemsOnly(items2);
  }
  const groups = await resolveGroups(
    ctx.api,
    ctx.query,
    ctx.scopedVars,
    ctx.signal
  );
  const hosts = await resolveHosts(
    ctx.api,
    ctx.query,
    ctx.scopedVars,
    groups.map((g) => String(g.groupid)),
    ctx.signal
  );
  const apps = await resolveApplications(
    ctx.api,
    ctx.query,
    ctx.scopedVars,
    hosts.map((h) => String(h.hostid)),
    ctx.signal
  );
  const items = await resolveItems(
    ctx.api,
    ctx.query,
    ctx.scopedVars,
    hosts.map((h) => String(h.hostid)),
    apps.map((a) => String(a.applicationid || a)),
    ctx.signal
  );
  return numericItemsOnly(items);
}
async function executeDirectDbQuery(ctx) {
  if (!ctx.settings.dbConnectionEnable) return null;
  if (!ctx.settings.dbConnectionDatasourceUID) {
    throw new DataSourceError(
      "UNSUPPORTED_CAPABILITY",
      "Direct DB enabled but datasource UID missing"
    );
  }
  const { ds: ds2, dialect } = resolveDirectDbGateway(
    ctx.settings.dbConnectionDatasourceUID
  );
  const plan = planQueryFunctions(ctx.query.functions || []);
  const { from, to } = rangeMs$2(ctx);
  const shifted = applyPlanToRange(from, to, plan);
  const fromSec = Math.floor(shifted.fromMs / 1e3);
  const toSec = Math.floor(shifted.toMs / 1e3);
  const items = await resolveDirectDbItems(ctx);
  if (!items.length) return [];
  const useTrends = shouldUseTrends({
    fromMs: shifted.fromMs,
    toMs: shifted.toMs,
    nowMs: Date.now(),
    query: ctx.query.options?.useTrends || "default",
    enabled: ctx.settings.trends !== false,
    trendsFrom: ctx.settings.trendsFrom || "7d",
    trendsRange: ctx.settings.trendsRange || "4d"
  });
  const groups = /* @__PURE__ */ new Map();
  for (const item of items) {
    const spec = resolveValueTypeSpec(item.value_type);
    const hist = spec.history === 3 ? 3 : 0;
    if (useTrends && !spec.supportsTrends) {
      throw new DataSourceError(
        "UNSUPPORTED_CAPABILITY",
        `Direct DB trends unsupported for value_type ${spec.valueType}`
      );
    }
    const list = groups.get(hist) || [];
    list.push(item);
    groups.set(hist, list);
  }
  const maxDataPoints = Math.min(1e4, ctx.maxDataPoints || 1e3);
  const allRows = [];
  const lastQueryTexts = [];
  for (const [history, group] of groups) {
    const itemids = group.map((i) => String(i.itemid));
    const rawQuery = buildDirectDbQueryText({
      dialect,
      itemids,
      history,
      fromSec,
      toSec,
      useTrends,
      trendValue: plan.trendValue,
      consolidateBy: plan.consolidateBy || void 0,
      maxDataPoints,
      retentionPolicy: ctx.settings.dbConnectionRetentionPolicy
    });
    lastQueryTexts.push(rawQuery);
    const result = await ds2.query(
      {
        requestId: `zabbix-direct-${ctx.query.refId}-${history}`,
        targets: [
          {
            refId: ctx.query.refId,
            rawSql: rawQuery,
            format: "table",
            query: rawQuery
          }
        ],
        range: {
          from: new Date(shifted.fromMs),
          to: new Date(shifted.toMs),
          raw: ctx.range.raw
        },
        maxDataPoints
      },
      ctx.signal
    );
    allRows.push(...framesToRows(result?.data || []));
  }
  const series = rowsToSeries(allRows, items, {
    source: "direct-db"
  }).map((s) => ({
    ...s,
    meta: {
      ...s.meta || {},
      dialect,
      lineage: "direct-db",
      requestPlan: {
        timeShiftMs: plan.timeShiftMs,
        trendValue: plan.trendValue,
        consolidateBy: plan.consolidateBy
      },
      queryTexts: lastQueryTexts
    }
  }));
  return runProcessingPipeline(series, {
    query: ctx.query,
    rangeFromMs: from,
    rangeToMs: to,
    maxDataPoints,
    intervalMs: ctx.intervalMs,
    datasourceUid: ctx.instance.uid,
    disableDataAlignment: ctx.settings.disableDataAlignment,
    requestPlanApplied: true,
    functionsOverride: plan.postFetchFunctions
  });
}
function resolveLldSelection(query) {
  if (query.executionMode === "lld" && query.lld?.ruleId) {
    return {
      ruleId: String(query.lld.ruleId),
      ruleName: query.lld.ruleName,
      prototypeIds: [...query.lld.prototypeIds || []].map(String),
      prototypeKeys: [...query.lld.prototypeKeys || []].map(String),
      discoveredItemIds: query.lld.discoveredItemIds?.map(String)
    };
  }
  if (query.lldRuleId) {
    return {
      ruleId: String(query.lldRuleId),
      ruleName: query.lldRuleName,
      prototypeIds: [],
      prototypeKeys: [...query.lldItemKeys || []].map(String)
    };
  }
  if (query.executionMode === "lld") {
    return {
      ruleId: "",
      prototypeIds: [],
      prototypeKeys: []
    };
  }
  return null;
}
function assertLldSelection(sel) {
  if (!sel.ruleId) {
    throw new DataSourceError(
      "INVALID_QUERY",
      "LLD ruleId is required when executionMode is lld"
    );
  }
  if (!sel.prototypeIds.length && !sel.prototypeKeys.length && !sel.discoveredItemIds?.length) {
    throw new DataSourceError(
      "INVALID_QUERY",
      "LLD requires prototypeIds, prototypeKeys, or discoveredItemIds"
    );
  }
}
async function resolveLldDiscoveredItems(ctx, sel) {
  assertLldSelection(sel);
  const groups = await resolveGroups(
    ctx.api,
    ctx.query,
    ctx.scopedVars,
    ctx.signal
  );
  const hosts = await resolveHosts(
    ctx.api,
    ctx.query,
    ctx.scopedVars,
    groups.map((g) => g.groupid),
    ctx.signal
  );
  const hostids = hosts.map((h) => String(h.hostid));
  let prototypeIds = [...sel.prototypeIds];
  if (!prototypeIds.length && sel.prototypeKeys.length) {
    const protos = await ctx.api.getItemPrototypesFull(sel.ruleId, ctx.signal);
    const rows = Array.isArray(protos) ? protos : protos.rows || [];
    const keySet = new Set(sel.prototypeKeys);
    prototypeIds = rows.filter((p) => keySet.has(String(p.key_))).map((p) => String(p.itemid));
  }
  if (sel.discoveredItemIds?.length) {
    const items2 = await ctx.api.getItemsByIds(
      sel.discoveredItemIds,
      ctx.signal
    );
    return { items: items2, ruleId: sel.ruleId, prototypeIds };
  }
  const items = await ctx.api.getDiscoveredItems(
    hostids,
    sel.ruleId,
    sel.prototypeKeys,
    ctx.signal,
    { prototypeIds, requireParentRelation: prototypeIds.length > 0 }
  );
  for (const it of items) {
    it.__lld = {
      ruleId: sel.ruleId,
      prototypeId: it.itemDiscovery?.parent_itemid,
      discoveredItemId: it.itemid,
      hostId: it.hostid,
      matchingBasis: "itemDiscovery.parent_itemid"
    };
  }
  return { items, ruleId: sel.ruleId, prototypeIds };
}
function rangeMs$1(ctx) {
  const from = ctx.range.from instanceof Date ? ctx.range.from.getTime() : Number(ctx.range.from);
  const to = ctx.range.to instanceof Date ? ctx.range.to.getTime() : Number(ctx.range.to);
  return { from, to };
}
function historyPageLimit(ctx) {
  const n = Number(ctx.settings.historyPageLimit);
  return Number.isFinite(n) && n > 0 ? Math.floor(n) : 1e4;
}
function historyBatchSize(ctx) {
  const n = Number(ctx.settings.historyBatchSize);
  return Number.isFinite(n) && n > 0 ? Math.floor(n) : 100;
}
const MAX_HISTORY_SERIES = 8;
const MAX_HISTORY_SERIES_UNSCOPED = 3;
const MAX_HISTORY_POINTS = 4e3;
async function loadHistoryForItems(ctx, items, opts) {
  if (!items.length) return [];
  const seriesCap = Math.max(
    1,
    Math.min(
      opts?.maxSeries ?? MAX_HISTORY_SERIES,
      MAX_HISTORY_SERIES
    )
  );
  const itemList = items.length > seriesCap ? items.slice(0, seriesCap) : items;
  const plan = planQueryFunctions(ctx.query.functions || []);
  const { from, to } = rangeMs$1(ctx);
  const shifted = applyPlanToRange(from, to, plan);
  const fromSec = Math.floor(shifted.fromMs / 1e3);
  const toSec = Math.floor(shifted.toMs / 1e3);
  const trendsQuery = ctx.query.options?.useTrends || "default";
  const useTrends = shouldUseTrends({
    fromMs: shifted.fromMs,
    toMs: shifted.toMs,
    nowMs: Date.now(),
    query: trendsQuery,
    enabled: ctx.settings.trends !== false,
    trendsFrom: ctx.settings.trendsFrom || "7d",
    trendsRange: ctx.settings.trendsRange || "4d"
  });
  const trendMode = opts?.trendValue || plan.trendValue || "avg";
  const pageLimit = Math.min(historyPageLimit(ctx), 2e3);
  const batchSize = Math.min(historyBatchSize(ctx), 25);
  const perSeries = Math.max(64, Number(ctx.maxDataPoints || 500) || 500);
  const maxRows = Math.min(MAX_HISTORY_POINTS, perSeries * itemList.length);
  const byType = /* @__PURE__ */ new Map();
  for (const item of itemList) {
    const spec = resolveValueTypeSpec(item.value_type);
    const list = byType.get(spec.history) || [];
    list.push(item);
    byType.set(spec.history, list);
  }
  const series = [];
  for (const [history, group] of byType) {
    const spec = resolveValueTypeSpec(history);
    const ids = group.map((i) => i.itemid);
    const appendResult = (result) => {
      for (const item of group.filter((g) => result.batch.includes(g.itemid))) {
        if (result.kind === "trend") {
          const rows = (result.trends || []).filter(
            (t) => String(t.itemid) === String(item.itemid)
          );
          let points = rows.map((t) => ({
            time: Number(t.clock) * 1e3,
            value: pickTrendValue(t, trendMode),
            valueRaw: String(t.value_avg ?? t.value_min ?? ""),
            value_min: t.value_min,
            value_avg: t.value_avg,
            value_max: t.value_max,
            num: t.num
          })).sort((a, b) => a.time - b.time);
          const maxPts = Math.max(64, Math.min(perSeries, 240));
          if (points.length > maxPts) {
            const step = Math.ceil(points.length / maxPts);
            points = points.filter(
              (_, i) => i % step === 0 || i === points.length - 1
            );
          }
          series.push({
            item,
            points,
            meta: {
              source: "trend",
              trendValue: trendMode,
              value_types: ["min", "avg", "max", "num"]
            }
          });
        } else {
          const hist = result.page.points.filter(
            (h) => String(h.itemid) === String(item.itemid)
          );
          const mapped = mapHistoryPoints(hist, spec);
          const points = mapped.times.map((time, idx) => ({
            time,
            value: mapped.values[idx] ?? null,
            valueRaw: mapped.valueRaw[idx] ?? null,
            ns: mapped.ns[idx] ?? void 0,
            timestamp: mapped.log.timestamp[idx] ?? void 0,
            source: mapped.log.source[idx] ?? void 0,
            severity: mapped.log.severity[idx] ?? void 0,
            logeventid: mapped.log.logeventid[idx] ?? void 0
          }));
          series.push({
            item,
            points,
            notices: [
              ...mapped.notices || [],
              ...result.page.truncated ? ["history result truncated: page limit or maxRows reached"] : []
            ],
            meta: {
              source: "history",
              truncated: result.page.truncated,
              history
            }
          });
        }
      }
      opts?.onPartial?.(series.slice());
    };
    for await (const _chunk of fetchHistoryStream({
      itemids: ids,
      batchSize,
      signal: ctx.signal,
      fetchBatch: async (batch) => {
        if (useTrends && !spec.supportsTrends) {
          if (trendsQuery === "true") {
            throw new DataSourceError(
              "UNSUPPORTED_CAPABILITY",
              `trends are not supported for value_type ${spec.valueType} (${spec.name})`
            );
          }
        }
        let result;
        if (useTrends && spec.supportsTrends) {
          const trends = await ctx.api.getTrends(
            batch,
            fromSec,
            toSec,
            ctx.signal
          );
          if (Array.isArray(trends) && trends.length > 0) {
            result = { kind: "trend", batch, trends };
          }
        }
        if (!result) {
          const page = await fetchHistoryRange({
            itemids: batch,
            history,
            fromSec,
            toSec,
            pageLimit,
            maxRows: Math.min(maxRows, perSeries * batch.length),
            signal: ctx.signal,
            getHistory: (itemids, h, f, t, signal, limit) => ctx.api.getHistory(itemids, h, f, t, signal, limit)
          });
          result = { kind: "history", batch, page };
        }
        appendResult(result);
        return result.kind === "history" ? result.page.points : [];
      }
    })) {
    }
  }
  return series;
}
async function executeMetricsQuery(ctx) {
  const directIds = (ctx.query.item?.ids || []).map(String).filter(Boolean);
  let items;
  const lldSel = resolveLldSelection(ctx.query);
  if (!directIds.length && !lldSel) {
    assertBoundedHostScope(ctx.query, ctx.scopedVars);
  }
  if (lldSel) {
    const resolved = await resolveLldDiscoveredItems(ctx, lldSel);
    items = resolved.items;
    if (!items.length) {
      return [emptyFrame(ctx.query.refId, "LLD 未匹配到 discovered items")];
    }
  } else if (directIds.length) {
    items = await ctx.api.getItemsByIds(directIds, ctx.signal);
    if (!items.length) {
      return [emptyFrame(ctx.query.refId, "item.ids 未找到监控项")];
    }
  } else {
    const hostF2 = interpolateFilter(ctx.query.host, ctx.scopedVars);
    const groupF2 = interpolateFilter(ctx.query.group, ctx.scopedVars);
    const hostAll = isMatchAllZabbixFilter(hostF2.filter) && !hostF2.ids?.length;
    const groupAll = isMatchAllZabbixFilter(groupF2.filter) && !groupF2.ids?.length;
    let hostids = [];
    let itemGroupids;
    if (!hostAll) {
      const groups = await resolveGroups(
        ctx.api,
        ctx.query,
        ctx.scopedVars,
        ctx.signal
      );
      const hosts = await resolveHosts(
        ctx.api,
        ctx.query,
        ctx.scopedVars,
        groups.map((g) => String(g.groupid)),
        ctx.signal
      );
      hostids = hosts.map((h) => String(h.hostid));
    } else if (!groupAll) {
      const groups = await resolveGroups(
        ctx.api,
        ctx.query,
        ctx.scopedVars,
        ctx.signal
      );
      if (groups.length) {
        itemGroupids = groups.map((g) => String(g.groupid));
      }
    }
    const apps = await resolveApplications(
      ctx.api,
      ctx.query,
      ctx.scopedVars,
      hostids,
      ctx.signal
    );
    items = await resolveItems(
      ctx.api,
      ctx.query,
      ctx.scopedVars,
      hostids,
      apps.map((a) => String(a.applicationid || a)),
      ctx.signal,
      itemGroupids
    );
  }
  if (!items.length) {
    return [emptyFrame(ctx.query.refId, "未匹配到监控项")];
  }
  const plan = planQueryFunctions(ctx.query.functions || []);
  const hostF = interpolateFilter(ctx.query.host, ctx.scopedVars);
  const groupF = interpolateFilter(ctx.query.group, ctx.scopedVars);
  const unscoped = isMatchAllZabbixFilter(hostF.filter) && !hostF.ids?.length || isMatchAllZabbixFilter(groupF.filter) && !groupF.ids?.length;
  const series = await loadHistoryForItems(ctx, items, {
    trendValue: plan.trendValue,
    maxSeries: unscoped ? MAX_HISTORY_SERIES_UNSCOPED : MAX_HISTORY_SERIES,
    onPartial: ctx.onPartialData ? (partialSeries) => {
      try {
        void buildFramesAsync(
          {
            series: partialSeries,
            refId: ctx.query.refId,
            datasourceUid: ctx.instance.uid,
            requestId: `partial-${ctx.query.refId}`
          },
          ctx.signal
        ).then((partialFrames) => {
          if (!ctx.signal?.aborted) ctx.onPartialData?.(partialFrames);
        }).catch(() => {
        });
      } catch {
      }
    } : void 0
  });
  const { from, to } = rangeMs$1(ctx);
  const pipelineOpts = {
    query: {
      ...ctx.query,
      functions: plan.postFetchFunctions
    },
    rangeFromMs: from,
    rangeToMs: to,
    maxDataPoints: ctx.maxDataPoints,
    intervalMs: ctx.intervalMs,
    datasourceUid: ctx.instance.uid,
    disableDataAlignment: Boolean(directIds.length) || Boolean(lldSel) || ctx.settings.disableDataAlignment || ctx.query.options?.disableDataAlignment,
    functionsOverride: plan.postFetchFunctions,
    requestPlanApplied: true
  };
  let frames;
  try {
    frames = await runProcessingPipelineAsync(series, pipelineOpts, ctx.signal);
  } catch (e) {
    if (e?.name === "AbortError") throw e;
    frames = runProcessingPipeline(series, pipelineOpts);
  }
  if (lldSel) {
    for (const f of frames) {
      const meta2 = f.meta ||= {};
      meta2.lld = {
        ruleId: lldSel.ruleId,
        ruleName: lldSel.ruleName,
        prototypeIds: lldSel.prototypeIds,
        prototypeKeys: lldSel.prototypeKeys
      };
    }
  }
  return frames;
}
function partialOpts(ctx) {
  if (!ctx.onPartialData) return void 0;
  return {
    onPartial: (partialSeries) => {
      try {
        ctx.onPartialData?.(seriesToFrames(partialSeries, ctx.query.refId));
      } catch {
      }
    }
  };
}
function parseItemIds(raw) {
  const ids = String(raw || "").split(",").map((v) => v.trim()).filter(Boolean);
  if (!ids.length)
    throw new DataSourceError("INVALID_QUERY", "itemids cannot be empty");
  if (ids.some((id) => !/^\d+$/.test(id)))
    throw new DataSourceError("INVALID_QUERY", "itemid must be numeric");
  if (ids.length > 500)
    throw new DataSourceError("INVALID_QUERY", "item count exceeds 500");
  return [...new Set(ids)];
}
async function executeItemIdQuery(ctx) {
  const rawIds = String(ctx.query.itemids || "").trim();
  if (rawIds) {
    const ids = parseItemIds(rawIds);
    const items2 = await ctx.api.getItemsByIds(ids, ctx.signal);
    const series2 = await loadHistoryForItems(ctx, items2, partialOpts(ctx));
    return seriesToFrames(series2, ctx.query.refId);
  }
  const itemF = interpolateFilter(ctx.query.item, ctx.scopedVars);
  if (itemF.ids?.length) {
    const items2 = await ctx.api.getItemsByIds(itemF.ids, ctx.signal);
    const series2 = await loadHistoryForItems(ctx, items2, partialOpts(ctx));
    return seriesToFrames(series2, ctx.query.refId);
  }
  if (!itemF.filter) {
    throw new DataSourceError("INVALID_QUERY", "itemids cannot be empty");
  }
  const hostF = interpolateFilter(ctx.query.host, ctx.scopedVars);
  const groupF = interpolateFilter(ctx.query.group, ctx.scopedVars);
  const hostAll = isMatchAllZabbixFilter(hostF.filter) && !hostF.ids?.length;
  const groupAll = isMatchAllZabbixFilter(groupF.filter) && !groupF.ids?.length;
  let hostids = [];
  let itemGroupids;
  if (!hostAll) {
    const groups = await resolveGroups(
      ctx.api,
      ctx.query,
      ctx.scopedVars,
      ctx.signal
    );
    const hosts = await resolveHosts(
      ctx.api,
      ctx.query,
      ctx.scopedVars,
      groups.map((g) => String(g.groupid)),
      ctx.signal
    );
    hostids = hosts.map((h) => String(h.hostid));
  } else if (!groupAll) {
    const groups = await resolveGroups(
      ctx.api,
      ctx.query,
      ctx.scopedVars,
      ctx.signal
    );
    if (groups.length) itemGroupids = groups.map((g) => String(g.groupid));
  }
  const items = await resolveItems(
    ctx.api,
    ctx.query,
    ctx.scopedVars,
    hostids,
    [],
    ctx.signal,
    itemGroupids
  );
  const series = await loadHistoryForItems(ctx, items, partialOpts(ctx));
  return seriesToFrames(series, ctx.query.refId);
}
function resolveSlaPeriodSeconds(slaInterval, rangeFromSec, rangeToSec) {
  const span = Math.max(1, rangeToSec - rangeFromSec);
  const key = String(slaInterval).toLowerCase();
  const map = {
    none: span,
    hour: 3600,
    day: 86400,
    week: 604800,
    month: 2592e3,
    quarter: 7776e3,
    year: 31536e3
  };
  let periodSeconds = map[key];
  if (periodSeconds == null) {
    const ms = parseDurationMs(key, Number.NaN);
    periodSeconds = Number.isFinite(ms) ? Math.max(1, Math.floor(ms / 1e3)) : span;
  }
  const periods = Math.max(1, Math.ceil(span / periodSeconds));
  return {
    periodFrom: rangeFromSec,
    periodTo: rangeToSec,
    periods,
    periodSeconds
  };
}
function numOrNull(v) {
  if (v == null || v === "") return null;
  const n = Number(v);
  return Number.isFinite(n) ? n : null;
}
async function executeServicesQuery(ctx) {
  const serviceFilter2 = interpolateZabbixValue(
    ctx.query.itServiceFilter || "",
    ctx.scopedVars
  );
  const slaFilter = interpolateZabbixValue(
    ctx.query.slaFilter || "",
    ctx.scopedVars
  );
  const property = String(ctx.query.slaProperty || "sli");
  const servicesPage = await ctx.api.getServices(ctx.signal);
  const services = Array.isArray(servicesPage) ? servicesPage : servicesPage.rows || [];
  const filtered = services.filter(
    (s) => !serviceFilter2 || String(s.name || "").includes(serviceFilter2)
  );
  const serviceids = filtered.map((s) => String(s.serviceid));
  const slasPage = await ctx.api.getSlas(serviceids, slaFilter, ctx.signal);
  const slas = Array.isArray(slasPage) ? slasPage : slasPage.rows || [];
  const from = Math.floor(
    (ctx.range.from instanceof Date ? ctx.range.from.getTime() : Number(ctx.range.from)) / 1e3
  );
  const to = Math.floor(
    (ctx.range.to instanceof Date ? ctx.range.to.getTime() : Number(ctx.range.to)) / 1e3
  );
  const period = resolveSlaPeriodSeconds(
    ctx.query.slaInterval || "none",
    from,
    to
  );
  const times = [];
  const serviceNames = [];
  const serviceIds = [];
  const slaNames = [];
  const slaIds = [];
  const props = [];
  const values = [];
  const sliCol = [];
  const uptimeCol = [];
  const downtimeCol = [];
  const errorBudgetCol = [];
  const notices = [];
  const rows = slas.length ? slas : filtered.map((s) => ({
    slaid: s.serviceid,
    name: s.name,
    serviceid: s.serviceid,
    sla: s.sla ?? s.status
  }));
  for (const sla of rows) {
    if (slaFilter && !String(sla.name || "").includes(slaFilter)) continue;
    let sli = numOrNull(sla.sli);
    let uptime = numOrNull(sla.uptime);
    let downtime = numOrNull(sla.downtime);
    let errorBudget = numOrNull(
      sla.error_budget ?? sla.errorBudget
    );
    let value = numOrNull(sla[property]);
    if (value == null && property === "sla")
      value = numOrNull(sla.sla ?? sla.slo);
    try {
      const sliRes = await ctx.api.getSli(
        {
          slaid: sla.slaid,
          serviceids: sla.serviceid ? [sla.serviceid] : void 0,
          period_from: period.periodFrom,
          period_to: period.periodTo,
          periods: period.periods
        },
        ctx.signal
      );
      const first = Array.isArray(sliRes) ? sliRes[0] : sliRes;
      if (first && typeof first === "object") {
        if (first.sli != null) {
          const raw = first.sli;
          sli = numOrNull(Array.isArray(raw) ? raw[0] : raw);
        }
        if (first.uptime != null) {
          const raw = first.uptime;
          uptime = numOrNull(Array.isArray(raw) ? raw[0] : raw);
        }
        if (first.downtime != null) {
          const raw = first.downtime;
          downtime = numOrNull(Array.isArray(raw) ? raw[0] : raw);
        }
        const eb = first.error_budget ?? first.errorBudget;
        if (eb != null) errorBudget = numOrNull(Array.isArray(eb) ? eb[0] : eb);
      }
      if (property === "sli" && sli != null) value = sli;
      else if (property === "uptime" && uptime != null) value = uptime;
      else if (property === "downtime" && downtime != null) value = downtime;
      else if (property === "error_budget" || property === "errorBudget")
        value = errorBudget;
      else if (value == null && sli != null) value = sli;
    } catch (e) {
      const msg = e instanceof Error ? e.message : String(e);
      notices.push(`sla.getsli failed for ${sla.slaid || sla.name}: ${msg}`);
      if (value === 0 && sla[property] == null && sla.sli == null && sla.sla == null) {
        value = null;
      }
    }
    const svc = filtered.find((s) => String(s.serviceid) === String(sla.serviceid)) || filtered[0] || {};
    times.push(to * 1e3);
    serviceNames.push(String(svc.name || sla.service_name || ""));
    serviceIds.push(String(svc.serviceid || sla.serviceid || ""));
    slaNames.push(String(sla.name || ""));
    slaIds.push(String(sla.slaid || ""));
    props.push(property);
    values.push(value);
    sliCol.push(sli);
    uptimeCol.push(uptime);
    downtimeCol.push(downtime);
    errorBudgetCol.push(errorBudget);
  }
  const frame = createDataFrame({
    refId: ctx.query.refId,
    fields: [
      { name: "Time", type: "time", values: times },
      { name: "Service", type: "string", values: serviceNames },
      { name: "ServiceId", type: "string", values: serviceIds },
      { name: "Sla", type: "string", values: slaNames },
      { name: "SlaId", type: "string", values: slaIds },
      { name: "Property", type: "string", values: props },
      { name: "Value", type: "number", values },
      { name: "SLI", type: "number", values: sliCol },
      { name: "Uptime", type: "number", values: uptimeCol },
      { name: "Downtime", type: "number", values: downtimeCol },
      { name: "ErrorBudget", type: "number", values: errorBudgetCol },
      {
        name: "PeriodSeconds",
        type: "number",
        values: times.map(() => period.periodSeconds)
      }
    ]
  });
  if (notices.length) {
    frame.meta = {
      notices: notices.map((text) => ({ severity: "warning", text }))
    };
  }
  return [frame];
}
function compileTextFilter(textFilter) {
  const source = String(textFilter || "").trim();
  if (!source) return { match: () => true };
  const slash = source.match(/^\/(.*)\/([gimsuy]*)$/);
  if (slash) {
    try {
      const re = new RegExp(slash[1], slash[2].replace(/g/g, ""));
      return { match: (value) => re.test(value) };
    } catch (e) {
      throw new DataSourceError(
        "INVALID_QUERY",
        `invalid textFilter regex: ${e instanceof Error ? e.message : String(e)}`
      );
    }
  }
  return {
    match: (value) => {
      if (matchesZabbixFilter(value, source)) return true;
      if (/[\\^$*+?[\]{}|]/.test(source)) {
        try {
          return new RegExp(source).test(value);
        } catch {
          return false;
        }
      }
      return false;
    }
  };
}
function extractText(value, textFilter, useCaptureGroups) {
  const source = String(textFilter || "").trim();
  const raw = String(value ?? "");
  if (!useCaptureGroups || !source) return raw;
  const slash = source.match(/^\/(.*)\/([gimsuy]*)$/);
  try {
    const re = slash ? new RegExp(slash[1], slash[2].replace(/g/g, "")) : new RegExp(source);
    const m = re.exec(raw);
    if (!m) return raw;
    if (m[1] != null) return m[1];
    return m[0] ?? raw;
  } catch {
    return raw;
  }
}
function isEmptySkipped(value, skipEmpty) {
  if (!skipEmpty) return false;
  if (value === "0") return false;
  return value === "" || value == null;
}
async function executeTextQuery(ctx) {
  assertBoundedHostScope(ctx.query, ctx.scopedVars);
  const hostF = interpolateFilter(ctx.query.host, ctx.scopedVars);
  const groupF = interpolateFilter(ctx.query.group, ctx.scopedVars);
  const hostAll = isMatchAllZabbixFilter(hostF.filter) && !hostF.ids?.length;
  const groupAll = isMatchAllZabbixFilter(groupF.filter) && !groupF.ids?.length;
  let hostids = [];
  let itemGroupids;
  if (!hostAll) {
    const groups = await resolveGroups(
      ctx.api,
      ctx.query,
      ctx.scopedVars,
      ctx.signal
    );
    const hosts = await resolveHosts(
      ctx.api,
      ctx.query,
      ctx.scopedVars,
      groups.map((g) => String(g.groupid)),
      ctx.signal
    );
    hostids = hosts.map((h) => String(h.hostid));
  } else if (!groupAll) {
    const groups = await resolveGroups(
      ctx.api,
      ctx.query,
      ctx.scopedVars,
      ctx.signal
    );
    if (groups.length) itemGroupids = groups.map((g) => String(g.groupid));
  }
  const apps = await resolveApplications(
    ctx.api,
    ctx.query,
    ctx.scopedVars,
    hostids,
    ctx.signal
  );
  let items = await resolveItems(
    ctx.api,
    ctx.query,
    ctx.scopedVars,
    hostids,
    apps.map((a) => String(a.applicationid || a)),
    ctx.signal,
    itemGroupids
  );
  items = items.filter((i) => ["1", "2", "4"].includes(String(i.value_type)));
  const from = Math.floor(
    (ctx.range.from instanceof Date ? ctx.range.from.getTime() : Number(ctx.range.from)) / 1e3
  );
  const to = Math.floor(
    (ctx.range.to instanceof Date ? ctx.range.to.getTime() : Number(ctx.range.to)) / 1e3
  );
  const textFilter = String(ctx.query.textFilter || "");
  const skipEmpty = Boolean(ctx.query.options?.skipEmptyValues);
  const filter2 = compileTextFilter(textFilter);
  const times = [];
  const values = [];
  const hostCol = [];
  const itemCol = [];
  const itemIdCol = [];
  const valueTypeCol = [];
  const nsCol = [];
  const timestampCol = [];
  const sourceCol = [];
  const severityCol = [];
  const logeventidCol = [];
  const eventIdCol = [];
  for (const item of items) {
    const history = Number(item.value_type);
    const rows = await ctx.api.getHistory(
      [item.itemid],
      history,
      from,
      to,
      ctx.signal
    );
    for (const row of rows) {
      const rawValue = row.value == null ? "" : String(row.value);
      if (isEmptySkipped(rawValue, skipEmpty)) continue;
      if (!filter2.match(rawValue)) continue;
      const value = extractText(
        rawValue,
        textFilter,
        Boolean(ctx.query.useCaptureGroups)
      );
      const ns = row.ns == null ? null : String(row.ns);
      const nsNum = Number(row.ns || 0);
      times.push(Number(row.clock) * 1e3 + Math.floor(nsNum / 1e6));
      values.push(value);
      hostCol.push(item.hosts?.[0]?.name || item.hosts?.[0]?.host || "");
      itemCol.push(item.name);
      itemIdCol.push(item.itemid);
      valueTypeCol.push(String(item.value_type));
      nsCol.push(ns);
      if (String(item.value_type) === "2") {
        timestampCol.push(row.timestamp == null ? null : String(row.timestamp));
        sourceCol.push(row.source == null ? null : String(row.source));
        severityCol.push(row.severity == null ? null : String(row.severity));
        const logeventid = row.logeventid == null ? null : String(row.logeventid);
        logeventidCol.push(logeventid);
        eventIdCol.push(logeventid);
      } else {
        timestampCol.push(null);
        sourceCol.push(null);
        severityCol.push(null);
        logeventidCol.push(null);
        eventIdCol.push(null);
      }
    }
  }
  const order = times.map((_, i) => i).sort((a, b) => times[a] - times[b]);
  const pick = (arr) => order.map((i) => arr[i]);
  if (ctx.query.resultFormat === "table") {
    const lastByItem = /* @__PURE__ */ new Map();
    for (let i = 0; i < itemIdCol.length; i++) {
      lastByItem.set(itemIdCol[i], {
        host: hostCol[i],
        item: itemCol[i],
        key: String(
          items.find((it) => it.itemid === itemIdCol[i])?.key_ || ""
        ),
        value: values[i]
      });
    }
    const rows = [...lastByItem.values()];
    return [
      createDataFrame({
        refId: ctx.query.refId,
        fields: [
          { name: "Host", type: "string", values: rows.map((r) => r.host) },
          { name: "Item", type: "string", values: rows.map((r) => r.item) },
          { name: "Key", type: "string", values: rows.map((r) => r.key) },
          {
            name: "Last value",
            type: "string",
            values: rows.map((r) => r.value)
          }
        ]
      })
    ];
  }
  return [
    createDataFrame({
      refId: ctx.query.refId,
      fields: [
        { name: "Time", type: "time", values: pick(times) },
        { name: "Value", type: "string", values: pick(values) },
        { name: "Host", type: "string", values: pick(hostCol) },
        { name: "Item", type: "string", values: pick(itemCol) },
        { name: "ItemId", type: "string", values: pick(itemIdCol) },
        { name: "value_type", type: "string", values: pick(valueTypeCol) },
        { name: "ns", type: "string", values: pick(nsCol) },
        { name: "timestamp", type: "string", values: pick(timestampCol) },
        { name: "source", type: "string", values: pick(sourceCol) },
        { name: "severity", type: "string", values: pick(severityCol) },
        { name: "logeventid", type: "string", values: pick(logeventidCol) },
        { name: "EventId", type: "string", values: pick(eventIdCol) }
      ]
    })
  ];
}
function buildTriggerGetParams(ctx, groupids, hostids) {
  const opts = ctx.query.options || {};
  const nested = ctx.query.triggers || {
    minSeverity: 0,
    acknowledged: 2,
    count: false
  };
  const params = {
    // Slim payload: full selectHosts/Items/LastEvent extend freezes table panels on large fleets
    output: [
      "triggerid",
      "description",
      "priority",
      "lastchange",
      "value",
      "status",
      "state",
      "comments",
      "expression",
      "manual_close"
    ],
    selectHosts: ["hostid", "name"],
    selectTags: "extend",
    expandDescription: true,
    monitored: true,
    skipDependent: true,
    limit: 200
  };
  if (groupids.length) params.groupids = groupids;
  if (hostids.length) params.hostids = hostids;
  const show = ctx.query.showProblems || "problems";
  if (show === "problems")
    params.filter = { ...params.filter, value: 1 };
  else if (show === "recent" || show === "history")
    params.filter = { ...params.filter, value: [0, 1] };
  const minSeverity = opts.minSeverity ?? nested.minSeverity;
  if (minSeverity != null && Number(minSeverity) > 0) {
    params.min_severity = Number(minSeverity);
  }
  const ack = opts.acknowledged ?? nested.acknowledged;
  if (ack === 0 || ack === 1) {
    params.withLastEventUnacknowledged = ack === 0;
    params.only_true = true;
  }
  if (opts.hostsInMaintenance === false) params.maintenance = false;
  if (opts.useTimeRange) {
    params.lastChangeSince = Math.floor(
      (ctx.range.from instanceof Date ? ctx.range.from.getTime() : Number(ctx.range.from)) / 1e3
    );
    params.lastChangeTill = Math.floor(
      (ctx.range.to instanceof Date ? ctx.range.to.getTime() : Number(ctx.range.to)) / 1e3
    );
  }
  const triggerFilter = interpolateFilter(ctx.query.trigger, ctx.scopedVars);
  if (triggerFilter.filter)
    params.search = { description: triggerFilter.filter };
  if (triggerFilter.ids?.length) params.triggerids = triggerFilter.ids;
  const tagsFilter = interpolateZabbixValue(
    String(ctx.query.tags?.filter || ""),
    ctx.scopedVars
  );
  if (tagsFilter) {
    params.tags = tagsFilter.split(",").map((part) => {
      const [tag, ...rest] = part.split(":");
      return { tag: tag.trim(), value: rest.join(":").trim(), operator: 0 };
    });
    params.evaltype = ctx.query.evaltype === "2" ? 2 : 0;
  }
  const limit = Number(opts.limit ?? 100);
  if (Number.isFinite(limit) && limit > 0)
    params.limit = Math.min(1001, Math.floor(limit));
  let countMode = "";
  if (ctx.query.countTriggersBy === "items" || ctx.query.countTriggersBy === "problems") {
    countMode = ctx.query.countTriggersBy;
    params.countOutput = true;
  } else if (opts.count || nested.count) {
    countMode = "problems";
    params.countOutput = true;
  }
  return { params, countMode };
}
async function executeTriggersQuery(ctx) {
  assertBoundedHostScope(ctx.query, ctx.scopedVars);
  const hostF = interpolateFilter(ctx.query.host, ctx.scopedVars);
  const groupF = interpolateFilter(ctx.query.group, ctx.scopedVars);
  const groupAll = isMatchAllZabbixFilter(groupF.filter) && !groupF.ids?.length;
  const hostAll = isMatchAllZabbixFilter(hostF.filter) && !hostF.ids?.length;
  const groups = groupAll ? [] : await resolveGroups(ctx.api, ctx.query, ctx.scopedVars, ctx.signal);
  let hostids = [];
  if (!hostAll) {
    const hosts = await resolveHosts(
      ctx.api,
      ctx.query,
      ctx.scopedVars,
      groups.map((g) => g.groupid),
      ctx.signal
    );
    hostids = hosts.map((h) => String(h.hostid));
  }
  const { params, countMode } = buildTriggerGetParams(
    ctx,
    groups.map((g) => g.groupid),
    hostids
  );
  if (countMode === "items" || ctx.query.countTriggersBy === "items") {
    try {
      const itemGroupids = hostAll && !groupAll && groups.length ? groups.map((g) => String(g.groupid)) : void 0;
      const items = await resolveItems(
        ctx.api,
        ctx.query,
        ctx.scopedVars,
        hostids,
        [],
        ctx.signal,
        itemGroupids
      );
      const itemids = items.map((i) => String(i.itemid)).filter(Boolean);
      if (itemids.length) params.itemids = itemids;
    } catch {
    }
  }
  const result = await ctx.api.getTriggers(params, ctx.signal);
  if (countMode) {
    const count = typeof result === "number" ? result : Array.isArray(result) ? result.length : Number(result?.rows?.length ?? 0);
    return [
      createDataFrame({
        refId: ctx.query.refId,
        fields: [
          { name: "Time", type: "time", values: [Date.now()] },
          {
            name: "Value",
            type: "number",
            values: [count],
            labels: { countBy: countMode }
          }
        ]
      })
    ];
  }
  const list = Array.isArray(result) ? result : result?.rows || [];
  return [
    createDataFrame({
      refId: ctx.query.refId,
      meta: {
        source: "live",
        datasourceUid: ctx.instance.uid,
        truncated: Boolean(result?.truncated)
      },
      fields: [
        {
          name: "triggerid",
          type: "string",
          values: list.map((r) => String(r.triggerid ?? ""))
        },
        {
          name: "description",
          type: "string",
          values: list.map((r) => String(r.description ?? ""))
        },
        {
          name: "priority",
          type: "number",
          values: list.map((r) => Number(r.priority ?? 0))
        },
        {
          name: "lastchange",
          type: "time",
          values: list.map((r) => Number(r.lastchange || 0) * 1e3)
        },
        {
          name: "value",
          type: "string",
          values: list.map((r) => String(r.value ?? ""))
        },
        {
          name: "status",
          type: "string",
          values: list.map((r) => String(r.status ?? ""))
        },
        {
          name: "state",
          type: "string",
          values: list.map((r) => String(r.state ?? ""))
        },
        {
          name: "comments",
          type: "string",
          values: list.map((r) => String(r.comments ?? ""))
        },
        {
          name: "expression",
          type: "string",
          values: list.map((r) => String(r.expression ?? ""))
        },
        {
          name: "manual_close",
          type: "string",
          values: list.map((r) => String(r.manual_close ?? ""))
        },
        {
          name: "hosts",
          type: "string",
          values: list.map(
            (r) => (Array.isArray(r.hosts) ? r.hosts : []).map((h) => String(h?.name || h?.host || h?.hostid || "")).filter(Boolean).join(", ")
          )
        },
        {
          name: "groups",
          type: "string",
          values: list.map(
            (r) => (Array.isArray(r.groups) ? r.groups : Array.isArray(r.hostgroups) ? r.hostgroups : []).map((g) => String(g?.name || g?.groupid || "")).filter(Boolean).join(", ")
          )
        },
        {
          name: "items",
          type: "string",
          values: list.map(
            (r) => (Array.isArray(r.items) ? r.items : []).map((i) => String(i?.name || i?.key_ || i?.itemid || "")).filter(Boolean).slice(0, 5).join(", ")
          )
        },
        {
          name: "tags",
          type: "string",
          values: list.map(
            (r) => (Array.isArray(r.tags) ? r.tags : []).map(
              (tg) => `${tg?.tag ?? ""}${tg?.value != null && tg?.value !== "" ? ":" + tg.value : ""}`
            ).filter(Boolean).slice(0, 10).join(", ")
          )
        },
        {
          name: "lastEvent",
          type: "string",
          values: list.map((r) => {
            const e = r.lastEvent || {};
            if (!e || typeof e !== "object") return "";
            return String(e.eventid || e.clock || "");
          })
        }
      ]
    })
  ];
}
async function executeZabbixQuery(ctx) {
  const queryType = normalizeZabbixQueryType(
    ctx.query.queryType
  );
  if ((queryType === "0" || queryType === "3") && ctx.settings.dbConnectionEnable) {
    try {
      const direct = await executeDirectDbQuery(ctx);
      if (direct) return direct;
    } catch (e) {
      throw e instanceof DataSourceError ? e : new DataSourceError(
        "INVALID_QUERY",
        e instanceof Error ? e.message : String(e)
      );
    }
  }
  switch (queryType) {
    case "0":
      return executeMetricsQuery(ctx);
    case "1":
      return executeServicesQuery(ctx);
    case "2":
      return executeTextQuery(ctx);
    case "3":
      return executeItemIdQuery(ctx);
    case "4":
      return executeTriggersQuery(ctx);
    case "5":
      return executeProblemsQuery(ctx);
    case "6":
      return executeMacrosQuery(ctx);
    default: {
      const _exhaustive = queryType;
      throw new DataSourceError(
        "INVALID_QUERY",
        `未知 queryType: ${String(_exhaustive)}`
      );
    }
  }
}
async function runTargetPool(tasks, options) {
  const concurrency = Math.max(1, Math.floor(options.concurrency || 1));
  const results = /* @__PURE__ */ new Map();
  let next = 0;
  let running = 0;
  let rejected = null;
  if (options.signal?.aborted) {
    throw new DOMException("Aborted", "AbortError");
  }
  return new Promise((resolve, reject) => {
    const onAbort = () => {
      rejected = new DOMException("Aborted", "AbortError");
      finishIfDone();
    };
    options.signal?.addEventListener("abort", onAbort, { once: true });
    function finishIfDone() {
      if (rejected) {
        options.signal?.removeEventListener("abort", onAbort);
        reject(rejected);
        return;
      }
      if (running === 0 && next >= tasks.length) {
        options.signal?.removeEventListener("abort", onAbort);
        resolve(
          tasks.map((t) => ({
            refId: t.refId,
            value: results.get(t.refId)
          }))
        );
      }
    }
    function pump() {
      if (rejected) {
        finishIfDone();
        return;
      }
      while (running < concurrency && next < tasks.length) {
        const idx = next++;
        const task = tasks[idx];
        running += 1;
        void task.run().then((value) => {
          if (rejected) return;
          results.set(task.refId, value);
          try {
            options.onPartial?.(task.refId, value);
          } catch {
          }
        }).catch((err) => {
          if (!rejected) rejected = err;
        }).finally(() => {
          running -= 1;
          if (rejected) {
            finishIfDone();
          } else {
            pump();
            finishIfDone();
          }
        });
      }
      finishIfDone();
    }
    if (!tasks.length) {
      resolve([]);
      return;
    }
    pump();
  });
}
const ZABBIX_CAPABILITIES = {
  signals: ["metrics"],
  query: true,
  health: true,
  metadata: true,
  variables: true,
  annotations: true,
  exemplars: false,
  streaming: false,
  queryLanguages: ["zabbix-json-rpc"]
};
const metadataCache = new ZabbixMetadataCache();
function mergeSignals(a, b) {
  if (!a) return b;
  if (!b) return a;
  if (typeof AbortSignal !== "undefined" && "any" in AbortSignal && typeof AbortSignal.any === "function") {
    return AbortSignal.any([a, b]);
  }
  const c = new AbortController();
  const abort = () => c.abort();
  a.addEventListener("abort", abort);
  b.addEventListener("abort", abort);
  return c.signal;
}
function createZabbixDataSource(instance, meta2) {
  const settingsResult = migrateZabbixConfig(
    instance.jsonData || {}
  );
  const settings = settingsResult.options;
  const url = String(instance.url || "").replace(/\/$/, "");
  const dataMode = settings.dataMode === "fixture" ? "fixture" : "live";
  const useFixture = dataMode === "fixture";
  const transport = useFixture ? new OfflineZabbixTransport("default") : new ZabbixRpcClient({
    url,
    uid: instance.uid,
    timeoutMs: settings.timeout || 3e4,
    // allow network even when dashboard CRUD is offline
    forceNetwork: true
  });
  if (!useFixture && transport instanceof ZabbixRpcClient) {
    transport.setAuthPlacementOverride(
      settings.authPlacement || "auto"
    );
  }
  const api = new ZabbixApi({
    transport,
    uid: instance.uid,
    cache: metadataCache,
    metadataTtlMs: parseCacheTtlMs$1(settings.cacheTTL),
    metadataPageLimit: Number(settings.metadataPageLimit) || 1e3
  });
  function buildContext(query2, range, request, signal) {
    return {
      api,
      instance,
      settings,
      query: query2,
      range,
      maxDataPoints: request.maxDataPoints || 1e3,
      intervalMs: request.intervalMs || 1e3,
      scopedVars: request.scopedVars || {},
      signal,
      onPartialData: request.onPartialData
    };
  }
  async function query(request, signal) {
    const timeoutMs = settings.queryTimeout || 6e4;
    const timeoutCtrl = new AbortController();
    let timedOut = false;
    const timer = setTimeout(() => {
      timedOut = true;
      timeoutCtrl.abort();
    }, timeoutMs);
    const merged = mergeSignals(signal, timeoutCtrl.signal);
    try {
      const tasks = (request.targets || []).filter((target) => !target.hide).map((target) => {
        const migrated = migrateZabbixQuery(target);
        if (target.useTrends != null && migrated.options) {
          migrated.options.useTrends = String(
            target.useTrends
          );
        }
        return {
          refId: String(migrated.refId || "A"),
          run: async () => {
            try {
              const part = await executeZabbixQuery(
                buildContext(migrated, request.range, request, merged)
              );
              return normalizeDataFrames(part, {
                refId: migrated.refId,
                source: "zabbix",
                datasourceUid: instance.uid,
                signal: "metrics",
                requestId: request.requestId
              });
            } catch (e) {
              if (timedOut) {
                throw new DataSourceError(
                  "TIMEOUT",
                  `数据源请求在 ${timeoutMs}ms 后超时`
                );
              }
              throw withDataSourceContext(e, {
                uid: instance.uid,
                refId: migrated.refId
              });
            }
          }
        };
      });
      const concurrency = Math.min(
        4,
        Math.max(1, Number(settings.historyConcurrency ?? 2) || 2)
      );
      const settled = await runTargetPool(tasks, {
        concurrency,
        signal: merged,
        onPartial: (refId, value) => {
          try {
            request.onPartialData?.(value);
          } catch {
          }
          void refId;
        }
      });
      const frames = [];
      for (const item of settled) {
        frames.push(...item.value || []);
      }
      return { data: frames };
    } catch (e) {
      if (timedOut)
        throw new DataSourceError(
          "TIMEOUT",
          `数据源请求在 ${timeoutMs}ms 后超时`
        );
      if (e instanceof DataSourceError) throw e;
      throw withDataSourceContext(e, { uid: instance.uid });
    } finally {
      clearTimeout(timer);
    }
  }
  async function listHostGroups(filter2 = "") {
    const groups = await resolveGroups(
      api,
      migrateZabbixQuery({ group: { filter: filter2 } }),
      {},
      void 0
    );
    return groups.map((g) => ({ text: g.name, value: g.name, id: g.groupid }));
  }
  async function listHosts(groupFilter = "") {
    const q = migrateZabbixQuery({
      group: { filter: groupFilter },
      host: { filter: "" }
    });
    const groups = await resolveGroups(api, q, {});
    const hosts = await resolveHosts(
      api,
      q,
      {},
      groups.map((g) => g.groupid)
    );
    return hosts.map((h) => ({
      text: String(h.name || h.host),
      value: String(h.name || h.host),
      id: String(h.hostid)
    }));
  }
  async function listItems(hostFilter = "") {
    const q = migrateZabbixQuery({
      host: { filter: hostFilter },
      item: { filter: "" }
    });
    const hosts = await resolveHosts(api, q, {}, []);
    const hostids = hosts.map((h) => String(h.hostid));
    const items = await resolveItems(api, q, {}, hostids, []);
    return items.map((i) => ({ text: i.name, value: i.name, id: i.itemid }));
  }
  async function testDatasource(signal) {
    if (useFixture) {
      return { status: "success", message: "Zabbix fixture mode 可用" };
    }
    try {
      const version = await api.version(signal);
      await api.getGroups("", signal);
      const caps2 = api.transport?.getCapabilities?.() || null;
      return {
        status: "success",
        message: `Zabbix ${version} 认证成功`,
        details: {
          version,
          authMode: caps2?.selectedAuthPlacement || caps2?.authCandidates?.[0],
          capabilities: caps2 ? {
            supportsApiToken: caps2.supportsApiToken,
            loginUserField: caps2.loginUserField,
            slaApi: caps2.slaApi,
            triggerHostGroupsField: caps2.triggerHostGroupsField
          } : void 0
        }
      };
    } catch (e) {
      return {
        status: "error",
        message: e?.message || String(e)
      };
    }
  }
  async function metricFindQuery(query2, signal, context) {
    return executeZabbixVariableQuery(
      api,
      query2,
      context?.scopedVars || {},
      signal
    );
  }
  async function annotationQuery(request, signal) {
    return executeAnnotationQuery({
      api,
      range: request.range,
      annotation: request.annotation,
      instance,
      signal
    });
  }
  async function getMetadata(request, signal) {
    const withPage = (base, page) => ({
      ...base,
      complete: page.complete,
      truncated: page.truncated
    });
    switch (request.type) {
      case "groups": {
        const page = await api.getGroups(request.filter, signal);
        return withPage(
          {
            type: "groups",
            values: page.rows.map((g) => ({
              text: String(g.name),
              value: String(g.name),
              id: String(g.groupid)
            }))
          },
          page
        );
      }
      case "hosts": {
        const page = await api.getHosts(
          request.groupids,
          request.filter,
          request.hostTags,
          signal
        );
        return withPage(
          {
            type: "hosts",
            values: page.rows.map((h) => ({
              text: String(h.name || h.host),
              value: String(h.name || h.host),
              id: String(h.hostid)
            }))
          },
          page
        );
      }
      case "applications": {
        const page = await api.getApplications(
          request.hostids,
          request.filter,
          signal
        );
        return withPage(
          {
            type: "applications",
            values: page.rows.map((a) => ({
              text: String(a.name),
              value: String(a.name),
              id: String(a.applicationid)
            }))
          },
          page
        );
      }
      case "items": {
        const page = await api.getItems(
          {
            hostids: request.hostids,
            applicationids: request.applicationids,
            filter: request.filter,
            itemTag: request.itemTag,
            showDisabled: request.showDisabled
          },
          signal
        );
        return withPage(
          {
            type: "items",
            values: page.rows.map((i) => ({
              text: i.name,
              value: i.name,
              id: i.itemid
            }))
          },
          page
        );
      }
      case "discoveryRules": {
        const page = await api.getDiscoveryRules(request.hostids, signal);
        return withPage(
          {
            type: "discoveryRules",
            values: page.rows.map((r) => ({
              text: r.name,
              value: r.itemid,
              id: r.itemid
            }))
          },
          page
        );
      }
      case "itemPrototypes": {
        const page = await api.getItemPrototypes(
          request.discoveryRuleId,
          signal
        );
        return withPage(
          {
            type: "itemPrototypes",
            values: page.rows.map((r) => ({
              text: r.name,
              value: r.key_,
              id: r.itemid
            }))
          },
          page
        );
      }
      case "triggers": {
        const pageOrCount = await api.getTriggers(
          {
            hostids: request.hostids,
            search: request.filter ? { description: request.filter } : void 0,
            output: "extend",
            selectGroups: "extend"
          },
          signal
        );
        const page = typeof pageOrCount === "number" ? { rows: [], complete: true, truncated: false } : pageOrCount;
        return withPage(
          {
            type: "triggers",
            values: page.rows.map((t) => ({
              text: String(t.description || t.triggerid),
              value: String(t.description || t.triggerid),
              id: String(t.triggerid)
            }))
          },
          page
        );
      }
      case "proxies": {
        const page = await api.getProxies(request.filter, signal);
        return withPage(
          {
            type: "proxies",
            values: page.rows.map((p) => {
              const name = String(p.name || p.host || p.proxyid);
              return { text: name, value: name, id: String(p.proxyid) };
            })
          },
          page
        );
      }
      case "services": {
        const page = await api.getServices(signal);
        return withPage(
          {
            type: "services",
            values: page.rows.map((s) => ({
              text: String(s.name),
              value: String(s.name),
              id: String(s.serviceid)
            }))
          },
          page
        );
      }
      case "slas": {
        const page = await api.getSlas(
          request.serviceids,
          request.filter,
          signal
        );
        return withPage(
          {
            type: "slas",
            values: page.rows.map((s) => ({
              text: String(s.name || s.slaid),
              value: String(s.name || s.slaid),
              id: String(s.slaid)
            }))
          },
          page
        );
      }
      case "macros": {
        const page = await api.getMacros(
          request.hostids,
          request.filter,
          signal
        );
        return withPage(
          {
            type: "macros",
            values: page.rows.map((m) => ({
              text: String(m.macro),
              value: String(m.macro),
              id: String(m.hostmacroid || m.macro)
            }))
          },
          page
        );
      }
      case "scripts": {
        const page = await api.getScripts(
          request.hostid,
          request.eventid,
          signal
        );
        return withPage({ type: "scripts", values: page.rows }, page);
      }
      case "problemDetail": {
        const value = await api.getProblemDetail(request.eventid, signal);
        return { type: "problemDetail", value };
      }
      case "actionCapabilities": {
        const user = useFixture ? { type: "3" } : await api.getCurrentUser(signal);
        const readOnly = settings.disableReadOnlyUsersAck && String(user.type) === "1";
        return {
          type: "actionCapabilities",
          value: {
            canAcknowledge: !readOnly,
            canClose: !readOnly,
            canChangeSeverity: !readOnly,
            canExecuteScripts: !readOnly,
            readOnly,
            reason: useFixture ? "fixture preview" : void 0
          }
        };
      }
      default: {
        const _never = request;
        throw new DataSourceError(
          "INVALID_QUERY",
          `未知 metadata 请求: ${JSON.stringify(_never)}`
        );
      }
    }
  }
  function liveWritesAllowed() {
    if (typeof process !== "undefined" && process.env && process.env.ZABBIX_LIVE_WRITES === "1") {
      return true;
    }
    return false;
  }
  async function mutate(request) {
    if (!settings.enableWrites) {
      return {
        status: "blocked",
        message: "数据源未开启 enableWrites"
      };
    }
    if (!useFixture && !liveWritesAllowed()) {
      return {
        status: "blocked",
        message: "未设置 ZABBIX_LIVE_WRITES=1"
      };
    }
    if (request.action === "zabbix.acknowledge") {
      if (useFixture) {
        return {
          status: "success",
          message: "fixture preview",
          data: { eventids: request.payload?.eventids || [], preview: true }
        };
      }
      const data = await api.acknowledgeEvent(
        request.payload || {},
        request.signal
      );
      metadataCache.invalidate(instance.uid, [
        "problem.get",
        "event.get",
        "user.get"
      ]);
      return { status: "success", message: "已确认", data };
    }
    if (request.action === "zabbix.executeScript") {
      const scriptid = String(request.payload?.scriptid ?? "").trim();
      if (!scriptid) {
        return {
          status: "blocked",
          message: "scriptid 必填（禁止默认 scriptid=1）"
        };
      }
      if (useFixture) {
        return {
          status: "success",
          message: "fixture preview",
          data: { response: "fixture preview", preview: true, scriptid }
        };
      }
      const data = await api.executeScript(
        request.payload || {},
        request.signal
      );
      return { status: "success", message: "脚本已执行", data };
    }
    throw new DataSourceError(
      "INVALID_QUERY",
      `不支持的动作: ${request.action}`
    );
  }
  function dispose() {
    metadataCache.clearUid(instance.uid);
  }
  return {
    id: instance.id,
    uid: instance.uid,
    type: instance.type || meta2.id,
    name: instance.name,
    capabilities: ZABBIX_CAPABILITIES,
    /** Surface write flag for panel four-way gate. */
    enableWrites: Boolean(settings.enableWrites),
    query,
    testDatasource,
    metricFindQuery,
    annotationQuery,
    getMetadata,
    mutate,
    dispose,
    // legacy helpers used by editors/tests
    listHostGroups,
    listHosts,
    listItems,
    api
  };
}
const meta$1 = {
  id: "alexanderzobnin-zabbix-datasource",
  name: "Zabbix",
  metrics: true,
  backend: true,
  capabilities: ZABBIX_CAPABILITIES
};
const plugin$2 = createDataSourcePlugin({
  meta: meta$1,
  QueryEditor: QueryEditor$1,
  ConfigEditor: ConfigEditor$1,
  VariableQueryEditor: VariableQueryEditor$1,
  AnnotationQueryEditor: AnnotationQueryEditor$1,
  createDataSource: (instance) => createZabbixDataSource(instance, meta$1)
});
const module$3 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
  __proto__: null,
  default: plugin$2,
  plugin: plugin$2
}, Symbol.toStringTag, { value: "Module" }));
const DEFAULT_ISSUES_OPTIONS = {
  layout: "table",
  pageSize: 50,
  showTraceDetail: true,
  sources: { logs: true, traces: true, alerts: true },
  attributeFilters: [],
  severities: [],
  sort: "time",
  highlightNew: true,
  highlightWindowMs: 5 * 60 * 1e3,
  showAttributes: true,
  showTraceLink: true,
  showDatasource: false
};
function col(frame, name) {
  const field = frame.fields.find(
    (f) => f.name.toLowerCase() === name.toLowerCase()
  );
  return field?.values || [];
}
function getAt(frame, names, i) {
  for (const n of names) {
    const v = col(frame, n)[i];
    if (v != null && v !== "") return v;
  }
  return void 0;
}
function toMs$1(v) {
  const n = Number(v ?? 0);
  if (!Number.isFinite(n) || n <= 0) return 0;
  if (n >= 1e9 && n < 1e12) return n * 1e3;
  return n;
}
function severityRank(s) {
  const k = String(s || "").toLowerCase();
  if (k === "critical" || k === "fatal") return 5;
  if (k === "error") return 4;
  if (k === "warning" || k === "warn") return 3;
  if (k === "info") return 2;
  if (k === "ok" || k === "resolved") return 1;
  return 0;
}
function inferSource(frame, row) {
  const meta2 = frame.meta || {};
  const hint = String(
    meta2.signal || meta2.preferredVisualisationType || meta2.custom?.signal || ""
  ).toLowerCase();
  if (hint.includes("alert") || row.status === "firing" || row.status === "pending")
    return "alert";
  if (hint.includes("trace") || row.traceId) return "trace";
  if (hint.includes("log")) return "log";
  if (row.alertId) return "alert";
  if (row.traceId) return "trace";
  return "log";
}
function parseAttributes(raw) {
  if (!raw) return {};
  if (typeof raw === "object" && !Array.isArray(raw)) {
    const out = {};
    for (const [k, v] of Object.entries(raw))
      out[k] = String(v);
    return out;
  }
  if (typeof raw === "string") {
    try {
      return parseAttributes(JSON.parse(raw));
    } catch {
      return {};
    }
  }
  return {};
}
function matchAttr(filters, attrs, optionErrors) {
  for (const f of filters || []) {
    const val = attrs[f.key] ?? "";
    if (f.operator === "=") {
      if (val !== f.value) return false;
    } else if (f.operator === "!=") {
      if (val === f.value) return false;
    } else if (f.operator === "=~" || f.operator === "!~") {
      try {
        const re = new RegExp(f.value);
        const ok2 = re.test(val);
        if (f.operator === "=~" ? !ok2 : ok2) return false;
      } catch {
        optionErrors.push(`无效属性正则: ${f.key} ${f.operator} ${f.value}`);
        return true;
      }
    }
  }
  return true;
}
function isDefaultIncluded(issue) {
  const sev = String(issue.severity || "").toLowerCase();
  const status = String(issue.status || "").toLowerCase();
  if (issue.source === "log") {
    return sev === "error" || sev === "fatal" || sev === "critical";
  }
  if (issue.source === "trace") {
    return sev === "error" || status === "error" || status === "fault";
  }
  if (issue.source === "alert") {
    return status === "firing" || status === "pending";
  }
  return true;
}
function framesToIssues(frames = [], options = {}) {
  const opts = {
    ...DEFAULT_ISSUES_OPTIONS,
    ...options,
    sources: { ...DEFAULT_ISSUES_OPTIONS.sources, ...options.sources || {} }
  };
  const notices = [];
  const optionErrors = [];
  const byId2 = /* @__PURE__ */ new Map();
  for (const frame of frames) {
    const n = frame.length || frame.fields[0]?.values?.length || 0;
    if (!n) continue;
    const dsUid = String(frame.meta?.datasourceUid || "");
    const dsName = String(frame.meta?.datasourceName || "");
    for (let i = 0; i < n; i++) {
      const id = String(
        getAt(frame, ["id", "alertId", "alert_id", "eventId"], i) ?? `${dsUid}-${i}`
      );
      const title = String(
        getAt(frame, ["title", "name", "message", "body", "summary"], i) ?? ""
      );
      const service = String(
        getAt(frame, ["service", "serviceName", "service_name"], i) ?? ""
      );
      const severity = String(
        getAt(frame, ["severity", "priority", "level"], i) ?? ""
      );
      const status = String(getAt(frame, ["status", "state"], i) ?? "");
      const traceId = getAt(frame, ["traceId", "trace_id", "traceID"], i);
      const time = toMs$1(
        getAt(frame, ["Time", "time", "timestamp", "ts"], i) || Date.now()
      );
      const durationMs = Number(
        getAt(frame, ["duration", "durationMs", "duration_ms"], i) ?? NaN
      );
      const environment = getAt(frame, ["environment", "env"], i);
      const operation = getAt(frame, ["operation", "operationName", "name"], i);
      const alertId = getAt(frame, ["alertId", "alert_id"], i);
      const attributes = parseAttributes(
        getAt(frame, ["attributes", "labels", "tags"], i)
      );
      const draft = {
        id,
        title,
        service,
        severity,
        status,
        source: "log",
        traceId: traceId != null ? String(traceId) : void 0,
        time: time || Date.now(),
        durationMs: Number.isFinite(durationMs) ? durationMs : void 0,
        attributes,
        datasourceUid: dsUid || void 0,
        datasourceName: dsName || void 0,
        environment: environment != null ? String(environment) : void 0,
        operation: operation != null ? String(operation) : void 0,
        alertId: alertId != null ? String(alertId) : void 0
      };
      draft.source = inferSource(frame, draft);
      if (draft.source === "log" && !opts.sources.logs) continue;
      if (draft.source === "trace" && !opts.sources.traces) continue;
      if (draft.source === "alert" && !opts.sources.alerts) continue;
      if (!isDefaultIncluded(draft) && !(opts.severities || []).length) {
        if (["info", "ok", "resolved", "debug"].includes(
          String(draft.severity || draft.status).toLowerCase()
        )) {
          continue;
        }
        if (!isDefaultIncluded(draft)) continue;
      }
      if (opts.service && draft.service && draft.service !== opts.service)
        continue;
      if (opts.environment && draft.environment && draft.environment !== opts.environment)
        continue;
      if (opts.operation && draft.operation && draft.operation !== opts.operation)
        continue;
      if (opts.minDurationMs != null && (draft.durationMs ?? 0) < opts.minDurationMs)
        continue;
      if (opts.maxDurationMs != null && (draft.durationMs ?? Infinity) > opts.maxDurationMs)
        continue;
      if ((opts.severities || []).length) {
        const sev = String(draft.severity || "").toLowerCase();
        if (!opts.severities.map((s) => s.toLowerCase()).includes(sev))
          continue;
      }
      if (!matchAttr(
        opts.attributeFilters || [],
        draft.attributes || {},
        optionErrors
      ))
        continue;
      const prev = byId2.get(draft.id);
      if (!prev || draft.time >= prev.time) byId2.set(draft.id, draft);
    }
  }
  if (!frames.length) notices.push("无数据帧");
  let issues = Array.from(byId2.values());
  if (opts.sort === "severity") {
    issues.sort(
      (a, b) => severityRank(b.severity) - severityRank(a.severity) || b.time - a.time
    );
  } else if (opts.sort === "duration") {
    issues.sort(
      (a, b) => (b.durationMs || 0) - (a.durationMs || 0) || b.time - a.time
    );
  } else {
    issues.sort((a, b) => b.time - a.time);
  }
  if (opts.limit && opts.limit > 0) issues = issues.slice(0, opts.limit);
  return { issues, notices, optionErrors: Array.from(new Set(optionErrors)) };
}
function issuesFromPanelData(data, options) {
  return framesToIssues(data?.series || [], options);
}
function stableSerialize(value) {
  if (value === void 0) return "undefined";
  if (value === null || typeof value !== "object") return JSON.stringify(value);
  if (Array.isArray(value)) return `[${value.map(stableSerialize).join(",")}]`;
  const obj = value;
  const keys = Object.keys(obj).filter((k) => obj[k] !== void 0).sort();
  return `{${keys.map((k) => `${JSON.stringify(k)}:${stableSerialize(obj[k])}`).join(",")}}`;
}
function hashParams(params) {
  return stableSerialize(params || {});
}
function serializeCacheKey(key) {
  return stableSerialize({
    uid: key.uid,
    profile: key.profile,
    normalizedBaseUrl: key.normalizedBaseUrl,
    organizationId: key.organizationId || "",
    authMode: key.authMode || "",
    credentialRevision: key.credentialRevision || "",
    observedVersion: key.observedVersion || "",
    deploymentFingerprint: key.deploymentFingerprint || "",
    endpointContractHash: key.endpointContractHash || "",
    method: key.method,
    path: key.path,
    paramsHash: key.paramsHash
  });
}
function identityPrefix(id) {
  return stableSerialize({
    uid: id.uid,
    profile: id.profile,
    normalizedBaseUrl: id.normalizedBaseUrl,
    organizationId: id.organizationId || "",
    authMode: id.authMode || "",
    credentialRevision: id.credentialRevision || "",
    observedVersion: id.observedVersion || "",
    deploymentFingerprint: id.deploymentFingerprint || "",
    endpointContractHash: id.endpointContractHash || ""
  });
}
const MAX_ENTRIES = 500;
class SigNozMetadataCache {
  entries = /* @__PURE__ */ new Map();
  get(key) {
    const s = serializeCacheKey(key);
    const hit = this.entries.get(s);
    if (!hit) return void 0;
    if (hit.expiresAt <= Date.now()) {
      this.entries.delete(s);
      return void 0;
    }
    hit.lastAccess = Date.now();
    return hit.value;
  }
  set(key, value, ttlMs) {
    if (ttlMs <= 0) return;
    if (value == null) return;
    if (this.entries.size >= MAX_ENTRIES) this.evict();
    this.entries.set(serializeCacheKey(key), {
      value,
      expiresAt: Date.now() + ttlMs,
      lastAccess: Date.now()
    });
  }
  /** Clear all entries for a UID (identity change / auth failure). */
  clearUid(uid) {
    for (const k of [...this.entries.keys()]) {
      if (k.includes(`"uid":${JSON.stringify(uid)}`) || k.includes(`"uid":"${uid}"`)) {
        this.entries.delete(k);
      }
    }
  }
  clearIdentity(id) {
    const prefix = identityPrefix(id);
    for (const k of [...this.entries.keys()]) {
      if (k.startsWith(prefix.slice(0, 20)) || k.includes(`"uid":${JSON.stringify(id.uid)}`)) {
        if (k.includes(JSON.stringify(id.uid)) && k.includes(JSON.stringify(id.profile))) {
          this.entries.delete(k);
        }
      }
    }
  }
  clearAll() {
    this.entries.clear();
  }
  size() {
    return this.entries.size;
  }
  evict() {
    let oldestKey = null;
    let oldest = Infinity;
    for (const [k, v] of this.entries) {
      if (v.lastAccess < oldest) {
        oldest = v.lastAccess;
        oldestKey = k;
      }
    }
    if (oldestKey) this.entries.delete(oldestKey);
  }
}
const sharedSigNozMetadataCache = new SigNozMetadataCache();
function validateHealthV1(status, data) {
  if (status < 200 || status >= 300) {
    throw new DataSourceError("UPSTREAM_ERROR", `health v1 HTTP ${status}`, {
      status
    });
  }
  if (data == null || typeof data !== "object") {
    throw new DataSourceError(
      "INVALID_RESPONSE",
      "health v1 body missing or not object"
    );
  }
  const st = String(data.status ?? "").toLowerCase();
  if (st !== "ok") {
    throw new DataSourceError(
      "INVALID_RESPONSE",
      `health v1 status must be 'ok', got ${st || "empty"}`
    );
  }
}
function validateHealthV2(status, data) {
  if (status === 503) {
    throw new DataSourceError(
      "UPSTREAM_ERROR",
      "health v2 reports unhealthy (503)",
      { status: 503 }
    );
  }
  if (status < 200 || status >= 300) {
    throw new DataSourceError("UPSTREAM_ERROR", `health v2 HTTP ${status}`, {
      status
    });
  }
  if (data == null || typeof data !== "object") {
    throw new DataSourceError(
      "INVALID_RESPONSE",
      "health v2 body missing or not object"
    );
  }
  const o = data;
  const st = String(o.status ?? "").toLowerCase();
  if (st !== "success") {
    throw new DataSourceError(
      "INVALID_RESPONSE",
      `health v2 status must be 'success', got ${st || "empty"}`
    );
  }
  const d = o.data;
  if (d == null || typeof d !== "object") {
    throw new DataSourceError(
      "INVALID_RESPONSE",
      "health v2 data.healthy missing"
    );
  }
  if (d.healthy !== true) {
    throw new DataSourceError(
      "INVALID_RESPONSE",
      "health v2 data.healthy must be true"
    );
  }
}
function isFallbackStatus(status) {
  return status === 404 || status === 405 || status === 501;
}
function parseVersionPayload(data) {
  if (data == null || typeof data !== "object") return {};
  const o = data;
  const nested = o.data && typeof o.data === "object" ? o.data : o;
  return {
    version: nested.version != null ? String(nested.version) : o.version != null ? String(o.version) : void 0,
    ee: nested.ee != null ? Boolean(nested.ee) : o.ee != null ? Boolean(o.ee) : void 0,
    setupCompleted: nested.setupCompleted != null ? Boolean(nested.setupCompleted) : o.setupCompleted != null ? Boolean(o.setupCompleted) : void 0
  };
}
function healthCandidatesFor(profile, opts) {
  const list = profile.endpoints.healthCandidates?.length ? profile.endpoints.healthCandidates : profile.endpoints.health ? [profile.endpoints.health] : [];
  let ordered = list.map((h) => {
    const path = h.path;
    const kind = path.includes("healthz") || path.includes("v2") ? "v2" : path.includes("v1") ? "v1" : "other";
    return { path, method: h.method, kind };
  });
  if (opts?.preferV1First) {
    ordered = [...ordered].sort(
      (a, b) => a.kind === "v1" ? -1 : b.kind === "v1" ? 1 : 0
    );
  }
  return ordered;
}
async function probeHealth(http, profile, opts) {
  const candidates = healthCandidatesFor(profile, opts);
  if (!candidates.length) {
    return {
      ok: false,
      path: "",
      fatal: true,
      reason: "no health endpoint",
      reasonCode: "NO_HEALTH"
    };
  }
  let last = {
    ok: false,
    path: candidates[0].path,
    fatal: true,
    reason: "no candidate succeeded"
  };
  for (const c of candidates) {
    try {
      const res = await http({
        path: c.path,
        method: c.method || "GET",
        signal: opts?.signal
      });
      const status = Number(res.status || 0);
      if (status === 401 || status === 403) {
        return {
          ok: false,
          path: c.path,
          fatal: true,
          status,
          reason: "authentication failed",
          reasonCode: "AUTH"
        };
      }
      if (status === 429) {
        return {
          ok: false,
          path: c.path,
          fatal: true,
          status,
          reason: "rate limited",
          reasonCode: "RATE_LIMITED"
        };
      }
      if (status >= 500 && status !== 503) {
        return {
          ok: false,
          path: c.path,
          fatal: true,
          status,
          reason: `server error ${status}`,
          reasonCode: "UPSTREAM_ERROR"
        };
      }
      if (isFallbackStatus(status)) {
        last = {
          ok: false,
          path: c.path,
          fatal: false,
          status,
          reason: `fallback status ${status}`
        };
        continue;
      }
      try {
        if (c.kind === "v2") validateHealthV2(status, res.data);
        else if (c.kind === "v1") validateHealthV1(status, res.data);
        else if (status < 200 || status >= 300) {
          throw new DataSourceError("UPSTREAM_ERROR", `health HTTP ${status}`);
        }
        return { ok: true, path: c.path, details: { status, kind: c.kind } };
      } catch (e) {
        const msg = e instanceof Error ? e.message : String(e);
        if (e instanceof DataSourceError && e.code === "INVALID_RESPONSE") {
          last = { ok: false, path: c.path, fatal: false, status, reason: msg };
          continue;
        }
        return {
          ok: false,
          path: c.path,
          fatal: true,
          status,
          reason: msg,
          reasonCode: e instanceof DataSourceError ? e.code : "UPSTREAM_ERROR"
        };
      }
    } catch (e) {
      const msg = e instanceof Error ? e.message : String(e);
      const code = e instanceof DataSourceError ? e.code : void 0;
      if (code === "AUTH_REQUIRED" || code === "AUTH_REJECTED" || /401|403|AUTH/i.test(msg)) {
        return {
          ok: false,
          path: c.path,
          fatal: true,
          reason: msg,
          reasonCode: "AUTH"
        };
      }
      last = { ok: false, path: c.path, fatal: false, reason: msg };
    }
  }
  return last;
}
function buildCapabilityIdentity(args) {
  return {
    uid: args.uid,
    profile: String(args.options.apiProfile || ""),
    normalizedBaseUrl: String(args.baseUrl || "").replace(/\/+$/, ""),
    organizationId: args.options.organizationId || "",
    authMode: args.options.credentialKind || "",
    credentialRevision: args.credentialRevision || "",
    observedVersion: args.observedVersion || "",
    deploymentFingerprint: args.deploymentFingerprint || "",
    endpointContractHash: args.endpointContractHash || ""
  };
}
function capabilityIdentityKey(id) {
  return identityPrefix(id);
}
function parseCacheTtlMs(raw, fallback = 3e5) {
  if (typeof raw === "number" && Number.isFinite(raw))
    return Math.max(0, Math.floor(raw));
  const s = String(raw ?? "").trim();
  if (!s) return fallback;
  const m = s.match(/^(\d+(?:\.\d+)?)(ms|s|m|h|d)$/i);
  if (!m) return fallback;
  const n = Number(m[1]);
  const scale = {
    ms: 1,
    s: 1e3,
    m: 6e4,
    h: 36e5,
    d: 864e5
  };
  return Math.floor(n * scale[m[2].toLowerCase()]);
}
function parseTimeoutMs(raw, fallback = 3e4) {
  const n = Number(raw);
  if (!Number.isFinite(n) || n <= 0) return fallback;
  return Math.floor(n);
}
function resolveLiveExportCapabilities(args) {
  const exp = args.options?.experimentalCapabilities || {};
  const ep = args.profile.endpoints;
  return {
    sseVerified: Boolean(exp.liveTailSse && ep.liveTail?.path),
    legacySseEnabled: Boolean(exp.liveTailLegacy && ep.liveTailLegacy?.path),
    // cursor poll available when logs query_range exists (raw/raw_stream)
    cursorPoll: Boolean(ep.logsQuery?.path || ep.metricsQuery?.path),
    exportRawVerified: Boolean(exp.exportRaw && ep.exportRaw?.path),
    liveTailPath: ep.liveTail?.path,
    legacyLiveTailPath: ep.liveTailLegacy?.path,
    exportRawPath: ep.exportRaw?.path
  };
}
const WATERFALL_ENDPOINT_SPECS = {
  "v3-waterfall": {
    id: "v3-waterfall",
    method: "POST",
    path: "/api/v3/traces/{traceId}/waterfall",
    buildBody: (state2) => ({
      selectedSpanId: state2.selectedSpanId ?? "",
      uncollapsedSpans: sortUnique(state2.uncollapsedSpans ?? []),
      aggregations: canonicalizeAggregations(state2.aggregations).slice(0, 10),
      limit: Math.min(state2.limit ?? 1e4, 1e4)
    })
  },
  "v4-waterfall": {
    id: "v4-waterfall",
    method: "POST",
    path: "/api/v4/traces/{traceId}/waterfall",
    buildBody: (state2) => ({
      selectedSpanId: state2.selectedSpanId ?? "",
      uncollapsedSpans: sortUnique(state2.uncollapsedSpans ?? [])
    })
  }
};
const ALLOWED_AGG = /* @__PURE__ */ new Set([
  "span_count",
  "execution_time_percentage",
  "duration"
]);
function sortUnique(ids) {
  return [...new Set(ids.map(String).filter(Boolean))].sort();
}
function canonicalizeAggregations(aggs) {
  if (!aggs?.length) return [];
  const out = [];
  for (const a of aggs) {
    const t = typeof a === "string" ? a : a?.type;
    if (ALLOWED_AGG.has(t)) out.push({ type: t });
  }
  return out;
}
function waterfallCandidateIds(hasObservedV3Evidence) {
  return hasObservedV3Evidence ? ["v3-waterfall", "v4-waterfall"] : ["v4-waterfall", "v3-waterfall"];
}
function buildWaterfallPath(spec, traceId) {
  return spec.path.replace("{traceId}", encodeURIComponent(traceId));
}
function isRouteUnsupportedStatus(status) {
  return status === 404 || status === 405 || status === 501;
}
function shouldTryNextWaterfallCandidate(status, err) {
  if (isRouteUnsupportedStatus(status)) return true;
  const msg = String(err?.message || "");
  if (/unsupported|not found|no route|schema/i.test(msg) && !/401|403|429|5\d\d/.test(msg))
    return true;
  if (status === 401 || status === 403 || status === 429 || status >= 500)
    return false;
  return false;
}
function waterfallCapabilityKey(identity) {
  return capabilityIdentityKey(identity);
}
function waterfallResponseCacheKey(args) {
  const v4 = args.normalizeForV4 || args.resolvedEndpointId === "v4-waterfall";
  return hashParams({
    capabilityKey: args.capabilityKey,
    resolvedEndpoint: args.resolvedEndpointId,
    traceId: args.traceId,
    selectedSpanId: args.state.selectedSpanId ?? "",
    uncollapsedSpans: sortUnique(args.state.uncollapsedSpans ?? []),
    limit: v4 ? "" : Math.min(args.state.limit ?? 1e4, 1e4),
    aggregations: v4 ? [] : canonicalizeAggregations(args.state.aggregations)
  });
}
function createMemoryWaterfallCache() {
  const resolved = /* @__PURE__ */ new Map();
  const details = /* @__PURE__ */ new Map();
  return {
    getResolved: (k) => resolved.get(k),
    setResolved: (k, v) => resolved.set(k, v),
    getDetail: (k) => details.get(k),
    setDetail: (k, v) => details.set(k, v),
    clearIdentity: (prefix) => {
      for (const k of [...resolved.keys()])
        if (k.includes(prefix) || k === prefix) resolved.delete(k);
      for (const k of [...details.keys()])
        if (k.includes(prefix) || k.startsWith(prefix)) details.delete(k);
    }
  };
}
function mapWaterfallPayload(data, candidateId, path, status) {
  const root = data && typeof data === "object" ? data : {};
  const payload = root.data && typeof root.data === "object" ? root.data : root;
  const spansRaw = payload.spans || payload.spanList || payload.events || [];
  const list = Array.isArray(spansRaw) ? spansRaw : [];
  const spans = list.map((s) => {
    const durationNano = s.duration_nano != null ? String(s.duration_nano) : s.durationNano != null ? String(s.durationNano) : s.duration != null && Number(s.duration) > 1e6 ? String(s.duration) : String(Math.round(Number(s.durationMs || s.duration || 0) * 1e6));
    const timeUnixMs = (() => {
      const t = s.time_unix ?? s.timeUnix ?? s.startTimeUnixNano ?? s.startTime ?? s.timestamp;
      if (t == null) return 0;
      const n = Number(t);
      if (!Number.isFinite(n)) return 0;
      if (n > 1e15) return Math.floor(n / 1e6);
      if (n > 1e12) return Math.floor(n / 1e3);
      return Math.floor(n);
    })();
    const durationMs = Number(durationNano) / 1e6;
    return {
      spanId: String(s.spanId ?? s.span_id ?? s.id ?? ""),
      parentSpanId: String(
        s.parentSpanId ?? s.parent_span_id ?? s.parentId ?? ""
      ),
      name: String(s.name ?? s.operationName ?? s.operation_name ?? ""),
      service: String(
        s.serviceName ?? s.service_name ?? s.service ?? s.resource?.["service.name"] ?? ""
      ),
      timeUnixMs,
      durationNano,
      durationMs: Number.isFinite(durationMs) ? durationMs : Number(s.durationMs || s.duration || 0),
      statusCode: s.statusCode != null ? String(s.statusCode) : s.status?.code != null ? String(s.status.code) : void 0,
      hasError: Boolean(
        s.hasError ?? s.error ?? (s.statusCode === 2 || s.status?.code === 2)
      ),
      resource: s.resource && typeof s.resource === "object" ? s.resource : void 0,
      attributes: s.attributes || s.tags || void 0,
      events: Array.isArray(s.events) ? s.events : void 0,
      links: Array.isArray(s.links) ? s.links : void 0,
      references: Array.isArray(s.references) ? s.references : void 0,
      raw: s
    };
  });
  return {
    candidateId,
    path,
    status,
    startMs: payload.start != null ? Number(payload.start) : spans[0]?.timeUnixMs,
    endMs: payload.end != null ? Number(payload.end) : spans.length ? Math.max(...spans.map((x) => x.timeUnixMs + x.durationMs)) : void 0,
    rootService: payload.rootService || payload.root_service || spans.find((s) => !s.parentSpanId)?.service,
    entryPoint: payload.entryPoint || payload.entry_point || spans.find((s) => !s.parentSpanId)?.name,
    missingCount: payload.missingCount ?? payload.missing_count,
    totalCount: payload.totalCount ?? payload.total_count ?? spans.length,
    errorCount: payload.errorCount ?? payload.error_count ?? spans.filter((s) => s.hasError).length,
    uncollapsed: Array.isArray(payload.uncollapsedSpans) ? payload.uncollapsedSpans.map(String) : void 0,
    hasMore: Boolean(payload.hasMore ?? payload.has_more),
    spans,
    raw: data
  };
}
function waterfallDetailToFrames(detail, refId = "Trace") {
  const spans = detail.spans;
  return [
    createDataFrame({
      refId,
      name: "waterfall",
      meta: {
        source: "live",
        preferredVisualisationType: "trace",
        signal: "traces",
        waterfall: {
          candidateId: detail.candidateId,
          path: detail.path,
          status: detail.status,
          rootService: detail.rootService,
          entryPoint: detail.entryPoint,
          missingCount: detail.missingCount,
          totalCount: detail.totalCount,
          errorCount: detail.errorCount,
          hasMore: detail.hasMore
        }
      },
      fields: [
        { name: "spanId", type: "string", values: spans.map((s) => s.spanId) },
        {
          name: "parentSpanId",
          type: "string",
          values: spans.map((s) => s.parentSpanId)
        },
        { name: "name", type: "string", values: spans.map((s) => s.name) },
        {
          name: "serviceName",
          type: "string",
          values: spans.map((s) => s.service)
        },
        {
          name: "service",
          type: "string",
          values: spans.map((s) => s.service)
        },
        {
          name: "startTime",
          type: "number",
          values: spans.map((s) => s.timeUnixMs)
        },
        {
          name: "duration",
          type: "number",
          values: spans.map((s) => s.durationMs)
        },
        {
          name: "duration_nano",
          type: "string",
          values: spans.map((s) => s.durationNano)
        },
        {
          name: "statusCode",
          type: "string",
          values: spans.map((s) => s.statusCode ?? "")
        },
        {
          name: "attributes",
          type: "string",
          values: spans.map(
            (s) => s.attributes ? JSON.stringify(s.attributes) : ""
          )
        },
        {
          name: "events",
          type: "string",
          values: spans.map((s) => s.events ? JSON.stringify(s.events) : "")
        },
        {
          name: "links",
          type: "string",
          values: spans.map((s) => s.links ? JSON.stringify(s.links) : "")
        },
        {
          name: "references",
          type: "string",
          values: spans.map(
            (s) => s.references ? JSON.stringify(s.references) : ""
          )
        }
      ]
    })
  ];
}
async function fetchWaterfall(args) {
  const traceId = String(args.traceId || "").trim();
  if (!traceId) throw new DataSourceError("INVALID_QUERY", "traceId required");
  const cache = args.cache || createMemoryWaterfallCache();
  const capKey = waterfallCapabilityKey(args.identity);
  const state2 = args.state || {};
  const resolved = cache.getResolved(capKey);
  const preferred = args.preferredCandidateId || resolved?.id;
  let candidates = waterfallCandidateIds(Boolean(args.hasObservedV3Evidence));
  if (preferred && candidates.includes(preferred)) {
    candidates = [
      preferred,
      ...candidates.filter((c) => c !== preferred)
    ];
  }
  let lastErr = null;
  for (const id of candidates) {
    const spec = WATERFALL_ENDPOINT_SPECS[id];
    const path = buildWaterfallPath(spec, traceId);
    const body = spec.buildBody(state2);
    const respKey = waterfallResponseCacheKey({
      capabilityKey: capKey,
      resolvedEndpointId: id,
      traceId,
      state: state2,
      normalizeForV4: id === "v4-waterfall"
    });
    const cached = cache.getDetail(respKey);
    if (cached) return cached;
    try {
      const res = await args.http({
        path,
        method: spec.method,
        body,
        signal: args.signal
      });
      const status = Number(res.status || 0);
      if (status === 401 || status === 403) {
        throw new DataSourceError("AUTH", `waterfall HTTP ${status}`, {
          status
        });
      }
      if (status === 429 || status >= 500) {
        throw new DataSourceError(
          "UPSTREAM_ERROR",
          `waterfall HTTP ${status}`,
          { status }
        );
      }
      if (isRouteUnsupportedStatus(status)) {
        lastErr = new DataSourceError(
          "UNSUPPORTED_CAPABILITY",
          `waterfall ${id} HTTP ${status}`,
          { status }
        );
        continue;
      }
      if (status < 200 || status >= 300) {
        if (shouldTryNextWaterfallCandidate(status)) {
          lastErr = new DataSourceError(
            "UNSUPPORTED_CAPABILITY",
            `waterfall ${id} HTTP ${status}`,
            { status }
          );
          continue;
        }
        throw new DataSourceError(
          "UPSTREAM_ERROR",
          `waterfall HTTP ${status}`,
          { status }
        );
      }
      const detail = mapWaterfallPayload(res.data, id, path, status);
      cache.setResolved(capKey, {
        id,
        path: spec.path,
        method: spec.method,
        observedAt: (/* @__PURE__ */ new Date()).toISOString()
      });
      cache.setDetail(respKey, detail);
      return detail;
    } catch (e) {
      if (e instanceof DataSourceError && (e.code === "AUTH" || e.code === "UPSTREAM_ERROR"))
        throw e;
      if (e?.name === "AbortError" || e?.code === "CANCELLED") throw e;
      const status = Number(e?.status || e?.meta?.status || 0);
      if (shouldTryNextWaterfallCandidate(status, e)) {
        lastErr = e instanceof Error ? e : new Error(String(e));
        continue;
      }
      throw e;
    }
  }
  throw lastErr || new DataSourceError(
    "UNSUPPORTED_CAPABILITY",
    "no waterfall candidate succeeded"
  );
}
async function fetchRelatedLogs(args) {
  const traceId = String(args.traceId || "").trim();
  if (!traceId)
    throw new DataSourceError(
      "INVALID_QUERY",
      "traceId required for related logs"
    );
  if (!args.logsQueryPath) {
    throw new DataSourceError(
      "UNSUPPORTED_CAPABILITY",
      "related logs 需要 logs query_range path"
    );
  }
  const margin = args.safetyMarginMs ?? 6e4;
  const start = Math.max(0, args.fromMs - margin);
  const end = args.toMs + margin;
  const filter2 = `trace_id = '${traceId.replace(/'/g, "\\'")}' OR traceId = '${traceId.replace(/'/g, "\\'")}'`;
  let cursor = null;
  const allRows = [];
  const maxPages = args.maxPages ?? 50;
  for (let page = 0; page < maxPages; page++) {
    const body = {
      start,
      end,
      requestType: "raw",
      compositeQuery: {
        queries: [
          {
            type: "builder_query",
            queryType: "builder",
            spec: {
              name: "A",
              signal: "logs",
              filter: { expression: filter2 },
              disabled: false,
              cursor: cursor || void 0,
              limit: 100
            }
          }
        ]
      }
    };
    const res = await args.http({
      path: args.logsQueryPath,
      method: "POST",
      body,
      signal: args.signal
    });
    const status = Number(res.status || 200);
    if (status === 401 || status === 403) {
      throw new DataSourceError("AUTH", `related logs HTTP ${status}`, {
        status
      });
    }
    if (status < 200 || status >= 300) {
      throw new DataSourceError(
        "UPSTREAM_ERROR",
        `related logs HTTP ${status}`,
        { status }
      );
    }
    const data = res.data;
    const results = data?.data?.data?.results ?? data?.data?.results ?? data?.results ?? [];
    const first = Array.isArray(results) ? results[0] : null;
    const rows = first?.rows || first?.data || [];
    if (Array.isArray(rows)) allRows.push(...rows);
    const next = first?.nextCursor ?? first?.cursor ?? null;
    if (!next || next === cursor) break;
    cursor = next;
  }
  const times = allRows.map(
    (r) => Number(r.timestamp ?? r.time ?? r.ts ?? start)
  );
  const lines = allRows.map(
    (r) => String(
      r.body ?? r.message ?? r.line ?? (typeof r === "string" ? r : JSON.stringify(r))
    )
  );
  const services = allRows.map(
    (r) => String(
      r.service ?? r.resources_string?.["service.name"] ?? r["service.name"] ?? ""
    )
  );
  const severities = allRows.map((r) => String(r.severity ?? r.level ?? ""));
  const spanIds = allRows.map((r) => String(r.span_id ?? r.spanId ?? ""));
  return [
    createDataFrame({
      name: "related_logs",
      meta: {
        source: "live",
        signal: "logs",
        relatedTraceId: traceId,
        rowCount: allRows.length
      },
      fields: [
        { name: "Time", type: "time", values: times },
        { name: "Line", type: "string", values: lines },
        { name: "service", type: "string", values: services },
        { name: "severity", type: "string", values: severities },
        { name: "traceId", type: "string", values: allRows.map(() => traceId) },
        { name: "spanId", type: "string", values: spanIds }
      ]
    })
  ];
}
function issuesWriteEnabled(args) {
  const id = String(args.profileId);
  if (id === "signoz-v3" || id === "signoz-v4" || id === "signoz-v5" || id === "prometheus-compatible") {
    return { acknowledge: false, resolve: false };
  }
  const base = Boolean(args.enableWrites) && Boolean(args.envGate) && Boolean(args.actionCapabilityVerified);
  return {
    acknowledge: base && Boolean(args.hasAcknowledgeEndpoint),
    resolve: base && Boolean(args.hasResolveEndpoint)
  };
}
function resolveApi(preferredUid) {
  if (preferredUid) {
    const byUid2 = getRuntimeDataSource(String(preferredUid));
    if (byUid2?.mutate) return byUid2;
  }
  const all = listRuntimeDataSources();
  return all.find(
    (ds2) => ds2?.mutate && (ds2.type === "signoz" || String(ds2.uid || "").includes("signoz"))
  ) || all.find((ds2) => ds2?.mutate);
}
async function runIssueAction(issue, action, message, gate) {
  if (issue.source !== "alert") {
    return {
      status: "error",
      message: "仅 alert 来源支持动作（trace/log issue 只读）"
    };
  }
  const api = resolveApi(issue.datasourceUid);
  if (!api?.mutate) {
    return { status: "error", message: "当前数据源不支持动作" };
  }
  const alertId = issue.alertId || issue.id;
  const res = await api.mutate({
    action,
    payload: { alertId, source: "alert", message }
  });
  if (res?.status !== "success") {
    return { status: "error", message: res?.message || "动作失败" };
  }
  return { status: "success", message: res.message || "ok", data: res.data };
}
const _hoisted_1$q = {
  class: "tbl",
  "data-testid": "issues-table"
};
const _hoisted_2$l = { key: 0 };
const _hoisted_3$h = ["data-testid", "onClick"];
const _hoisted_4$d = { key: 0 };
const _hoisted_5$c = ["onClick"];
const _hoisted_6$a = ["onClick"];
const _hoisted_7$8 = {
  key: 1,
  class: "ro"
};
const _sfc_main$r = /* @__PURE__ */ defineComponent({
  __name: "IssuesTable",
  props: {
    items: {},
    options: {}
  },
  emits: ["select", "acknowledge", "resolve"],
  setup(__props, { emit: __emit }) {
    const emit = __emit;
    function sevColor(sev) {
      const s = String(sev || "").toLowerCase();
      if (s === "critical" || s === "fatal") return "#d32f2f";
      if (s === "error") return "#f44336";
      if (s === "warning" || s === "warn") return "#ff9800";
      if (s === "info") return "#2196f3";
      return "#9e9e9e";
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("table", _hoisted_1$q, [
        createElementVNode("thead", null, [
          createElementVNode("tr", null, [
            _cache[1] || (_cache[1] = createElementVNode(
              "th",
              null,
              "时间",
              -1
              /* CACHED */
            )),
            _cache[2] || (_cache[2] = createElementVNode(
              "th",
              null,
              "来源",
              -1
              /* CACHED */
            )),
            _cache[3] || (_cache[3] = createElementVNode(
              "th",
              null,
              "服务",
              -1
              /* CACHED */
            )),
            _cache[4] || (_cache[4] = createElementVNode(
              "th",
              null,
              "标题",
              -1
              /* CACHED */
            )),
            _cache[5] || (_cache[5] = createElementVNode(
              "th",
              null,
              "严重性",
              -1
              /* CACHED */
            )),
            _cache[6] || (_cache[6] = createElementVNode(
              "th",
              null,
              "状态",
              -1
              /* CACHED */
            )),
            __props.options.showDatasource ? (openBlock(), createElementBlock("th", _hoisted_2$l, "数据源")) : createCommentVNode("v-if", true),
            _cache[7] || (_cache[7] = createElementVNode(
              "th",
              null,
              "动作",
              -1
              /* CACHED */
            ))
          ])
        ]),
        createElementVNode("tbody", null, [
          (openBlock(true), createElementBlock(
            Fragment,
            null,
            renderList(__props.items, (issue) => {
              return openBlock(), createElementBlock("tr", {
                key: issue.id,
                "data-testid": `issue-${issue.id}`,
                onClick: ($event) => emit("select", issue)
              }, [
                createElementVNode(
                  "td",
                  null,
                  toDisplayString(new Date(issue.time).toLocaleString()),
                  1
                  /* TEXT */
                ),
                createElementVNode(
                  "td",
                  null,
                  toDisplayString(issue.source),
                  1
                  /* TEXT */
                ),
                createElementVNode(
                  "td",
                  null,
                  toDisplayString(issue.service),
                  1
                  /* TEXT */
                ),
                createElementVNode(
                  "td",
                  null,
                  toDisplayString(issue.title),
                  1
                  /* TEXT */
                ),
                createElementVNode("td", null, [
                  createElementVNode(
                    "span",
                    {
                      class: "sev",
                      style: normalizeStyle({ background: sevColor(issue.severity) })
                    },
                    toDisplayString(issue.severity || "—"),
                    5
                    /* TEXT, STYLE */
                  )
                ]),
                createElementVNode(
                  "td",
                  null,
                  toDisplayString(issue.status),
                  1
                  /* TEXT */
                ),
                __props.options.showDatasource ? (openBlock(), createElementBlock(
                  "td",
                  _hoisted_4$d,
                  toDisplayString(issue.datasourceName || issue.datasourceUid),
                  1
                  /* TEXT */
                )) : createCommentVNode("v-if", true),
                createElementVNode("td", {
                  onClick: _cache[0] || (_cache[0] = withModifiers(() => {
                  }, ["stop"]))
                }, [
                  issue.source === "alert" ? (openBlock(), createElementBlock(
                    Fragment,
                    { key: 0 },
                    [
                      createElementVNode("button", {
                        type: "button",
                        "data-testid": "issue-ack",
                        onClick: ($event) => emit("acknowledge", issue)
                      }, " 确认 ", 8, _hoisted_5$c),
                      createElementVNode("button", {
                        type: "button",
                        "data-testid": "issue-resolve",
                        onClick: ($event) => emit("resolve", issue)
                      }, " 解决 ", 8, _hoisted_6$a)
                    ],
                    64
                    /* STABLE_FRAGMENT */
                  )) : (openBlock(), createElementBlock("span", _hoisted_7$8, "只读"))
                ])
              ], 8, _hoisted_3$h);
            }),
            128
            /* KEYED_FRAGMENT */
          ))
        ])
      ]);
    };
  }
});
const IssuesTable = /* @__PURE__ */ _export_sfc(_sfc_main$r, [["__scopeId", "data-v-52987685"]]);
const _hoisted_1$p = {
  class: "list",
  "data-testid": "issues-list"
};
const _hoisted_2$k = ["data-testid", "onClick"];
const _hoisted_3$g = { class: "title" };
const _hoisted_4$c = { class: "meta" };
const _sfc_main$q = /* @__PURE__ */ defineComponent({
  __name: "IssuesList",
  props: {
    items: {},
    options: {}
  },
  emits: ["select"],
  setup(__props, { emit: __emit }) {
    const emit = __emit;
    function sevColor(sev) {
      const s = String(sev || "").toLowerCase();
      if (s === "critical" || s === "fatal") return "#d32f2f";
      if (s === "error") return "#f44336";
      if (s === "warning" || s === "warn") return "#ff9800";
      return "#9e9e9e";
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("ul", _hoisted_1$p, [
        (openBlock(true), createElementBlock(
          Fragment,
          null,
          renderList(__props.items, (issue) => {
            return openBlock(), createElementBlock("li", {
              key: issue.id,
              "data-testid": `issue-${issue.id}`,
              onClick: ($event) => emit("select", issue)
            }, [
              createElementVNode(
                "span",
                {
                  class: "sev",
                  style: normalizeStyle({ background: sevColor(issue.severity) })
                },
                toDisplayString(issue.severity || issue.source),
                5
                /* TEXT, STYLE */
              ),
              createElementVNode(
                "span",
                _hoisted_3$g,
                toDisplayString(issue.title),
                1
                /* TEXT */
              ),
              createElementVNode(
                "span",
                _hoisted_4$c,
                toDisplayString(issue.service) + " · " + toDisplayString(new Date(issue.time).toLocaleString()),
                1
                /* TEXT */
              )
            ], 8, _hoisted_2$k);
          }),
          128
          /* KEYED_FRAGMENT */
        ))
      ]);
    };
  }
});
const IssuesList = /* @__PURE__ */ _export_sfc(_sfc_main$q, [["__scopeId", "data-v-8c6eb442"]]);
const _hoisted_1$o = {
  class: "detail",
  "data-testid": "issue-detail"
};
const _hoisted_2$j = { key: 0 };
const _hoisted_3$f = { "data-testid": "issue-trace-id" };
const _hoisted_4$b = ["href"];
const _hoisted_5$b = {
  key: 1,
  "data-testid": "issue-attributes"
};
const _hoisted_6$9 = {
  key: 2,
  "data-testid": "issue-detail-loading"
};
const _hoisted_7$7 = {
  key: 3,
  class: "err",
  role: "alert"
};
const _hoisted_8$4 = {
  key: 4,
  "data-testid": "issue-spans",
  class: "block"
};
const _hoisted_9$3 = { class: "span-tree" };
const _hoisted_10$2 = ["data-span-id"];
const _hoisted_11$2 = { class: "muted" };
const _hoisted_12$2 = {
  key: 0,
  class: "sub",
  "data-testid": "issue-span-events"
};
const _hoisted_13$2 = {
  key: 1,
  class: "sub",
  "data-testid": "issue-span-attrs"
};
const _hoisted_14$2 = {
  key: 5,
  "data-testid": "issue-related-logs",
  class: "block"
};
const _hoisted_15$2 = { class: "muted" };
const _sfc_main$p = /* @__PURE__ */ defineComponent({
  __name: "IssueDetails",
  props: {
    issue: {},
    options: {},
    range: {}
  },
  setup(__props) {
    const props = __props;
    const spans = ref([]);
    const logs = ref([]);
    const loading = ref(false);
    const error = ref("");
    let controller = null;
    let seq = 0;
    const dataLink = computed(() => {
      if (!props.issue.traceId) return "";
      const tid = encodeURIComponent(props.issue.traceId);
      return `/d/signoz-traces/signoz-traces?var-traceId=${tid}`;
    });
    function fieldCol(frame, name) {
      const f = (frame?.fields || []).find(
        (x) => String(x.name).toLowerCase() === name.toLowerCase()
      );
      return f?.values || [];
    }
    function framesToSpanRows(frames) {
      const out = [];
      for (const fr of frames || []) {
        const n = fr.fields?.[0]?.values?.length || 0;
        const spanId = fieldCol(fr, "spanId");
        const parent = fieldCol(fr, "parentSpanId");
        const name = fieldCol(fr, "name");
        const service = fieldCol(fr, "serviceName").length ? fieldCol(fr, "serviceName") : fieldCol(fr, "service");
        const duration = fieldCol(fr, "duration");
        const attributes = fieldCol(fr, "attributes");
        const events = fieldCol(fr, "events");
        for (let i = 0; i < n; i++) {
          out.push({
            spanId: String(spanId[i] ?? ""),
            parentSpanId: String(parent[i] ?? ""),
            name: String(name[i] ?? ""),
            service: String(service[i] ?? ""),
            duration: Number(duration[i] ?? 0),
            attributes: attributes[i] != null ? String(attributes[i]) : void 0,
            events: events[i] != null ? String(events[i]) : void 0
          });
        }
      }
      return out;
    }
    function framesToLogRows(frames) {
      const out = [];
      for (const fr of frames || []) {
        const n = fr.fields?.[0]?.values?.length || 0;
        const time = fieldCol(fr, "Time").length ? fieldCol(fr, "Time") : fieldCol(fr, "time");
        const line = fieldCol(fr, "Line").length ? fieldCol(fr, "Line") : fieldCol(fr, "line");
        const service = fieldCol(fr, "service");
        const severity = fieldCol(fr, "severity");
        const spanId = fieldCol(fr, "spanId");
        for (let i = 0; i < n; i++) {
          out.push({
            time: Number(time[i] ?? 0),
            line: String(line[i] ?? ""),
            service: String(service[i] ?? ""),
            severity: String(severity[i] ?? ""),
            spanId: String(spanId[i] ?? "")
          });
        }
      }
      return out;
    }
    async function loadDetail() {
      if (!props.options.showTraceDetail) return;
      if (!props.issue.traceId || !props.issue.datasourceUid) {
        spans.value = [];
        logs.value = [];
        return;
      }
      controller?.abort();
      controller = new AbortController();
      const my = ++seq;
      loading.value = true;
      error.value = "";
      try {
        const api = getRuntimeDataSource(String(props.issue.datasourceUid));
        if (!api?.getMetadata) {
          loading.value = false;
          return;
        }
        const fromMs = props.range?.fromMs ?? Date.now() - 36e5;
        const toMs2 = props.range?.toMs ?? Date.now();
        let spanFrames = [];
        if (typeof api.getTraceWaterfall === "function") {
          const wf = await api.getTraceWaterfall(
            { traceId: props.issue.traceId, selectedSpanId: "" },
            controller.signal
          );
          spanFrames = wf?.frames || (Array.isArray(wf) ? wf : []);
        } else {
          const traceRes = await api.getMetadata(
            { type: "traceById", traceId: props.issue.traceId },
            controller.signal
          );
          spanFrames = traceRes?.frames || [];
        }
        const logRes = await api.getMetadata(
          { type: "relatedLogs", traceId: props.issue.traceId, fromMs, toMs: toMs2 },
          controller.signal
        );
        if (my !== seq) return;
        spans.value = framesToSpanRows(spanFrames);
        logs.value = framesToLogRows(logRes?.frames || []);
      } catch (e) {
        if (e?.name === "AbortError") return;
        if (my === seq) error.value = e instanceof Error ? e.message : String(e);
      } finally {
        if (my === seq) loading.value = false;
      }
    }
    watch(
      () => [
        props.issue.id,
        props.issue.traceId,
        props.range?.fromMs,
        props.range?.toMs
      ],
      () => void loadDetail(),
      { immediate: true }
    );
    onBeforeUnmount(() => {
      controller?.abort();
      seq += 1;
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("aside", _hoisted_1$o, [
        createElementVNode(
          "h4",
          null,
          toDisplayString(__props.issue.title),
          1
          /* TEXT */
        ),
        createElementVNode(
          "p",
          null,
          "服务: " + toDisplayString(__props.issue.service),
          1
          /* TEXT */
        ),
        createElementVNode(
          "p",
          null,
          " 来源: " + toDisplayString(__props.issue.source) + " · 严重性: " + toDisplayString(__props.issue.severity) + " · 状态: " + toDisplayString(__props.issue.status),
          1
          /* TEXT */
        ),
        __props.issue.traceId ? (openBlock(), createElementBlock("p", _hoisted_2$j, [
          _cache[1] || (_cache[1] = createTextVNode(
            " Trace: ",
            -1
            /* CACHED */
          )),
          createElementVNode(
            "span",
            _hoisted_3$f,
            toDisplayString(__props.issue.traceId),
            1
            /* TEXT */
          ),
          __props.options.showTraceLink && dataLink.value ? (openBlock(), createElementBlock("a", {
            key: 0,
            href: dataLink.value,
            "data-testid": "issue-trace-link",
            onClick: _cache[0] || (_cache[0] = withModifiers(() => {
            }, ["stop"]))
          }, " 打开 ", 8, _hoisted_4$b)) : createCommentVNode("v-if", true)
        ])) : createCommentVNode("v-if", true),
        __props.options.showAttributes && __props.issue.attributes ? (openBlock(), createElementBlock("div", _hoisted_5$b, [
          createElementVNode("table", null, [
            (openBlock(true), createElementBlock(
              Fragment,
              null,
              renderList(__props.issue.attributes, (v, k) => {
                return openBlock(), createElementBlock("tr", { key: k }, [
                  createElementVNode(
                    "td",
                    null,
                    toDisplayString(k),
                    1
                    /* TEXT */
                  ),
                  createElementVNode(
                    "td",
                    null,
                    toDisplayString(v),
                    1
                    /* TEXT */
                  )
                ]);
              }),
              128
              /* KEYED_FRAGMENT */
            ))
          ])
        ])) : createCommentVNode("v-if", true),
        loading.value ? (openBlock(), createElementBlock("div", _hoisted_6$9, "加载详情…")) : createCommentVNode("v-if", true),
        error.value ? (openBlock(), createElementBlock(
          "div",
          _hoisted_7$7,
          toDisplayString(error.value),
          1
          /* TEXT */
        )) : createCommentVNode("v-if", true),
        spans.value.length ? (openBlock(), createElementBlock("div", _hoisted_8$4, [
          createElementVNode(
            "h5",
            null,
            "Spans (" + toDisplayString(spans.value.length) + ")",
            1
            /* TEXT */
          ),
          createElementVNode("ul", _hoisted_9$3, [
            (openBlock(true), createElementBlock(
              Fragment,
              null,
              renderList(spans.value, (s) => {
                return openBlock(), createElementBlock("li", {
                  key: s.spanId,
                  "data-span-id": s.spanId
                }, [
                  createElementVNode(
                    "strong",
                    null,
                    toDisplayString(s.service),
                    1
                    /* TEXT */
                  ),
                  createTextVNode(
                    " · " + toDisplayString(s.name) + " ",
                    1
                    /* TEXT */
                  ),
                  createElementVNode(
                    "span",
                    _hoisted_11$2,
                    toDisplayString(s.duration.toFixed?.(2) ?? s.duration) + "ms",
                    1
                    /* TEXT */
                  ),
                  s.events ? (openBlock(), createElementBlock(
                    "div",
                    _hoisted_12$2,
                    " events: " + toDisplayString(s.events),
                    1
                    /* TEXT */
                  )) : createCommentVNode("v-if", true),
                  s.attributes ? (openBlock(), createElementBlock(
                    "div",
                    _hoisted_13$2,
                    " attrs: " + toDisplayString(s.attributes),
                    1
                    /* TEXT */
                  )) : createCommentVNode("v-if", true)
                ], 8, _hoisted_10$2);
              }),
              128
              /* KEYED_FRAGMENT */
            ))
          ])
        ])) : createCommentVNode("v-if", true),
        logs.value.length ? (openBlock(), createElementBlock("div", _hoisted_14$2, [
          createElementVNode(
            "h5",
            null,
            "Related logs (" + toDisplayString(logs.value.length) + ")",
            1
            /* TEXT */
          ),
          createElementVNode("ul", null, [
            (openBlock(true), createElementBlock(
              Fragment,
              null,
              renderList(logs.value, (l, i) => {
                return openBlock(), createElementBlock("li", {
                  key: i,
                  "data-testid": "issue-log-row"
                }, [
                  createElementVNode(
                    "span",
                    _hoisted_15$2,
                    toDisplayString(l.severity),
                    1
                    /* TEXT */
                  ),
                  createTextVNode(
                    " " + toDisplayString(l.line),
                    1
                    /* TEXT */
                  )
                ]);
              }),
              128
              /* KEYED_FRAGMENT */
            ))
          ])
        ])) : createCommentVNode("v-if", true)
      ]);
    };
  }
});
const IssueDetails = /* @__PURE__ */ _export_sfc(_sfc_main$p, [["__scopeId", "data-v-42ce578f"]]);
const _hoisted_1$n = {
  class: "signoz-issues",
  "data-testid": "signoz-issues-panel"
};
const _hoisted_2$i = { class: "toolbar" };
const _hoisted_3$e = {
  key: 0,
  "data-testid": "issue-action-msg"
};
const _hoisted_4$a = {
  key: 1,
  class: "err",
  "data-testid": "issue-action-error",
  role: "alert"
};
const _hoisted_5$a = {
  key: 0,
  "data-testid": "issues-empty"
};
const _hoisted_6$8 = {
  key: 3,
  class: "pager"
};
const _hoisted_7$6 = ["disabled"];
const _hoisted_8$3 = ["disabled"];
const _hoisted_9$2 = {
  key: 5,
  class: "confirm",
  "data-testid": "issue-action-confirm",
  role: "dialog"
};
const _sfc_main$o = /* @__PURE__ */ defineComponent({
  __name: "IssuesPanel",
  props: {
    id: {},
    data: {},
    options: {},
    fieldConfig: {},
    width: {},
    height: {},
    timeRange: {},
    replaceVariables: { type: Function },
    title: {},
    transparent: { type: Boolean }
  },
  setup(__props) {
    const props = __props;
    const options = computed(() => ({
      ...DEFAULT_ISSUES_OPTIONS,
      ...props.options || {},
      sources: {
        ...DEFAULT_ISSUES_OPTIONS.sources,
        ...props.options?.sources || {}
      }
    }));
    const alertFrames = ref([]);
    const actionMsg = ref("");
    const actionError = ref("");
    const selected = ref(null);
    const page = ref(0);
    const confirmIssue = ref(null);
    const confirmAction = ref(null);
    let alertsController = null;
    let alertsSeq = 0;
    const baseModel = computed(
      () => issuesFromPanelData(props.data, options.value)
    );
    const mergedFrames = computed(() => [
      ...props.data?.series || [],
      ...alertFrames.value
    ]);
    const model = computed(() => {
      if (!alertFrames.value.length) return baseModel.value;
      return framesToIssues(mergedFrames.value, options.value);
    });
    const issues = computed(() => model.value.issues);
    const notices = computed(() => [
      ...model.value.notices,
      ...model.value.optionErrors
    ]);
    const pageSize = computed(() => options.value.pageSize || 50);
    const pageItems = computed(() => {
      const start = page.value * pageSize.value;
      return issues.value.slice(start, start + pageSize.value);
    });
    const range = computed(() => {
      const r = props.data?.timeRange || props.timeRange;
      return {
        fromMs: r?.from?.valueOf?.() ?? Date.now() - 36e5,
        toMs: r?.to?.valueOf?.() ?? Date.now()
      };
    });
    function collectSigNozUids() {
      const uids = /* @__PURE__ */ new Set();
      for (const fr of props.data?.series || []) {
        const u = fr.meta?.datasourceUid;
        if (u) uids.add(String(u));
      }
      const dsRef = props.data?.request?.targets?.[0]?.datasource || props.datasource;
      const uid = typeof dsRef === "string" ? dsRef : dsRef?.uid;
      if (uid) uids.add(String(uid));
      if (!uids.size) {
        for (const ds2 of listRuntimeDataSources()) {
          if (ds2?.type === "signoz" || String(ds2?.uid || "").includes("signoz"))
            uids.add(String(ds2.uid));
        }
      }
      return Array.from(uids);
    }
    async function loadAlertsMetadata() {
      if (!options.value.sources?.alerts) {
        alertFrames.value = [];
        return;
      }
      alertsController?.abort();
      alertsController = new AbortController();
      const my = ++alertsSeq;
      const frames = [];
      for (const uid of collectSigNozUids()) {
        const api = getRuntimeDataSource(uid);
        if (!api?.getMetadata) continue;
        try {
          const res = await api.getMetadata(
            {
              type: "alerts",
              fromMs: range.value.fromMs,
              toMs: range.value.toMs,
              service: options.value.service,
              environment: options.value.environment,
              severities: options.value.severities
            },
            alertsController.signal
          );
          if (my !== alertsSeq) return;
          for (const fr of res?.frames || []) {
            frames.push({
              ...fr,
              meta: { ...fr.meta || {}, datasourceUid: uid, signal: "alerts" }
            });
          }
        } catch (e) {
          if (e?.name === "AbortError") return;
        }
      }
      if (my === alertsSeq) alertFrames.value = frames;
    }
    watch(
      () => [
        options.value.sources?.alerts,
        options.value.service,
        options.value.environment,
        range.value.fromMs,
        range.value.toMs,
        props.data?.series?.length
      ],
      () => void loadAlertsMetadata(),
      { immediate: true }
    );
    onBeforeUnmount(() => {
      alertsController?.abort();
      alertsSeq += 1;
    });
    function requestAction(issue, action) {
      confirmIssue.value = issue;
      confirmAction.value = action;
    }
    async function confirmRun() {
      if (!confirmIssue.value || !confirmAction.value) return;
      actionMsg.value = "";
      actionError.value = "";
      const res = await runIssueAction(confirmIssue.value, confirmAction.value);
      if (res.status === "success") {
        actionMsg.value = res.message || "ok";
        await loadAlertsMetadata();
      } else {
        actionError.value = res.message || "动作失败";
      }
      confirmIssue.value = null;
      confirmAction.value = null;
    }
    function cancelConfirm() {
      confirmIssue.value = null;
      confirmAction.value = null;
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$n, [
        createElementVNode("div", _hoisted_2$i, [
          createElementVNode(
            "span",
            null,
            "Issues " + toDisplayString(issues.value.length),
            1
            /* TEXT */
          ),
          actionMsg.value ? (openBlock(), createElementBlock(
            "span",
            _hoisted_3$e,
            toDisplayString(actionMsg.value),
            1
            /* TEXT */
          )) : createCommentVNode("v-if", true),
          actionError.value ? (openBlock(), createElementBlock(
            "span",
            _hoisted_4$a,
            toDisplayString(actionError.value),
            1
            /* TEXT */
          )) : createCommentVNode("v-if", true)
        ]),
        (openBlock(true), createElementBlock(
          Fragment,
          null,
          renderList(notices.value, (n) => {
            return openBlock(), createElementBlock(
              "div",
              {
                key: n,
                class: "notice",
                role: "status"
              },
              toDisplayString(n),
              1
              /* TEXT */
            );
          }),
          128
          /* KEYED_FRAGMENT */
        )),
        !issues.value.length ? (openBlock(), createElementBlock("div", _hoisted_5$a, " 当前筛选条件下没有 Issues ")) : options.value.layout === "table" ? (openBlock(), createBlock(IssuesTable, {
          key: 1,
          items: pageItems.value,
          options: options.value,
          onSelect: _cache[0] || (_cache[0] = ($event) => selected.value = $event),
          onAcknowledge: _cache[1] || (_cache[1] = ($event) => requestAction($event, "signoz.acknowledge")),
          onResolve: _cache[2] || (_cache[2] = ($event) => requestAction($event, "signoz.resolve"))
        }, null, 8, ["items", "options"])) : (openBlock(), createBlock(IssuesList, {
          key: 2,
          items: pageItems.value,
          options: options.value,
          onSelect: _cache[3] || (_cache[3] = ($event) => selected.value = $event)
        }, null, 8, ["items", "options"])),
        issues.value.length > pageSize.value ? (openBlock(), createElementBlock("div", _hoisted_6$8, [
          createElementVNode("button", {
            type: "button",
            disabled: page.value === 0,
            "data-testid": "issues-prev",
            onClick: _cache[4] || (_cache[4] = ($event) => page.value--)
          }, " 上一页 ", 8, _hoisted_7$6),
          createElementVNode(
            "span",
            null,
            toDisplayString(page.value + 1) + " / " + toDisplayString(Math.max(1, Math.ceil(issues.value.length / pageSize.value))),
            1
            /* TEXT */
          ),
          createElementVNode("button", {
            type: "button",
            disabled: (page.value + 1) * pageSize.value >= issues.value.length,
            "data-testid": "issues-next",
            onClick: _cache[5] || (_cache[5] = ($event) => page.value++)
          }, " 下一页 ", 8, _hoisted_8$3)
        ])) : createCommentVNode("v-if", true),
        selected.value && options.value.showTraceDetail ? (openBlock(), createBlock(IssueDetails, {
          key: 4,
          issue: selected.value,
          options: options.value,
          range: range.value
        }, null, 8, ["issue", "options", "range"])) : createCommentVNode("v-if", true),
        confirmIssue.value && confirmAction.value ? (openBlock(), createElementBlock("div", _hoisted_9$2, [
          createElementVNode(
            "p",
            null,
            " 确认对 alert " + toDisplayString(confirmIssue.value.alertId || confirmIssue.value.id) + " 执行 " + toDisplayString(confirmAction.value) + "？ ",
            1
            /* TEXT */
          ),
          createElementVNode("button", {
            type: "button",
            "data-testid": "issue-confirm-ok",
            onClick: confirmRun
          }, " 确认 "),
          createElementVNode("button", {
            type: "button",
            "data-testid": "issue-confirm-cancel",
            onClick: cancelConfirm
          }, " 取消 ")
        ])) : createCommentVNode("v-if", true)
      ]);
    };
  }
});
const IssuesPanel = /* @__PURE__ */ _export_sfc(_sfc_main$o, [["__scopeId", "data-v-921da130"]]);
const plugin$1 = new VuePanelPlugin(
  { id: "signoz-issues", name: "SigNoz 可观测性问题", state: "stable" },
  IssuesPanel
).setPanelOptions((builder) => {
  builder.addNumber(
    {
      id: "pageSize",
      path: "pageSize",
      name: "每页条数",
      editor: "number"
    },
    50
  ).addBoolean(
    {
      id: "showTraceDetail",
      path: "showTraceDetail",
      name: "显示 Trace 详情",
      editor: "boolean"
    },
    true
  ).addBoolean(
    {
      id: "showAttributes",
      path: "showAttributes",
      name: "显示属性",
      editor: "boolean"
    },
    true
  ).addBoolean(
    {
      id: "showTraceLink",
      path: "showTraceLink",
      name: "显示 Trace 链接",
      editor: "boolean"
    },
    true
  ).addBoolean(
    {
      id: "showDatasource",
      path: "showDatasource",
      name: "显示数据源",
      editor: "boolean"
    },
    false
  );
}).setRuntimeConsumedPaths([
  "layout",
  "pageSize",
  "showTraceDetail",
  "sources",
  "service",
  "environment",
  "operation",
  "attributeFilters",
  "severities",
  "minDurationMs",
  "maxDurationMs",
  "sort",
  "limit",
  "highlightNew",
  "highlightWindowMs",
  "showAttributes",
  "showTraceLink",
  "showDatasource"
]).register();
const module$2 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
  __proto__: null,
  default: plugin$1
}, Symbol.toStringTag, { value: "Module" }));
function defaultBuilderSpec(name = "A", signal = "traces", opts) {
  const forceMetrics = opts?.forceMetricsHost || signal === "metrics";
  const effective = forceMetrics ? "metrics" : signal;
  const aggregations = effective === "metrics" ? [
    {
      kind: "metric",
      metricName: "",
      timeAggregation: "rate",
      spaceAggregation: "sum"
    }
  ] : [{ kind: "expression", expression: "count()" }];
  return {
    name,
    signal: effective,
    source: void 0,
    stepInterval: 60,
    tags: [],
    disabled: false,
    filter: { expression: "" },
    having: { expression: "" },
    groupBy: [],
    // Aggregation requestTypes (default time_series) reject order-by timestamp.
    // List/raw panels set order via QueryAddons; wire also re-adds defaults when needed.
    order: [],
    limit: 100,
    legend: "",
    functions: [],
    aggregations
  };
}
function defaultAggregationsForSignal(signal) {
  if (signal === "metrics") {
    return [
      {
        kind: "metric",
        metricName: "",
        timeAggregation: "rate",
        spaceAggregation: "sum"
      }
    ];
  }
  return [{ kind: "expression", expression: "count()" }];
}
function defaultPromItem(name = "A", expr = "") {
  return {
    type: "builder_query",
    queryType: "promql",
    spec: defaultBuilderSpec(name, "metrics"),
    rawQuery: expr,
    rawLegend: ""
  };
}
const DEFAULT_SIGNOZ_QUERY = {
  refId: "A",
  schema: 1,
  apiProfile: "signoz-v5",
  requestType: "time_series",
  queries: [
    {
      type: "builder_query",
      queryType: "builder",
      spec: defaultBuilderSpec("A", "traces")
    }
  ],
  signal: "traces",
  expr: "",
  legendFormat: "",
  limit: 100,
  formatOptions: { fillGaps: false, formatTableResultForUI: false }
};
const DEFAULT_SIGNOZ_OPTIONS = {
  schema: 1,
  apiProfile: "signoz-v5",
  timeout: 3e4,
  metadataCacheTTL: "5m",
  rawPageSize: 100,
  liveTailIntervalMs: 2e3,
  maxConcurrentRequests: 4,
  credentialKind: "signozApiKey",
  credentialHeaderName: "SIGNOZ-API-KEY",
  fetchCredentials: "omit",
  customHealthOk: false,
  customHealthSignature: "",
  dataMode: "live"
};
const STABLE_FUNCTIONS = [
  "cutOffMin",
  "cutOffMax",
  "clampMin",
  "clampMax",
  "absolute",
  "runningDiff",
  "log2",
  "log10",
  "cumulativeSum",
  "ewma3",
  "ewma5",
  "ewma7",
  "median3",
  "median5",
  "median7",
  "timeShift",
  "fillZero"
];
const FUNCTION_ARG_NAMES = {
  cutOffMin: ["threshold"],
  cutOffMax: ["threshold"],
  clampMin: ["threshold"],
  clampMax: ["threshold"],
  timeShift: ["shift"],
  absolute: [],
  runningDiff: [],
  log2: [],
  log10: [],
  cumulativeSum: [],
  ewma3: [],
  ewma5: [],
  ewma7: [],
  median3: [],
  median5: [],
  median7: [],
  fillZero: [],
  anomaly: []
};
const SIGNOZ_FUNCTION_CATALOG = STABLE_FUNCTIONS.map((name) => ({ name, category: "transform" }));
function normalizeFunctionArgs(name, args) {
  const names = FUNCTION_ARG_NAMES[name] || [];
  const list = Array.isArray(args) ? args : [];
  return list.map((a, i) => {
    if (a != null && typeof a === "object" && "value" in a) {
      const val = String(a.value ?? "");
      const n = a.name != null && String(a.name) !== "" ? String(a.name) : names[i] || (names.length === 1 ? names[0] : `arg${i}`);
      return { name: n, value: val };
    }
    return {
      name: names[i] || (names.length === 1 ? names[0] : `arg${i}`),
      value: String(a ?? "")
    };
  });
}
function resolveEditorCapabilities(args) {
  const id = String(args.profile.id);
  const exp = args.options?.experimentalCapabilities || {};
  const product = id === "signoz-v5" || id === "signoz-v4" || id === "signoz-v3";
  return {
    builder: product || id === "custom",
    formula: product || id === "custom",
    promql: true,
    clickhouseSql: product || id === "custom",
    traceOperator: product,
    subQuery: Boolean(exp.builderSubQuery),
    join: Boolean(exp.builderJoin),
    anomaly: Boolean(exp.anomaly),
    distribution: Boolean(exp.distribution),
    alerts: Boolean(args.profile.endpoints.alertsQuery?.path) || product
  };
}
function allowedRequestTypes(caps2) {
  const list = [
    "time_series",
    "scalar",
    "raw",
    "raw_stream",
    "trace"
  ];
  if (caps2.distribution) list.push("distribution");
  return list;
}
function validateSavedItem(item, caps2) {
  if (item.type === "builder_sub_query" && !caps2.subQuery) {
    return {
      ok: false,
      message: "builder_sub_query 当前不可用（缺少 capability VERIFIED）"
    };
  }
  if (item.type === "builder_join" && !caps2.join) {
    return {
      ok: false,
      message: "builder_join 当前不可用（缺少 capability VERIFIED）"
    };
  }
  if (item.type === "builder_trace_operator" && !caps2.traceOperator) {
    return { ok: false, message: "builder_trace_operator 当前 profile 不支持" };
  }
  if (item.type === "builder_query" && item.spec.functions?.length) {
    for (const fn of item.spec.functions) {
      if (fn.name === "anomaly" && !caps2.anomaly) {
        return {
          ok: false,
          message: "anomaly 函数当前不可用（缺少 capability VERIFIED）"
        };
      }
      if (fn.name !== "anomaly" && !STABLE_FUNCTIONS.includes(fn.name)) {
        return { ok: false, message: `函数 ${fn.name} 当前 profile 不支持` };
      }
    }
  }
  return { ok: true };
}
function functionsForEditor(caps2) {
  const list = STABLE_FUNCTIONS.map(
    (name) => ({ name, label: name })
  );
  if (caps2.anomaly) list.push({ name: "anomaly", label: "anomaly (licensed)" });
  return list;
}
const ALL_MODES = ["builder", "promql", "clickhouse_sql"];
const BUILDER_ONLY = ["builder"];
const PROMQL_ONLY = ["promql"];
const EMPTY_MODES = {
  metrics: [],
  logs: [],
  traces: []
};
function defaultIsHealthy(status, data) {
  if (status < 200 || status >= 300) return false;
  if (data == null || typeof data !== "object") return true;
  const o = data;
  if ("success" in o && o.success === false) return false;
  if ("ok" in o && o.ok === false) return false;
  if ("status" in o) {
    const s = String(o.status).toLowerCase();
    if (s === "error" || s === "failed") return false;
  }
  if ("error" in o && o.error != null && String(o.error).trim() !== "")
    return false;
  return true;
}
const SIGNOZ_PROFILES = {
  "prometheus-compatible": {
    id: "prometheus-compatible",
    signals: ["metrics"],
    formulaServerSide: false,
    supportsServerFormula: false,
    queryModesBySignal: { metrics: PROMQL_ONLY, logs: [], traces: [] },
    isHealthy: defaultIsHealthy,
    endpoints: {
      metricsQuery: { path: "/api/v1/query_range", method: "GET" },
      health: { path: "/api/v1/status/buildinfo", method: "GET" }
    }
  },
  "signoz-v3": {
    id: "signoz-v3",
    signals: ["metrics", "logs", "traces"],
    formulaServerSide: true,
    supportsServerFormula: true,
    queryModesBySignal: {
      metrics: ALL_MODES,
      logs: BUILDER_ONLY,
      traces: BUILDER_ONLY
    },
    isHealthy: defaultIsHealthy,
    endpoints: {
      metricsQuery: { path: "/api/v3/query_range", method: "POST" },
      logsQuery: { path: "/api/v3/query_range", method: "POST" },
      tracesQuery: { path: "/api/v3/query_range", method: "POST" },
      traceById: { path: "/api/v1/traces/{id}", method: "GET" },
      metadata: { path: "/api/v1/services", method: "POST" },
      services: { path: "/api/v1/services", method: "POST" },
      health: { path: "/api/v1/health", method: "GET" },
      liveTail: { path: "/api/v3/logs/livetail", method: "GET" },
      liveTailLegacy: { path: "/api/v1/logs/tail", method: "GET" },
      exportRaw: { path: "/api/v1/export_raw_data", method: "POST" }
    }
  },
  "signoz-v5": {
    id: "signoz-v5",
    signals: ["metrics", "logs", "traces"],
    formulaServerSide: true,
    supportsServerFormula: true,
    credentialModes: ["signozApiKey", "bearer", "session", "proxy", "headers"],
    defaultCredentialHeader: "SIGNOZ-API-KEY",
    queryModesBySignal: {
      metrics: ALL_MODES,
      logs: ALL_MODES,
      traces: BUILDER_ONLY
    },
    isHealthy: defaultIsHealthy,
    endpoints: {
      metricsQuery: { path: "/api/v5/query_range", method: "POST" },
      logsQuery: { path: "/api/v5/query_range", method: "POST" },
      tracesQuery: { path: "/api/v5/query_range", method: "POST" },
      // default health order: v2 then v1 (verified deployments)
      health: { path: "/api/v2/healthz", method: "GET" },
      healthCandidates: [
        { path: "/api/v2/healthz", method: "GET" },
        { path: "/api/v1/health", method: "GET" }
      ],
      version: { path: "/api/v1/version", method: "GET" },
      metricsList: { path: "/api/v2/metrics", method: "GET" },
      metadata: { path: "/api/v2/metrics", method: "GET" },
      fieldsKeys: { path: "/api/v1/fields/keys", method: "GET" },
      fieldsValues: { path: "/api/v1/fields/values", method: "GET" },
      attributeKeys: { path: "/api/v1/fields/keys", method: "GET" },
      attributeValues: { path: "/api/v1/fields/values", method: "GET" },
      services: { path: "/api/v2/services", method: "POST" },
      alertsQuery: { path: "/api/v1/rules", method: "GET" },
      variablesQuery: { path: "/api/v2/variables/query", method: "POST" },
      traceById: { path: "/api/v4/traces/{id}", method: "GET" },
      // liveTail SSE candidate — capability gated until Content-Type verified live
      liveTail: { path: "/api/v3/logs/livetail", method: "GET" },
      liveTailLegacy: { path: "/api/v1/logs/tail", method: "GET" },
      exportRaw: { path: "/api/v1/export_raw_data", method: "POST" }
    }
  },
  "signoz-v4": {
    id: "signoz-v4",
    signals: ["metrics", "logs", "traces"],
    formulaServerSide: true,
    supportsServerFormula: true,
    queryModesBySignal: {
      metrics: ALL_MODES,
      logs: BUILDER_ONLY,
      traces: BUILDER_ONLY
    },
    isHealthy: defaultIsHealthy,
    endpoints: {
      metricsQuery: { path: "/api/v4/query_range", method: "POST" },
      logsQuery: { path: "/api/v4/query_range", method: "POST" },
      tracesQuery: { path: "/api/v4/query_range", method: "POST" },
      health: { path: "/api/v1/health", method: "GET" }
    }
  },
  custom: {
    id: "custom",
    signals: [],
    formulaServerSide: false,
    supportsServerFormula: false,
    queryModesBySignal: { ...EMPTY_MODES },
    isHealthy: defaultIsHealthy,
    endpoints: {}
  }
};
function resolveSigNozProfile(options) {
  let id = String(options?.apiProfile || "signoz-v5");
  if (id === "argus-v5") id = "signoz-v5";
  const base = SIGNOZ_PROFILES[id] || SIGNOZ_PROFILES["signoz-v3"];
  if (id !== "custom") {
    return {
      ...base,
      endpoints: { ...base.endpoints },
      queryModesBySignal: { ...base.queryModesBySignal },
      isHealthy: base.isHealthy || defaultIsHealthy
    };
  }
  const endpoints = {};
  if (options?.customMetricsPath)
    endpoints.metricsQuery = {
      path: options.customMetricsPath,
      method: "POST"
    };
  if (options?.customLogsPath)
    endpoints.logsQuery = { path: options.customLogsPath, method: "POST" };
  if (options?.customTracesPath)
    endpoints.tracesQuery = { path: options.customTracesPath, method: "POST" };
  if (options?.customAlertsPath)
    endpoints.alertsQuery = { path: options.customAlertsPath, method: "POST" };
  if (options?.customTraceByIdPath)
    endpoints.traceById = { path: options.customTraceByIdPath, method: "GET" };
  if (options?.customMetadataPath)
    endpoints.metadata = { path: options.customMetadataPath, method: "GET" };
  if (options?.customHealthPath)
    endpoints.health = { path: options.customHealthPath, method: "GET" };
  if (options?.customAcknowledgePath)
    endpoints.acknowledge = {
      path: options.customAcknowledgePath,
      method: "POST"
    };
  if (options?.customResolvePath)
    endpoints.resolve = { path: options.customResolvePath, method: "POST" };
  const signals = [];
  const queryModesBySignal = {
    metrics: [],
    logs: [],
    traces: []
  };
  if (endpoints.metricsQuery) {
    signals.push("metrics");
    queryModesBySignal.metrics = ALL_MODES;
  }
  if (endpoints.logsQuery) {
    signals.push("logs");
    queryModesBySignal.logs = BUILDER_ONLY;
  }
  if (endpoints.tracesQuery) {
    signals.push("traces");
    queryModesBySignal.traces = BUILDER_ONLY;
  }
  return {
    id: "custom",
    signals,
    formulaServerSide: false,
    supportsServerFormula: false,
    queryModesBySignal,
    isHealthy: defaultIsHealthy,
    endpoints
  };
}
function buildCustomHealthSignature(url, options) {
  const payload = {
    url: String(url || "").replace(/\/+$/, ""),
    apiProfile: options.apiProfile || "custom",
    credentialKind: options.credentialKind || "",
    credentialHeaderName: options.credentialHeaderName || "",
    fetchCredentials: options.fetchCredentials || "",
    customHealthPath: options.customHealthPath || "",
    customMetricsPath: options.customMetricsPath || "",
    customLogsPath: options.customLogsPath || "",
    customTracesPath: options.customTracesPath || "",
    customAlertsPath: options.customAlertsPath || "",
    customTraceByIdPath: options.customTraceByIdPath || "",
    customMetadataPath: options.customMetadataPath || "",
    customMetricsListPath: options.customMetricsListPath || "",
    customFieldsKeysPath: options.customFieldsKeysPath || "",
    customFieldsValuesPath: options.customFieldsValuesPath || "",
    customAcknowledgePath: options.customAcknowledgePath || "",
    customResolvePath: options.customResolvePath || ""
  };
  return JSON.stringify(payload);
}
function isSuccessfulActionResponse(status, data) {
  return defaultIsHealthy(status, data);
}
function modesForSignal(profile, signal) {
  return profile.queryModesBySignal?.[signal] || [];
}
function isModeAllowed(profile, signal, mode2) {
  return modesForSignal(profile, signal).includes(mode2);
}
function deepClone$1(v) {
  try {
    return structuredClone(v);
  } catch {
    return JSON.parse(JSON.stringify(v));
  }
}
function migrateLimitBy(raw, fallbackLimit) {
  if (raw == null) return void 0;
  if (Array.isArray(raw)) {
    const keys = raw.map((x) => typeof x === "string" ? x : x?.key).filter((k) => Boolean(k));
    if (!keys.length) return void 0;
    const firstVal = raw[0] && typeof raw[0] === "object" ? raw[0].value : void 0;
    const value = firstVal != null && firstVal !== "" ? Number(firstVal) : fallbackLimit != null ? Number(fallbackLimit) : 10;
    return { keys, value: Number.isFinite(value) ? value : 10 };
  }
  if (typeof raw === "object" && Array.isArray(raw.keys)) {
    const keys = raw.keys.map(String).filter(Boolean);
    if (!keys.length) return void 0;
    const value = raw.value != null ? Number(raw.value) : fallbackLimit != null ? Number(fallbackLimit) : void 0;
    return {
      keys,
      value: value != null && Number.isFinite(value) ? value : void 0
    };
  }
  return void 0;
}
function migrateJoinOn(raw) {
  if (raw == null) return "";
  if (typeof raw === "string") return raw;
  if (Array.isArray(raw)) {
    return raw.map((p) => {
      const l = p?.left ?? p?.l ?? "";
      const r = p?.right ?? p?.r ?? l;
      if (!l && !r) return "";
      return `${l} = ${r}`;
    }).filter(Boolean).join(" AND ");
  }
  return String(raw);
}
function migrateBuilderSpec(spec) {
  if (!spec || typeof spec !== "object") return spec;
  const next = { ...spec };
  if (next.functions) {
    next.functions = next.functions.map((f) => ({
      name: f.name,
      args: normalizeFunctionArgs(String(f.name || ""), f.args)
    }));
  }
  if (next.limitBy != null) {
    next.limitBy = migrateLimitBy(next.limitBy, next.limit);
  }
  return next;
}
function migrateQueryItem(item) {
  if (!item || typeof item !== "object") return item;
  if (item.type === "builder_query" && item.spec) {
    return { ...item, spec: migrateBuilderSpec(item.spec) };
  }
  if (item.type === "builder_join" && item.spec) {
    return {
      ...item,
      spec: {
        ...item.spec,
        on: migrateJoinOn(item.spec.on)
      }
    };
  }
  return item;
}
function migrateSigNozQuery(input) {
  const src = deepClone$1(input);
  if (Array.isArray(src.queries) && src.queries.length) {
    const queries2 = src.queries.map(migrateQueryItem);
    return {
      ...DEFAULT_SIGNOZ_QUERY,
      ...src,
      schema: 1,
      queries: queries2
    };
  }
  const signal = String(src.signal || "metrics");
  const expr = String(src.expr || src.query || "");
  const formula = String(src.formula || "");
  const name = String(src.refId || "A");
  const queries = [];
  if (formula) {
    queries.push({
      type: "builder_formula",
      spec: {
        name: "F1",
        expression: formula,
        disabled: false,
        legend: "",
        order: []
      }
    });
  }
  if (signal === "metrics" || !signal) {
    queries.unshift(defaultPromItem(name, expr));
  } else {
    const spec = defaultBuilderSpec(
      name,
      signal === "logs" || signal === "traces" ? signal : "metrics"
    );
    spec.service = src.service != null ? String(src.service) : void 0;
    spec.operation = src.operation != null ? String(src.operation) : void 0;
    spec.limit = src.limit != null ? Number(src.limit) : void 0;
    spec.legend = String(src.legendFormat || "");
    queries.unshift({
      type: "builder_query",
      queryType: "builder",
      spec,
      rawQuery: expr,
      rawLegend: String(src.legendFormat || "")
    });
  }
  return {
    refId: String(src.refId || "A"),
    hide: Boolean(src.hide),
    datasource: src.datasource,
    schema: 1,
    apiProfile: src.apiProfile || DEFAULT_SIGNOZ_QUERY.apiProfile,
    queries: queries.map(migrateQueryItem),
    signal,
    expr,
    service: src.service != null ? String(src.service) : void 0,
    operation: src.operation != null ? String(src.operation) : void 0,
    formula: formula || void 0,
    legendFormat: src.legendFormat != null ? String(src.legendFormat) : "",
    limit: src.limit != null ? Number(src.limit) : 100
  };
}
function migrateSigNozConfig(input) {
  const src = deepClone$1(input);
  let profile = String(src.apiProfile || DEFAULT_SIGNOZ_OPTIONS.apiProfile);
  if (!SIGNOZ_PROFILES[profile]) profile = "signoz-v5";
  let timeout = Number(src.timeout ?? DEFAULT_SIGNOZ_OPTIONS.timeout);
  if (!Number.isFinite(timeout) || timeout <= 0)
    timeout = DEFAULT_SIGNOZ_OPTIONS.timeout;
  if (typeof src.timeout === "string")
    timeout = Number(src.timeout) || DEFAULT_SIGNOZ_OPTIONS.timeout;
  const cacheTTL = String(
    src.metadataCacheTTL || src.cacheTTL || DEFAULT_SIGNOZ_OPTIONS.metadataCacheTTL
  );
  const options = {
    ...DEFAULT_SIGNOZ_OPTIONS,
    ...src,
    schema: 1,
    apiProfile: profile,
    timeout,
    metadataCacheTTL: cacheTTL,
    credentialKind: src.credentialKind || "bearer",
    customHealthOk: Boolean(src.customHealthOk),
    customHealthSignature: String(src.customHealthSignature || "")
  };
  if (options.apiProfile === "custom") {
    const url = String(src.url || "");
    const sig = buildCustomHealthSignature(url, options);
    if (options.customHealthOk && options.customHealthSignature !== sig) {
      options.customHealthOk = false;
    }
    const resolved = resolveSigNozProfile(options);
    if (!resolved.signals.length) {
      options.customHealthOk = false;
    }
  }
  return options;
}
function nextQueryName(items) {
  const used = new Set(items.map((item) => item.spec.name));
  for (const name of "ABCDEFGHIJKLMNOPQRSTUVWXYZ") {
    if (!used.has(name)) return name;
  }
  let index2 = 1;
  while (used.has(`Q${index2}`)) index2 += 1;
  return `Q${index2}`;
}
function nextFormulaName(items) {
  const used = new Set(items.map((item) => item.spec.name));
  let index2 = 1;
  while (used.has(`F${index2}`)) index2 += 1;
  return `F${index2}`;
}
function deepClone(v) {
  return JSON.parse(JSON.stringify(v));
}
function cloneBuilderSpec(spec) {
  return deepClone(spec);
}
function emptyState(mode2 = "builder") {
  return {
    activeQueryType: mode2,
    builder: {
      queries: [defaultBuilderSpec("A", "traces")],
      formulas: [],
      traceOperators: []
    },
    promql: [],
    clickhouseSql: []
  };
}
function toEditorState(query) {
  const q = query || {};
  if (q.editor && typeof q.editor === "object") {
    return deepClone(q.editor);
  }
  const items = Array.isArray(q.queries) ? q.queries : [];
  if (!items.length) return emptyState();
  const modes = /* @__PURE__ */ new Set();
  const state2 = emptyState();
  state2.builder.queries = [];
  for (const item of items) {
    if (item.type === "builder_formula") {
      const f = item.spec;
      state2.builder.formulas.push(
        deepClone({
          name: f?.name || "F1",
          expression: f?.expression || "",
          disabled: Boolean(f?.disabled),
          legend: f?.legend || "",
          order: Array.isArray(f?.order) ? f.order : [],
          limit: f?.limit
        })
      );
      modes.add("builder");
      continue;
    }
    if (item.type === "builder_trace_operator") {
      state2.builder.traceOperators.push(
        deepClone(item.spec)
      );
      modes.add("builder");
      continue;
    }
    if (item.type !== "builder_query") continue;
    const qt = item.queryType || "builder";
    modes.add(qt);
    if (qt === "promql") {
      state2.promql.push({
        name: item.spec?.name || "A",
        query: String(item.rawQuery || ""),
        legend: item.rawLegend || item.spec?.legend,
        disabled: item.spec?.disabled
      });
    } else if (qt === "clickhouse_sql") {
      state2.clickhouseSql.push({
        name: item.spec?.name || "A",
        query: String(item.rawQuery || ""),
        legend: item.rawLegend || item.spec?.legend,
        disabled: item.spec?.disabled
      });
    } else {
      state2.builder.queries.push(cloneBuilderSpec(item.spec));
    }
  }
  if (!state2.builder.queries.length) {
    state2.builder.queries = [defaultBuilderSpec("A", "traces")];
  }
  const modeList = [...modes].filter(
    (m) => m === "builder" || m === "promql" || m === "clickhouse_sql"
  );
  if (modeList.length > 1) {
    state2.legacyMixed = true;
    state2.legacySchema1 = deepClone(items);
    state2.activeQueryType = modeList[0] || "builder";
  } else {
    state2.activeQueryType = modeList[0] || "builder";
  }
  return state2;
}
function fromEditorState(state2, base = {}) {
  if (state2.legacyMixed && state2.legacySchema1?.length) {
    return {
      refId: base.refId || "A",
      schema: 1,
      ...base,
      queries: deepClone(state2.legacySchema1),
      editor: deepClone(state2)
    };
  }
  const queries = [];
  if (state2.activeQueryType === "builder") {
    for (const spec of state2.builder.queries) {
      queries.push({
        type: "builder_query",
        queryType: "builder",
        spec: cloneBuilderSpec(spec)
      });
    }
    for (const f of state2.builder.formulas) {
      queries.push({ type: "builder_formula", spec: deepClone(f) });
    }
    for (const t of state2.builder.traceOperators) {
      queries.push({ type: "builder_trace_operator", spec: deepClone(t) });
    }
  } else if (state2.activeQueryType === "promql") {
    for (const r of state2.promql.length ? state2.promql : [{ name: "A", query: "" }]) {
      queries.push({
        type: "builder_query",
        queryType: "promql",
        rawQuery: r.query,
        rawLegend: r.legend,
        spec: {
          ...defaultBuilderSpec(r.name, "metrics"),
          disabled: r.disabled,
          legend: r.legend
        }
      });
    }
  } else {
    for (const r of state2.clickhouseSql.length ? state2.clickhouseSql : [{ name: "A", query: "" }]) {
      queries.push({
        type: "builder_query",
        queryType: "clickhouse_sql",
        rawQuery: r.query,
        rawLegend: r.legend,
        spec: {
          ...defaultBuilderSpec(r.name, "logs"),
          disabled: r.disabled,
          legend: r.legend
        }
      });
    }
  }
  return {
    refId: base.refId || "A",
    schema: 2,
    apiProfile: base.apiProfile || "signoz-v5",
    requestType: base.requestType || "time_series",
    ...base,
    queries,
    editor: deepClone(state2)
  };
}
function commitGlobalMode(state2, mode2) {
  const next = deepClone(state2);
  next.activeQueryType = mode2;
  next.legacyMixed = false;
  next.legacySchema1 = void 0;
  return next;
}
const _hoisted_1$m = {
  class: "field-key-select",
  "data-testid": "signoz-field-key-select"
};
const _hoisted_2$h = {
  key: 0,
  class: "err",
  "data-testid": "signoz-field-key-error",
  role: "status"
};
const _sfc_main$n = /* @__PURE__ */ defineComponent({
  __name: "FieldKeySelect",
  props: {
    modelValue: {},
    multiple: { type: Boolean },
    signal: {},
    metricName: {},
    datasourceApi: {},
    placeholder: {},
    testId: {},
    numberOnly: { type: Boolean }
  },
  emits: ["update:modelValue"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const options = ref([]);
    const loading = ref(false);
    const error = ref("");
    let timer = null;
    let abort = null;
    function fieldFromValue(name) {
      const hit = options.value.find((o) => o.value === name)?.field;
      return hit || {
        name,
        fieldDataType: "string",
        fieldContext: "tag"
      };
    }
    function currentNames() {
      const mv = props.modelValue;
      if (mv == null || mv === "") return [];
      if (typeof mv === "string") return mv ? [mv] : [];
      if (Array.isArray(mv))
        return mv.map((f) => typeof f === "string" ? f : f.name).filter(Boolean);
      return [mv.name].filter(Boolean);
    }
    async function search(text) {
      if (!props.datasourceApi?.getMetadata) {
        options.value = currentNames().map((n) => ({ label: n, value: n }));
        return;
      }
      abort?.abort();
      abort = new AbortController();
      loading.value = true;
      error.value = "";
      try {
        const res = await props.datasourceApi.getMetadata(
          {
            type: "attributeKeys",
            signal: props.signal || "metrics",
            metricName: props.metricName,
            search: text || void 0
          },
          abort.signal
        );
        let fields = Array.isArray(res?.values) ? res.values : [];
        if (props.numberOnly) {
          fields = fields.filter(
            (f) => f.fieldDataType === "float64" || f.fieldDataType === "int64"
          );
        }
        options.value = fields.map((f) => ({
          label: f.fieldContext ? `${f.name} (${f.fieldContext})` : f.name,
          value: f.name,
          field: f
        }));
      } catch (e) {
        if (e?.name === "AbortError") return;
        error.value = e?.message || String(e);
        options.value = currentNames().map((n) => ({ label: n, value: n }));
      } finally {
        loading.value = false;
      }
    }
    function debounceSearch(text) {
      if (timer) clearTimeout(timer);
      timer = setTimeout(() => search(text), 300);
    }
    function onChange(val) {
      if (props.multiple) {
        const names = Array.isArray(val) ? val.map(String) : val ? [String(val)] : [];
        emit(
          "update:modelValue",
          names.map((n) => fieldFromValue(n))
        );
        return;
      }
      const name = val == null || val === "" ? null : String(val);
      emit("update:modelValue", name ? fieldFromValue(name) : null);
    }
    watch(
      () => [props.signal, props.metricName, Boolean(props.datasourceApi)],
      () => {
        search("");
      },
      { immediate: true }
    );
    onBeforeUnmount(() => {
      if (timer) clearTimeout(timer);
      abort?.abort();
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$m, [
        createVNode(unref(GSelect), {
          value: __props.multiple ? currentNames() : currentNames()[0],
          options: options.value,
          mode: __props.multiple ? "multiple" : void 0,
          "show-search": "",
          "allow-clear": "",
          placeholder: __props.placeholder || "搜索字段…",
          loading: loading.value,
          "test-id": __props.testId || "signoz-field-key",
          onSearch: _cache[0] || (_cache[0] = ($event) => debounceSearch(String($event || ""))),
          "onUpdate:value": onChange
        }, null, 8, ["value", "options", "mode", "placeholder", "loading", "test-id"]),
        error.value ? (openBlock(), createElementBlock(
          "p",
          _hoisted_2$h,
          toDisplayString(error.value),
          1
          /* TEXT */
        )) : createCommentVNode("v-if", true)
      ]);
    };
  }
});
const FieldKeySelect = /* @__PURE__ */ _export_sfc(_sfc_main$n, [["__scopeId", "data-v-de824783"]]);
const _hoisted_1$l = {
  class: "group-by",
  "data-testid": "signoz-group-by-editor"
};
const _sfc_main$m = /* @__PURE__ */ defineComponent({
  __name: "GroupByEditor",
  props: {
    modelValue: {},
    signal: {},
    metricName: {},
    datasourceApi: {}
  },
  emits: ["update:modelValue"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    function asText() {
      return (props.modelValue || []).map((f) => f.name).join(",");
    }
    function fromText(v) {
      const next = String(v || "").split(",").map((s) => s.trim()).filter(Boolean).map((name) => ({
        name,
        fieldDataType: "string",
        fieldContext: "tag"
      }));
      emit("update:modelValue", next);
    }
    function onSelect(v) {
      const list = Array.isArray(v) ? v : v ? [v] : [];
      emit("update:modelValue", list);
    }
    function addField() {
      emit("update:modelValue", [
        ...props.modelValue || [],
        { name: "", fieldDataType: "string", fieldContext: "tag" }
      ]);
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$l, [
        __props.datasourceApi?.getMetadata ? (openBlock(), createBlock(FieldKeySelect, {
          key: 0,
          "model-value": __props.modelValue || [],
          multiple: "",
          signal: __props.signal || "metrics",
          "metric-name": __props.metricName,
          "datasource-api": __props.datasourceApi,
          "test-id": "signoz-group-by",
          "onUpdate:modelValue": onSelect
        }, null, 8, ["model-value", "signal", "metric-name", "datasource-api"])) : (openBlock(), createElementBlock(
          Fragment,
          { key: 1 },
          [
            createVNode(unref(GInput), {
              "model-value": asText(),
              placeholder: "service,name",
              "test-id": "signoz-group-by",
              "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => fromText(String($event)))
            }, null, 8, ["model-value"]),
            createVNode(unref(GButton), {
              size: "sm",
              variant: "secondary",
              type: "button",
              "test-id": "signoz-group-by-add",
              onClick: addField
            }, {
              default: withCtx(() => [..._cache[1] || (_cache[1] = [
                createTextVNode(
                  "+",
                  -1
                  /* CACHED */
                )
              ])]),
              _: 1
              /* STABLE */
            })
          ],
          64
          /* STABLE_FRAGMENT */
        ))
      ]);
    };
  }
});
const GroupByEditor = /* @__PURE__ */ _export_sfc(_sfc_main$m, [["__scopeId", "data-v-8436cf39"]]);
const _hoisted_1$k = {
  class: "groupby-field-select",
  "data-testid": "signoz-groupby-field-select"
};
const _sfc_main$l = /* @__PURE__ */ defineComponent({
  __name: "GroupByFieldSelect",
  props: {
    modelValue: {},
    signal: {},
    metricName: {},
    datasourceApi: {}
  },
  emits: ["update:modelValue"],
  setup(__props, { emit: __emit }) {
    const emit = __emit;
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$k, [
        createVNode(GroupByEditor, {
          "model-value": __props.modelValue,
          signal: __props.signal,
          "metric-name": __props.metricName,
          "datasource-api": __props.datasourceApi,
          "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => emit("update:modelValue", $event))
        }, null, 8, ["model-value", "signal", "metric-name", "datasource-api"])
      ]);
    };
  }
});
const GroupByFieldSelect = /* @__PURE__ */ _export_sfc(_sfc_main$l, [["__scopeId", "data-v-959f1373"]]);
const _hoisted_1$j = {
  class: "fn-ed",
  "data-testid": "signoz-function-editor",
  "data-matrix-id": "signoz-functions"
};
const _hoisted_2$g = {
  key: 0,
  "data-testid": "signoz-functions",
  class: "fn-anchor",
  "aria-hidden": "true"
};
const _hoisted_3$d = {
  key: 1,
  class: "warn",
  "data-testid": "signoz-function-unsupported",
  role: "status"
};
const _sfc_main$k = /* @__PURE__ */ defineComponent({
  __name: "FunctionEditor",
  props: {
    modelValue: {},
    unsupported: {},
    catalog: {},
    capabilities: {}
  },
  emits: ["update:modelValue"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const catalog = computed(() => {
      if (props.catalog?.length) return props.catalog;
      if (props.capabilities) {
        return functionsForEditor(props.capabilities).map((f) => ({
          name: f.name
        }));
      }
      return SIGNOZ_FUNCTION_CATALOG;
    });
    const options = computed(
      () => catalog.value.map((c) => ({ label: c.name, value: c.name }))
    );
    function updateAt(index2, patch) {
      const next = (props.modelValue || []).map((f, i) => {
        if (i !== index2) return f;
        const merged = { ...f, ...patch };
        if (patch.name && patch.name !== f.name) {
          merged.args = normalizeFunctionArgs(
            patch.name,
            (merged.args || []).map((a) => a.value)
          );
        }
        return merged;
      });
      emit("update:modelValue", next);
    }
    function setArgs(index2, text) {
      const fn = (props.modelValue || [])[index2];
      const parts = String(text || "").split(",").map((s) => s.trim()).filter((s) => s !== "");
      const args = normalizeFunctionArgs(fn?.name || "", parts);
      updateAt(index2, { args });
    }
    function argsText(f) {
      return (f.args || []).map((a) => a.value).join(",");
    }
    function add() {
      const first = catalog.value[0]?.name || "absolute";
      emit("update:modelValue", [
        ...props.modelValue || [],
        { name: first, args: [] }
      ]);
    }
    function removeAt(index2) {
      emit(
        "update:modelValue",
        (props.modelValue || []).filter((_, i) => i !== index2)
      );
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$j, [
        (openBlock(true), createElementBlock(
          Fragment,
          null,
          renderList(__props.modelValue || [], (fn, index2) => {
            return openBlock(), createElementBlock("div", {
              key: index2,
              class: "fn-row"
            }, [
              createVNode(unref(GSelect), {
                value: fn.name,
                options: options.value,
                "test-id": "signoz-functions",
                "onUpdate:value": ($event) => updateAt(index2, { name: String($event) })
              }, null, 8, ["value", "options", "onUpdate:value"]),
              createVNode(unref(GInput), {
                "model-value": argsText(fn),
                placeholder: "args (comma-separated)",
                "test-id": `signoz-function-args-${index2}`,
                "onUpdate:modelValue": ($event) => setArgs(index2, String($event))
              }, null, 8, ["model-value", "test-id", "onUpdate:modelValue"]),
              createVNode(unref(GButton), {
                size: "sm",
                variant: "secondary",
                type: "button",
                onClick: ($event) => removeAt(index2)
              }, {
                default: withCtx(() => [..._cache[0] || (_cache[0] = [
                  createTextVNode(
                    "×",
                    -1
                    /* CACHED */
                  )
                ])]),
                _: 1
                /* STABLE */
              }, 8, ["onClick"])
            ]);
          }),
          128
          /* KEYED_FRAGMENT */
        )),
        !(__props.modelValue || []).length ? (openBlock(), createElementBlock("span", _hoisted_2$g)) : createCommentVNode("v-if", true),
        createVNode(unref(GButton), {
          size: "sm",
          variant: "secondary",
          type: "button",
          "test-id": "signoz-function-add",
          onClick: add
        }, {
          default: withCtx(() => [..._cache[1] || (_cache[1] = [
            createTextVNode(
              " + 函数 ",
              -1
              /* CACHED */
            )
          ])]),
          _: 1
          /* STABLE */
        }),
        __props.unsupported?.length ? (openBlock(), createElementBlock(
          "p",
          _hoisted_3$d,
          " 已保存但不支持的函数: " + toDisplayString(__props.unsupported.join(", ")) + "（未删除，请调整或恢复 capability） ",
          1
          /* TEXT */
        )) : createCommentVNode("v-if", true)
      ]);
    };
  }
});
const FunctionEditor = /* @__PURE__ */ _export_sfc(_sfc_main$k, [["__scopeId", "data-v-1ad190f2"]]);
const _hoisted_1$i = {
  class: "multi-agg",
  "data-testid": "signoz-multi-agg"
};
const _sfc_main$j = /* @__PURE__ */ defineComponent({
  __name: "MultiAggEditor",
  props: {
    modelValue: {},
    signal: {},
    datasourceApi: {}
  },
  emits: ["update:modelValue"],
  setup(__props, { emit: __emit }) {
    const FN_OPTIONS = [
      "count",
      "count_distinct",
      "sum",
      "avg",
      "min",
      "max",
      "p05",
      "p10",
      "p50",
      "p90",
      "p95",
      "p99",
      "rate",
      "rate_sum",
      "rate_avg"
    ].map((v) => ({ label: v, value: v }));
    const props = __props;
    const emit = __emit;
    function rows() {
      return props.modelValue?.length ? props.modelValue : [{ expression: "count()" }];
    }
    function parseFn(expression) {
      const m = String(expression || "").match(/^([a-zA-Z0-9_]+)/);
      return m?.[1] || "count";
    }
    function parseField(expression) {
      const m = String(expression || "").match(/\(([^)]*)\)/);
      return (m?.[1] || "").trim();
    }
    function setAt(index2, fn, field) {
      const next = rows().map((r, i) => {
        if (i !== index2) return r;
        const expression = fn === "count" ? "count()" : `${fn}(${field || ""})`;
        return { ...r, expression, timeAggregation: fn };
      });
      emit("update:modelValue", next);
    }
    function add() {
      emit("update:modelValue", [...rows(), { expression: "count()" }]);
    }
    function removeAt(index2) {
      const next = rows().filter((_, i) => i !== index2);
      emit("update:modelValue", next.length ? next : [{ expression: "count()" }]);
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$i, [
        (openBlock(true), createElementBlock(
          Fragment,
          null,
          renderList(rows(), (row, index2) => {
            return openBlock(), createElementBlock("div", {
              key: index2,
              class: "row"
            }, [
              createVNode(unref(GSelect), {
                value: parseFn(row.expression),
                options: unref(FN_OPTIONS),
                "test-id": `signoz-multi-agg-fn-${index2}`,
                "onUpdate:value": ($event) => setAt(index2, String($event), parseField(row.expression))
              }, null, 8, ["value", "options", "test-id", "onUpdate:value"]),
              parseFn(row.expression) !== "count" ? (openBlock(), createBlock(FieldKeySelect, {
                key: 0,
                "model-value": parseField(row.expression) ? {
                  name: parseField(row.expression),
                  fieldDataType: "float64",
                  fieldContext: "tag"
                } : null,
                signal: __props.signal || "logs",
                "datasource-api": __props.datasourceApi,
                "number-only": "",
                "test-id": `signoz-multi-agg-field-${index2}`,
                "onUpdate:modelValue": ($event) => setAt(
                  index2,
                  parseFn(row.expression),
                  $event && typeof $event === "object" && "name" in $event ? String($event.name) : ""
                )
              }, null, 8, ["model-value", "signal", "datasource-api", "test-id", "onUpdate:modelValue"])) : (openBlock(), createBlock(unref(GInput), {
                key: 1,
                "model-value": "",
                disabled: "",
                placeholder: "count() 无字段",
                "test-id": `signoz-multi-agg-field-${index2}`
              }, null, 8, ["test-id"])),
              createVNode(unref(GButton), {
                size: "sm",
                variant: "secondary",
                type: "button",
                onClick: ($event) => removeAt(index2)
              }, {
                default: withCtx(() => [..._cache[0] || (_cache[0] = [
                  createTextVNode(
                    "×",
                    -1
                    /* CACHED */
                  )
                ])]),
                _: 1
                /* STABLE */
              }, 8, ["onClick"])
            ]);
          }),
          128
          /* KEYED_FRAGMENT */
        )),
        createVNode(unref(GButton), {
          size: "sm",
          variant: "secondary",
          type: "button",
          "test-id": "signoz-multi-agg-add",
          onClick: add
        }, {
          default: withCtx(() => [..._cache[1] || (_cache[1] = [
            createTextVNode(
              "+ 聚合",
              -1
              /* CACHED */
            )
          ])]),
          _: 1
          /* STABLE */
        })
      ]);
    };
  }
});
const MultiAggEditor = /* @__PURE__ */ _export_sfc(_sfc_main$j, [["__scopeId", "data-v-af460cc0"]]);
const _hoisted_1$h = {
  class: "expr-agg",
  "data-testid": "signoz-expression-aggregation-editor"
};
const _hoisted_2$f = {
  key: 0,
  class: "expr-agg-row"
};
const _sfc_main$i = /* @__PURE__ */ defineComponent({
  __name: "ExpressionAggregationEditor",
  props: {
    aggregations: {},
    signal: {},
    datasourceApi: {},
    testIdPrefix: {},
    multi: { type: Boolean }
  },
  emits: ["update:aggregations"],
  setup(__props, { emit: __emit }) {
    const EXPRESSION_PRESETS = [
      { label: "count()", value: "count()" },
      { label: "rate()", value: "rate()" },
      { label: "avg()", value: "avg()" },
      { label: "sum()", value: "sum()" },
      { label: "min()", value: "min()" },
      { label: "max()", value: "max()" },
      { label: "p50()", value: "p50()" },
      { label: "p90()", value: "p90()" },
      { label: "p95()", value: "p95()" },
      { label: "p99()", value: "p99()" }
    ];
    const props = __props;
    const emit = __emit;
    const tid = (base) => props.testIdPrefix ? `${base}-${props.testIdPrefix}` : base;
    const primaryExpr = computed({
      get: () => {
        const a = props.aggregations?.[0];
        if (!a) return "count()";
        if (a.kind === "expression" || a.expression)
          return String(a.expression || "count()");
        return String(a.timeAggregation || "count()");
      },
      set: (v) => {
        const expr = !v ? "count()" : v.includes("(") ? v : v === "count" ? "count()" : v;
        emit("update:aggregations", [{ kind: "expression", expression: expr }]);
      }
    });
    function onMulti(v) {
      const next = (v || []).map((a) => {
        if (a?.kind === "metric") return a;
        return {
          kind: "expression",
          expression: String(a?.expression || a?.timeAggregation || "count()"),
          ...a?.alias != null ? { alias: String(a.alias) } : {}
        };
      });
      emit(
        "update:aggregations",
        next.length ? next : [{ kind: "expression", expression: "count()" }]
      );
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$h, [
        !__props.multi ? (openBlock(), createElementBlock("div", _hoisted_2$f, [
          _cache[1] || (_cache[1] = createElementVNode(
            "span",
            { class: "qb-label" },
            "聚合",
            -1
            /* CACHED */
          )),
          createVNode(unref(GSelect), {
            value: primaryExpr.value,
            options: EXPRESSION_PRESETS,
            "allow-clear": "",
            "test-id": tid("signoz-aggregation"),
            class: "qb-flex",
            "onUpdate:value": _cache[0] || (_cache[0] = ($event) => primaryExpr.value = String($event || "count()"))
          }, null, 8, ["value", "test-id"])
        ])) : (openBlock(), createBlock(MultiAggEditor, {
          key: 1,
          "model-value": __props.aggregations,
          signal: __props.signal,
          "datasource-api": __props.datasourceApi,
          "onUpdate:modelValue": onMulti
        }, null, 8, ["model-value", "signal", "datasource-api"]))
      ]);
    };
  }
});
const ExpressionAggregationEditor = /* @__PURE__ */ _export_sfc(_sfc_main$i, [["__scopeId", "data-v-77f32c7d"]]);
const METRIC_AGG_CATALOG = {
  Sum: {
    time: ["rate", "increase"],
    space: ["sum", "avg", "min", "max", "count"],
    hideTimeAggregation: false
  },
  Gauge: {
    time: ["latest", "sum", "avg", "min", "max", "count", "count_distinct"],
    space: ["sum", "avg", "min", "max", "count"],
    hideTimeAggregation: false
  },
  Histogram: {
    time: [],
    space: ["p50", "p75", "p90", "p95", "p99"],
    hideTimeAggregation: true
  },
  ExponentialHistogram: {
    time: [],
    space: ["p50", "p75", "p90", "p95", "p99"],
    hideTimeAggregation: true
  },
  unknown: {
    time: [
      "latest",
      "sum",
      "avg",
      "min",
      "max",
      "count",
      "count_distinct",
      "rate",
      "increase"
    ],
    space: [
      "sum",
      "avg",
      "min",
      "max",
      "count",
      "p50",
      "p75",
      "p90",
      "p95",
      "p99"
    ],
    hideTimeAggregation: false
  }
};
function normalizeCatalogKind(type) {
  const t = String(type || "").toLowerCase();
  if (t.includes("exp") && t.includes("hist")) return "ExponentialHistogram";
  if (t.includes("hist")) return "Histogram";
  if (t === "sum" || t.startsWith("sum")) return "Sum";
  if (t.includes("gauge")) return "Gauge";
  if (t.includes("counter")) return "Sum";
  return "unknown";
}
function timeAggregationOptions(type) {
  const kind = normalizeCatalogKind(type);
  return METRIC_AGG_CATALOG[kind].time.map((v) => ({ label: v, value: v }));
}
function spaceAggregationOptions(type) {
  const kind = normalizeCatalogKind(type);
  return METRIC_AGG_CATALOG[kind].space.map((v) => ({ label: v, value: v }));
}
function shouldHideTimeAggregation(type) {
  return METRIC_AGG_CATALOG[normalizeCatalogKind(type)].hideTimeAggregation;
}
function coerceAggregationsForMetricType(type, current) {
  const timeOpts = timeAggregationOptions(type).map((o) => o.value);
  const spaceOpts = spaceAggregationOptions(type).map((o) => o.value);
  const hideTime = shouldHideTimeAggregation(type);
  const timeAggregation = hideTime ? void 0 : timeOpts.includes(String(current.timeAggregation || "")) ? current.timeAggregation : timeOpts[0];
  const spaceAggregation = spaceOpts.includes(
    String(current.spaceAggregation || "")
  ) ? current.spaceAggregation : spaceOpts[0];
  return { timeAggregation, spaceAggregation, hideTime };
}
const _hoisted_1$g = {
  class: "qb-metrics-agg-grid",
  "data-testid": "signoz-metric-aggregation-fields"
};
const _hoisted_2$e = {
  key: 0,
  class: "qb-metrics-agg-cell"
};
const _hoisted_3$c = { class: "qb-metrics-agg-cell" };
const _hoisted_4$9 = { class: "qb-metrics-agg-cell" };
const _hoisted_5$9 = { class: "qb-metrics-agg-cell" };
const _sfc_main$h = /* @__PURE__ */ defineComponent({
  __name: "MetricAggregationFields",
  props: {
    metricType: {},
    timeAggregation: {},
    spaceAggregation: {},
    stepInterval: {},
    testIdPrefix: {}
  },
  emits: ["update:metricType", "update:timeAggregation", "update:spaceAggregation", "update:stepInterval"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const tid = (base) => props.testIdPrefix ? `${base}-${props.testIdPrefix}` : base;
    const timeOpts = computed(() => timeAggregationOptions(props.metricType));
    const spaceOpts = computed(() => spaceAggregationOptions(props.metricType));
    const hideTime = computed(() => shouldHideTimeAggregation(props.metricType));
    watch(
      () => props.metricType,
      (t) => {
        const c = coerceAggregationsForMetricType(t, {
          timeAggregation: props.timeAggregation,
          spaceAggregation: props.spaceAggregation
        });
        if (!c.hideTime && c.timeAggregation != null && c.timeAggregation !== props.timeAggregation) {
          emit("update:timeAggregation", c.timeAggregation);
        }
        if (c.spaceAggregation != null && c.spaceAggregation !== props.spaceAggregation) {
          emit("update:spaceAggregation", c.spaceAggregation);
        }
      }
    );
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$g, [
        !hideTime.value ? (openBlock(), createElementBlock("div", _hoisted_2$e, [
          _cache[4] || (_cache[4] = createElementVNode(
            "span",
            { class: "qb-label" },
            "Time Agg",
            -1
            /* CACHED */
          )),
          createVNode(unref(GSelect), {
            value: __props.timeAggregation || void 0,
            options: timeOpts.value,
            "allow-clear": "",
            "test-id": tid("signoz-aggregation"),
            class: "qb-flex",
            "onUpdate:value": _cache[0] || (_cache[0] = ($event) => emit("update:timeAggregation", String($event || "")))
          }, null, 8, ["value", "options", "test-id"])
        ])) : createCommentVNode("v-if", true),
        createElementVNode("div", _hoisted_3$c, [
          _cache[5] || (_cache[5] = createElementVNode(
            "span",
            { class: "qb-label" },
            "Space Agg",
            -1
            /* CACHED */
          )),
          createVNode(unref(GSelect), {
            value: __props.spaceAggregation || void 0,
            options: spaceOpts.value,
            "allow-clear": "",
            "test-id": tid("signoz-space-agg"),
            class: "qb-flex",
            "onUpdate:value": _cache[1] || (_cache[1] = ($event) => emit("update:spaceAggregation", String($event || "")))
          }, null, 8, ["value", "options", "test-id"])
        ]),
        createElementVNode("div", _hoisted_4$9, [
          _cache[6] || (_cache[6] = createElementVNode(
            "span",
            { class: "qb-label" },
            "类型",
            -1
            /* CACHED */
          )),
          createVNode(unref(GSelect), {
            value: __props.metricType,
            options: [
              { label: "Gauge", value: "gauge" },
              { label: "Sum", value: "sum" },
              { label: "Histogram", value: "histogram" }
            ],
            "test-id": tid("signoz-metric-type"),
            class: "qb-flex",
            "onUpdate:value": _cache[2] || (_cache[2] = ($event) => emit("update:metricType", String($event)))
          }, null, 8, ["value", "test-id"])
        ]),
        createElementVNode("div", _hoisted_5$9, [
          _cache[7] || (_cache[7] = createElementVNode(
            "span",
            { class: "qb-label" },
            "Step",
            -1
            /* CACHED */
          )),
          createVNode(unref(GInput), {
            "model-value": __props.stepInterval != null ? String(__props.stepInterval) : "",
            placeholder: "auto",
            "test-id": tid("signoz-offset"),
            class: "qb-flex",
            "onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => emit(
              "update:stepInterval",
              String($event) === "" ? null : Number($event)
            ))
          }, null, 8, ["model-value", "test-id"])
        ])
      ]);
    };
  }
});
const MetricAggregationFields = /* @__PURE__ */ _export_sfc(_sfc_main$h, [["__scopeId", "data-v-1d3e0cd0"]]);
const _hoisted_1$f = {
  class: "qb-addons-bar",
  "data-testid": "signoz-query-addons"
};
const _hoisted_2$d = ["data-testid", "onClick"];
const _sfc_main$g = /* @__PURE__ */ defineComponent({
  __name: "QueryAddons",
  props: {
    active: {}
  },
  emits: ["toggle"],
  setup(__props, { emit: __emit }) {
    const ADDON_DEFS = [
      { key: "group_by", label: "Group By" },
      { key: "having", label: "Having" },
      { key: "limit", label: "Limit" },
      { key: "order_by", label: "Order By" }
    ];
    const props = __props;
    const emit = __emit;
    function on(key) {
      return props.active.includes(key);
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$f, [
        (openBlock(), createElementBlock(
          Fragment,
          null,
          renderList(ADDON_DEFS, (addon) => {
            return createElementVNode("button", {
              key: addon.key,
              type: "button",
              class: normalizeClass(["qb-addon-btn", { "qb-addon-btn--active": on(addon.key) }]),
              "data-testid": `signoz-addon-${addon.key}`,
              onClick: ($event) => emit("toggle", addon.key)
            }, toDisplayString(addon.label), 11, _hoisted_2$d);
          }),
          64
          /* STABLE_FRAGMENT */
        ))
      ]);
    };
  }
});
const QueryAddons = /* @__PURE__ */ _export_sfc(_sfc_main$g, [["__scopeId", "data-v-88bb0a01"]]);
const _hoisted_1$e = {
  class: "lqs",
  "data-testid": "signoz-log-query-search"
};
const _hoisted_2$c = ["value", "placeholder", "data-testid"];
const _hoisted_3$b = {
  key: 0,
  class: "lqs-status lqs-status--error",
  title: "引号未闭合"
};
const _hoisted_4$8 = {
  key: 0,
  class: "lqs-dropdown-loading"
};
const _hoisted_5$8 = ["onMousedown"];
const _hoisted_6$7 = { class: "lqs-dropdown-item-label" };
const _hoisted_7$5 = {
  key: 0,
  class: "lqs-dropdown-item-meta"
};
const _sfc_main$f = /* @__PURE__ */ defineComponent({
  ...{ name: "LogQuerySearch" },
  __name: "LogQuerySearch",
  props: {
    modelValue: {},
    placeholder: { default: "输入过滤表达式，例如 service.name = 'frontend' AND body CONTAINS 'error'" },
    signal: { default: "logs" },
    metricName: {},
    datasourceApi: {},
    testId: {}
  },
  emits: ["update:modelValue", "run"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const OP_DEFS = [
      { value: "=", meta: "Equal to", types: ["string", "number", "boolean", "keyword"] },
      { value: "!=", meta: "Not equal to", types: ["string", "number", "boolean", "keyword"] },
      { value: ">", meta: "Greater than", types: ["number"] },
      { value: ">=", meta: "Greater than or equal", types: ["number"] },
      { value: "<", meta: "Less than", types: ["number"] },
      { value: "<=", meta: "Less than or equal", types: ["number"] },
      { value: "IN", meta: "In list", types: ["string", "number", "keyword"] },
      { value: "NOT IN", meta: "Not in list", types: ["string", "number", "keyword"] },
      { value: "LIKE", meta: "Like", types: ["string", "keyword"] },
      { value: "ILIKE", meta: "Case-insensitive like", types: ["string", "keyword"] },
      { value: "CONTAINS", meta: "Contains", types: ["string", "keyword"] },
      { value: "NOT CONTAINS", meta: "Not contains", types: ["string", "keyword"] },
      { value: "EXISTS", meta: "Exists", types: ["string", "number", "boolean", "keyword"] },
      { value: "NOT EXISTS", meta: "Not exists", types: ["string", "number", "boolean", "keyword"] },
      { value: "REGEXP", meta: "Regular expression", types: ["string", "keyword"] },
      { value: "BETWEEN", meta: "Between", types: ["number"] }
    ];
    const CONJ_OPS = [
      { label: "AND", value: "AND", kind: "conj", meta: "and" },
      { label: "OR", value: "OR", kind: "conj", meta: "or" }
    ];
    const NON_VALUE_OPS = /* @__PURE__ */ new Set(["EXISTS", "NOT EXISTS"]);
    const wrapEl = ref(null);
    const inputEl = ref(null);
    const local = ref(props.modelValue || "");
    const open = ref(false);
    const loading = ref(false);
    const options = ref([]);
    const activeIdx = ref(0);
    const dropStyle = ref({});
    const suggestMode = ref("key");
    const keyTypeMap = ref({});
    let abort = null;
    let debounce = null;
    const showValidation = computed(() => {
      const s = local.value;
      const q = (s.match(/'/g) || []).length;
      const dq = (s.match(/"/g) || []).length;
      return q % 2 === 1 || dq % 2 === 1;
    });
    watch(
      () => props.modelValue,
      (v) => {
        if (v !== local.value) local.value = v || "";
      }
    );
    function commit(v, caret) {
      local.value = v;
      emit("update:modelValue", v);
      void nextTick(() => {
        const el = inputEl.value;
        if (!el) return;
        el.focus();
        const pos = caret == null ? v.length : Math.min(caret, v.length);
        el.setSelectionRange(pos, pos);
      });
    }
    function onInput(e) {
      const v = e.target.value;
      local.value = v;
      emit("update:modelValue", v);
      scheduleSuggest();
    }
    function onKeydown(e) {
      if (e.key === "Enter" && !e.shiftKey) {
        if (open.value && options.value[activeIdx.value]) {
          e.preventDefault();
          applyOpt(options.value[activeIdx.value]);
          return;
        }
        e.preventDefault();
        open.value = false;
        emit("run", local.value);
        return;
      }
      if (e.key === "Tab" && open.value && options.value[activeIdx.value]) {
        e.preventDefault();
        applyOpt(options.value[activeIdx.value]);
        return;
      }
      if (!open.value) return;
      if (e.key === "ArrowDown") {
        e.preventDefault();
        activeIdx.value = Math.min(activeIdx.value + 1, options.value.length - 1);
      } else if (e.key === "ArrowUp") {
        e.preventDefault();
        activeIdx.value = Math.max(activeIdx.value - 1, 0);
      } else if (e.key === "Escape") {
        open.value = false;
      }
    }
    function tokenAtCursor(text = local.value, pos) {
      const el = inputEl.value;
      const caret = pos ?? el?.selectionStart ?? text.length;
      const left = text.slice(0, caret);
      const parts = left.split(/\s+(?:AND|OR)\s+/i);
      const seg = parts[parts.length - 1] ?? "";
      const completePair = /^\s*(\S+)\s+(NOT\s+)?(EXISTS|NOT\s+EXISTS|=|!=|>=|<=|>|<|IN|NOT\s+IN|LIKE|ILIKE|CONTAINS|NOT\s+CONTAINS|REGEXP|BETWEEN)\s+(?:('[^']*'|"[^"]*"|\[[^\]]*\]|\S+))\s+$/i;
      if (completePair.test(seg) || /^\s*(\S+)\s+(NOT\s+)?EXISTS\s+$/i.test(seg)) {
        return { prefix: "", mode: "conj" };
      }
      const keyOnly = seg.match(/^\s*([a-zA-Z0-9_.[\]/-]*)$/);
      if (keyOnly) {
        const k = keyOnly[1] || "";
        if (!k) return { prefix: "", mode: "key" };
        if (/\s$/.test(seg)) return { prefix: "", mode: "op", key: k.trim() };
        return { prefix: k, mode: "key" };
      }
      const keySpace = seg.match(/^\s*([a-zA-Z0-9_.[\]/-]+)\s+$/);
      if (keySpace) {
        return { prefix: "", mode: "op", key: keySpace[1] };
      }
      const keyOp = seg.match(
        /^\s*([a-zA-Z0-9_.[\]/-]+)\s+(NOT\s+)?([A-Za-z!<>=]+)?(\s*)$/
      );
      if (keyOp) {
        const key = keyOp[1];
        const notPrefix = keyOp[2] || "";
        const opPart = (notPrefix + (keyOp[3] || "")).trim();
        const trailingSpace = keyOp[4] || "";
        if (!opPart) return { prefix: "", mode: "op", key };
        if (!trailingSpace) return { prefix: opPart, mode: "op", key };
        const opUpper = opPart.replace(/\s+/g, " ").toUpperCase();
        if (NON_VALUE_OPS.has(opUpper)) {
          return { prefix: "", mode: "conj", key, op: opUpper };
        }
        return { prefix: "", mode: "value", key, op: opUpper };
      }
      const keyOpVal = seg.match(
        /^\s*([a-zA-Z0-9_.[\]/-]+)\s+(NOT\s+(?:IN|EXISTS|CONTAINS|LIKE|ILIKE)|EXISTS|IN|LIKE|ILIKE|CONTAINS|REGEXP|BETWEEN|=|!=|>=|<=|>|<)\s+([\s\S]*)$/i
      );
      if (keyOpVal) {
        const key = keyOpVal[1];
        const op = keyOpVal[2].replace(/\s+/g, " ").toUpperCase();
        const rest = keyOpVal[3] ?? "";
        if (NON_VALUE_OPS.has(op)) {
          return { prefix: "", mode: "conj", key, op };
        }
        if (/^\s*('[^']*'|"[^"]*"|\[[^\]]*\])\s+$/.test(rest) || /^\s*\S+\s+$/.test(rest)) {
          return { prefix: "", mode: "conj", key, op };
        }
        const prefix = rest.trim().replace(/^['"]|['"]$/g, "").replace(/^\[|\]$/g, "");
        return { prefix, mode: "value", key, op };
      }
      return { prefix: "", mode: "key" };
    }
    function scheduleSuggest(immediate = false) {
      if (debounce) clearTimeout(debounce);
      if (immediate) {
        void loadSuggest();
        return;
      }
      debounce = setTimeout(() => void loadSuggest(), 120);
    }
    async function loadSuggest() {
      const ctx = tokenAtCursor();
      suggestMode.value = ctx.mode;
      activeIdx.value = 0;
      if (ctx.mode === "op") {
        const keyType = (ctx.key && keyTypeMap.value[ctx.key] || "string").toLowerCase();
        const q = (ctx.prefix || "").toUpperCase();
        options.value = OP_DEFS.filter((o) => {
          if (q && !o.value.toUpperCase().includes(q)) return false;
          if (!o.types) return true;
          if (keyType === "number" || keyType === "float" || keyType === "int") {
            return o.types.includes("number");
          }
          if (keyType === "boolean" || keyType === "bool") {
            return o.types.includes("boolean");
          }
          return o.types.includes("string") || o.types.includes("keyword");
        }).map((o) => ({
          label: o.value,
          value: o.value,
          meta: o.meta,
          kind: "op"
        }));
        open.value = options.value.length > 0;
        await nextTick();
        placeDropdown();
        return;
      }
      if (ctx.mode === "conj") {
        options.value = CONJ_OPS;
        open.value = true;
        await nextTick();
        placeDropdown();
        return;
      }
      if (!props.datasourceApi?.getMetadata) {
        options.value = [];
        open.value = false;
        return;
      }
      abort?.abort();
      abort = new AbortController();
      loading.value = true;
      try {
        if (ctx.mode === "key") {
          const res = await props.datasourceApi.getMetadata(
            {
              type: "attributeKeys",
              signal: props.signal || "logs",
              metricName: props.metricName,
              search: ctx.prefix || void 0
            },
            abort.signal
          );
          const vals = Array.isArray(res?.values) ? res.values : [];
          const nextMap = { ...keyTypeMap.value };
          options.value = vals.map((v) => {
            const name = String(v?.name ?? v?.key ?? v ?? "").trim();
            if (!name) return null;
            const ft = String(
              v?.fieldDataType || v?.dataType || v?.type || "string"
            );
            nextMap[name] = ft;
            return {
              label: name,
              value: name,
              kind: "key",
              meta: ft,
              fieldType: ft
            };
          }).filter(Boolean);
          keyTypeMap.value = nextMap;
          if (ctx.prefix) {
            const p = ctx.prefix.toLowerCase();
            options.value = options.value.filter(
              (o) => o.label.toLowerCase().includes(p)
            );
          }
        } else {
          const key = ctx.key || "";
          if (!key) {
            options.value = [];
            open.value = false;
            return;
          }
          const res = await props.datasourceApi.getMetadata(
            {
              type: "attributeValues",
              signal: props.signal || "logs",
              metricName: props.metricName,
              attributeKey: key,
              search: ctx.prefix || void 0
            },
            abort.signal
          );
          const vals = Array.isArray(res?.values) ? res.values : [];
          options.value = vals.map((v) => {
            const raw = v == null ? "" : typeof v === "object" ? String(v.value ?? v.name ?? "") : String(v);
            if (raw === "") return null;
            return {
              label: raw,
              value: raw,
              kind: "value",
              meta: "value"
            };
          }).filter(Boolean);
          if (ctx.prefix) {
            const p = ctx.prefix.toLowerCase();
            options.value = options.value.filter(
              (o) => o.label.toLowerCase().includes(p)
            );
          }
        }
        open.value = options.value.length > 0 || loading.value;
        await nextTick();
        placeDropdown();
      } catch (e) {
        if (e?.name === "AbortError") return;
        options.value = [];
        open.value = false;
      } finally {
        loading.value = false;
      }
    }
    function placeDropdown() {
      const el = wrapEl.value;
      if (!el) return;
      const r = el.getBoundingClientRect();
      dropStyle.value = {
        position: "fixed",
        top: `${r.bottom + 4}px`,
        left: `${r.left}px`,
        width: `${Math.max(r.width, 320)}px`,
        zIndex: "3000"
      };
    }
    function quoteValue(insert, op) {
      if (op === "IN" || op === "NOT IN") {
        if (insert.startsWith("[")) return insert;
        const needsQuote2 = !/^\d+(\.\d+)?$/.test(insert) && insert !== "true" && insert !== "false";
        const lit = needsQuote2 ? `'${insert.replace(/'/g, "\\'")}'` : insert;
        return `[${lit}]`;
      }
      const needsQuote = !/^\d+(\.\d+)?$/.test(insert) && insert !== "true" && insert !== "false";
      return needsQuote ? `'${insert.replace(/'/g, "\\'")}'` : insert;
    }
    function applyOpt(opt) {
      const el = inputEl.value;
      const text = local.value;
      const pos = el?.selectionStart ?? text.length;
      const left = text.slice(0, pos);
      const right = text.slice(pos);
      const mode2 = suggestMode.value;
      const ctx = tokenAtCursor(text, pos);
      let next = text;
      let caret = pos;
      if (mode2 === "key" || opt.kind === "key") {
        const replaced = left.replace(/([a-zA-Z0-9_.[\]/-]*)$/, `${opt.value} `);
        next = replaced + right;
        caret = replaced.length;
        if (opt.fieldType) keyTypeMap.value[opt.value] = opt.fieldType;
      } else if (mode2 === "op" || opt.kind === "op") {
        const m = left.match(/^(.*?\S)(\s+)(\S*)$/);
        if (m) {
          const base = m[1] + m[2] + opt.value + " ";
          next = base + right;
          caret = base.length;
        } else {
          next = left.replace(/(\S*)$/, `${opt.value} `) + right;
          caret = next.length - right.length;
        }
      } else if (mode2 === "conj" || opt.kind === "conj") {
        const base = left.replace(/\s*$/, ` ${opt.value} `);
        next = base + right;
        caret = base.length;
      } else {
        const lit = quoteValue(opt.value, ctx.op);
        const m = left.match(
          /^(.*?(?:=|!=|>=|<=|>|<|IN|NOT IN|LIKE|ILIKE|CONTAINS|NOT CONTAINS|REGEXP|BETWEEN)\s+)([\s\S]*)$/i
        );
        if (m) {
          const base = m[1] + lit + " ";
          next = base + right;
          caret = base.length;
        } else {
          const base = left.replace(/(['"]?)[^'"=\s[\]]*$/, lit + " ");
          next = base + right;
          caret = base.length;
        }
      }
      commit(next, caret);
      void nextTick(() => {
        scheduleSuggest(true);
      });
    }
    function onFocus() {
      scheduleSuggest(true);
    }
    function onDocClick(e) {
      if (!wrapEl.value) return;
      if (!wrapEl.value.contains(e.target)) {
        const drop = document.querySelector('[data-testid="signoz-lqs-dropdown"]');
        if (drop && drop.contains(e.target)) return;
        open.value = false;
      }
    }
    onMounted(() => document.addEventListener("mousedown", onDocClick, true));
    onBeforeUnmount(() => {
      document.removeEventListener("mousedown", onDocClick, true);
      abort?.abort();
      if (debounce) clearTimeout(debounce);
    });
    watch(
      () => [props.signal, props.metricName],
      () => {
        if (open.value) scheduleSuggest(true);
      }
    );
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$e, [
        createElementVNode(
          "div",
          {
            ref_key: "wrapEl",
            ref: wrapEl,
            class: normalizeClass(["lqs-editor-wrap", { "lqs-editor-wrap--error": showValidation.value }])
          },
          [
            _cache[0] || (_cache[0] = createElementVNode(
              "span",
              {
                class: "lqs-lead",
                "aria-hidden": "true"
              },
              "⌕",
              -1
              /* CACHED */
            )),
            createElementVNode("input", {
              ref_key: "inputEl",
              ref: inputEl,
              class: "lqs-editor",
              type: "text",
              value: local.value,
              placeholder: __props.placeholder,
              "data-testid": __props.testId || "signoz-filter",
              autocomplete: "off",
              spellcheck: "false",
              onInput,
              onKeydown,
              onFocus
            }, null, 40, _hoisted_2$c),
            showValidation.value ? (openBlock(), createElementBlock("span", _hoisted_3$b, "!")) : createCommentVNode("v-if", true)
          ],
          2
          /* CLASS */
        ),
        (openBlock(), createBlock(Teleport, { to: "body" }, [
          open.value ? (openBlock(), createElementBlock(
            "ul",
            {
              key: 0,
              class: "lqs-dropdown",
              style: normalizeStyle(dropStyle.value),
              role: "listbox",
              "data-testid": "signoz-lqs-dropdown"
            },
            [
              loading.value && !options.value.length ? (openBlock(), createElementBlock("li", _hoisted_4$8, " 加载中… ")) : createCommentVNode("v-if", true),
              (openBlock(true), createElementBlock(
                Fragment,
                null,
                renderList(options.value, (opt, i) => {
                  return openBlock(), createElementBlock("li", {
                    key: opt.kind + opt.value + i,
                    role: "option",
                    class: normalizeClass(["lqs-dropdown-item", { "lqs-dropdown-item--active": i === activeIdx.value }]),
                    onMousedown: withModifiers(($event) => applyOpt(opt), ["prevent"])
                  }, [
                    createElementVNode(
                      "span",
                      _hoisted_6$7,
                      toDisplayString(opt.label),
                      1
                      /* TEXT */
                    ),
                    opt.meta ? (openBlock(), createElementBlock(
                      "span",
                      _hoisted_7$5,
                      toDisplayString(opt.meta),
                      1
                      /* TEXT */
                    )) : createCommentVNode("v-if", true)
                  ], 42, _hoisted_5$8);
                }),
                128
                /* KEYED_FRAGMENT */
              ))
            ],
            4
            /* STYLE */
          )) : createCommentVNode("v-if", true)
        ]))
      ]);
    };
  }
});
const LogQuerySearch = /* @__PURE__ */ _export_sfc(_sfc_main$f, [["__scopeId", "data-v-eacfa99b"]]);
function validateFilterExpression(expr) {
  const s = String(expr || "");
  let depth = 0;
  let inQuote = false;
  let escape = false;
  for (let i = 0; i < s.length; i++) {
    const ch = s[i];
    if (escape) {
      escape = false;
      continue;
    }
    if (ch === "\\" && inQuote) {
      escape = true;
      continue;
    }
    if (ch === "'") {
      inQuote = !inQuote;
      continue;
    }
    if (inQuote) continue;
    if (ch === "(") depth++;
    if (ch === ")") {
      depth--;
      if (depth < 0)
        return { ok: false, message: "多余的右括号", column: i + 1 };
    }
  }
  if (inQuote) return { ok: false, message: "未闭合的引号", column: s.length };
  if (depth !== 0)
    return { ok: false, message: "括号未闭合", column: s.length };
  return { ok: true };
}
const _hoisted_1$d = {
  class: "filter-expr-editor",
  "data-testid": "signoz-filter-expression-editor"
};
const _hoisted_2$b = {
  key: 0,
  class: "err",
  "data-testid": "signoz-filter-syntax-error"
};
const _hoisted_3$a = { key: 0 };
const _sfc_main$e = /* @__PURE__ */ defineComponent({
  __name: "FilterExpressionEditor",
  props: {
    modelValue: {},
    signal: {},
    metricName: {},
    datasourceApi: {},
    testId: {}
  },
  emits: ["update:modelValue", "run"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const validation = computed(() => validateFilterExpression(props.modelValue));
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$d, [
        createVNode(LogQuerySearch, {
          "model-value": __props.modelValue,
          signal: __props.signal,
          "metric-name": __props.metricName,
          "datasource-api": __props.datasourceApi,
          "test-id": __props.testId || "signoz-filter",
          "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => emit("update:modelValue", $event)),
          onRun: _cache[1] || (_cache[1] = ($event) => emit("run", $event))
        }, null, 8, ["model-value", "signal", "metric-name", "datasource-api", "test-id"]),
        !validation.value.ok ? (openBlock(), createElementBlock("p", _hoisted_2$b, [
          createTextVNode(
            toDisplayString(validation.value.message),
            1
            /* TEXT */
          ),
          validation.value.column ? (openBlock(), createElementBlock(
            "span",
            _hoisted_3$a,
            "（列 " + toDisplayString(validation.value.column) + "）",
            1
            /* TEXT */
          )) : createCommentVNode("v-if", true)
        ])) : createCommentVNode("v-if", true)
      ]);
    };
  }
});
const FilterExpressionEditor = /* @__PURE__ */ _export_sfc(_sfc_main$e, [["__scopeId", "data-v-2d171e85"]]);
const AGG_MATRIX = {
  gauge: {
    time: ["latest", "avg", "sum", "min", "max", "count", "count_distinct"],
    space: ["avg", "sum", "min", "max", "count"]
  },
  sum: {
    time: ["rate", "increase"],
    space: ["sum", "avg", "min", "max", "count"]
  },
  counter: {
    time: ["rate", "increase"],
    space: ["sum", "avg", "min", "max", "count"]
  },
  histogram: {
    time: [],
    space: ["p50", "p75", "p90", "p95", "p99"],
    hideTimeAgg: true
  },
  summary: {
    time: ["avg", "sum", "min", "max", "count"],
    space: ["avg", "sum", "min", "max", "count"]
  },
  unknown: {
    time: [
      "latest",
      "sum",
      "avg",
      "min",
      "max",
      "count",
      "count_distinct",
      "rate",
      "increase"
    ],
    space: ["sum", "avg", "min", "max", "count", "p50", "p95", "p99"]
  }
};
function normalizeMetricKind(type) {
  const t = String(type || "").toLowerCase();
  if (t.includes("hist")) return "histogram";
  if (t.includes("summary")) return "summary";
  if (t.includes("counter")) return "counter";
  if (t === "sum" || t.startsWith("sum")) return "sum";
  if (t.includes("gauge")) return "gauge";
  return "unknown";
}
function timeAggOptionsFor(type) {
  const kind = normalizeMetricKind(type);
  const list = AGG_MATRIX[kind].time;
  const seen = /* @__PURE__ */ new Set();
  const out = [];
  for (const v of list) {
    const key = v.toLowerCase();
    if (seen.has(key)) continue;
    seen.add(key);
    out.push({ label: v, value: v });
  }
  return out;
}
function spaceAggOptionsFor(type) {
  const kind = normalizeMetricKind(type);
  const list = AGG_MATRIX[kind].space;
  const seen = /* @__PURE__ */ new Set();
  const out = [];
  for (const v of list) {
    const key = v.toLowerCase();
    if (seen.has(key)) continue;
    seen.add(key);
    out.push({ label: v, value: v });
  }
  return out;
}
const _hoisted_1$c = {
  class: "qb-elements",
  "data-testid": "signoz-signal-builder-form"
};
const _hoisted_2$a = {
  key: 0,
  class: "qb-meta-err",
  "data-testid": "signoz-builder-meta-error"
};
const _hoisted_3$9 = {
  key: 1,
  class: "qb-meta-loading",
  "data-testid": "signoz-builder-meta-loading"
};
const _hoisted_4$7 = { class: "qb-row qb-row--filter" };
const _hoisted_5$7 = { class: "qb-metric-option" };
const _hoisted_6$6 = { class: "qb-metric-name" };
const _hoisted_7$4 = {
  key: 0,
  class: "qb-metric-type"
};
const _hoisted_8$2 = { class: "qb-row qb-row--agg" };
const _hoisted_9$1 = ["data-testid"];
const _hoisted_10$1 = {
  key: 2,
  class: "qb-addons-content"
};
const _hoisted_11$1 = {
  key: 0,
  class: "qb-addon-cell qb-addon-cell--full"
};
const _hoisted_12$1 = {
  key: 1,
  class: "qb-addon-cell"
};
const _hoisted_13$1 = {
  key: 2,
  class: "qb-addon-cell"
};
const _hoisted_14$1 = {
  key: 3,
  class: "qb-addon-cell"
};
const _hoisted_15$1 = {
  key: 4,
  class: "qb-addon-cell"
};
const _hoisted_16$1 = {
  key: 5,
  class: "qb-addon-cell qb-addon-cell--full"
};
const _hoisted_17$1 = {
  key: 0,
  class: "qb-warn"
};
const _hoisted_18$1 = {
  key: 6,
  class: "qb-addon-cell"
};
const _hoisted_19$1 = {
  key: 7,
  class: "qb-addon-cell"
};
const _hoisted_20$1 = {
  key: 8,
  class: "qb-addon-cell qb-addon-cell--full qb-more-grid"
};
const _hoisted_21 = { class: "qb-metrics-agg-cell" };
const _hoisted_22 = { class: "qb-metrics-agg-cell" };
const _hoisted_23 = {
  key: 0,
  class: "qb-metrics-agg-cell"
};
const _hoisted_24 = {
  key: 1,
  class: "qb-metrics-agg-cell"
};
const _hoisted_25 = {
  key: 2,
  class: "qb-metrics-agg-cell"
};
const _hoisted_26 = {
  key: 3,
  class: "qb-metrics-agg-cell"
};
const _hoisted_27 = {
  key: 4,
  class: "qb-metrics-agg-cell"
};
const _hoisted_28 = {
  key: 5,
  class: "qb-metrics-agg-cell"
};
const _hoisted_29 = {
  key: 6,
  class: "qb-metrics-agg-cell"
};
const _hoisted_30 = { class: "qb-metrics-agg-cell" };
const _hoisted_31 = { class: "qb-metrics-agg-cell" };
const _hoisted_32 = {
  class: "sr-only",
  "aria-hidden": "true"
};
const _hoisted_33 = ["data-testid"];
const _hoisted_34 = ["data-testid"];
const _hoisted_35 = ["data-testid"];
const _hoisted_36 = ["data-testid"];
const _hoisted_37 = ["data-testid"];
const _hoisted_38 = ["data-testid"];
const _hoisted_39 = ["data-testid"];
const _hoisted_40 = {
  key: 7,
  "data-testid": "signoz-group-by"
};
const _hoisted_41 = ["data-testid"];
const _hoisted_42 = ["data-testid"];
const _hoisted_43 = ["data-testid"];
const _hoisted_44 = ["data-testid"];
const _hoisted_45 = ["data-testid"];
const _hoisted_46 = ["data-testid"];
const _hoisted_47 = ["data-testid"];
const _hoisted_48 = ["data-testid"];
const _hoisted_49 = ["data-testid"];
const _hoisted_50 = ["data-testid"];
const _hoisted_51 = ["data-testid"];
const _hoisted_52 = ["data-testid"];
const _sfc_main$d = /* @__PURE__ */ defineComponent({
  __name: "SignalBuilderForm",
  props: {
    spec: {},
    isPrimary: { type: Boolean },
    datasourceApi: {},
    capabilities: {}
  },
  emits: ["update:spec", "run"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const metricType = ref("gauge");
    const services = ref([]);
    const operations = ref([]);
    const metrics = ref([]);
    const metaError = ref("");
    const metaLoading = ref(false);
    const activeAddons = ref([]);
    function toggleAddon(key) {
      if (activeAddons.value.includes(key)) {
        activeAddons.value = activeAddons.value.filter((k) => k !== key);
      } else {
        activeAddons.value = [...activeAddons.value, key];
      }
    }
    function addonOn(key) {
      return activeAddons.value.includes(key);
    }
    const caps2 = computed(
      () => props.capabilities || {
        builder: true,
        formula: true,
        promql: true,
        clickhouseSql: true,
        traceOperator: true,
        subQuery: false,
        join: false,
        anomaly: false,
        distribution: false,
        alerts: false
      }
    );
    const unsupportedFns = computed(() => {
      const names = (props.spec.functions || []).map((f) => f.name);
      return names.filter(
        (n) => n === "anomaly" ? !caps2.value.anomaly : !STABLE_FUNCTIONS.includes(n)
      );
    });
    computed(() => timeAggOptionsFor(metricType.value));
    computed(() => spaceAggOptionsFor(metricType.value));
    function patch(partial) {
      emit("update:spec", { ...props.spec, ...partial });
    }
    function setSecondaryMeta(key, raw) {
      const cur = props.spec.secondaryAggregations?.[0] || {};
      const value = key === "stepInterval" ? String(raw ?? "") === "" ? void 0 : Number(raw) : String(raw ?? "");
      patch({
        secondaryAggregations: [
          {
            ...cur,
            [key]: value,
            expression: cur.expression || secondaryAgg.value || void 0
          }
        ]
      });
    }
    function setSpaceAgg(v) {
      const agg = props.spec.aggregations?.[0] || {};
      patch({
        aggregations: [
          {
            ...agg,
            spaceAggregation: v || void 0,
            metricName: agg.metricName || metric.value
          }
        ]
      });
    }
    const metric = computed({
      get: () => props.spec.aggregations?.[0]?.metricName || "",
      set: (v) => {
        const agg = props.spec.aggregations?.[0] || {};
        const next = {
          ...agg,
          metricName: v,
          timeAggregation: agg.timeAggregation || "avg",
          spaceAggregation: agg.spaceAggregation || "avg"
        };
        if (props.spec.signal === "metrics") delete next.expression;
        patch({ aggregations: [next] });
        void loadMetricMeta(v);
      }
    });
    async function loadMetricMeta(name) {
      if (!name || !props.datasourceApi?.getMetadata) return;
      try {
        const res = await props.datasourceApi.getMetadata({
          type: "metrics",
          search: name
        });
        const list = Array.isArray(res?.values) ? res.values : [];
        const hit = list.find((m) => m.metricName === name) || list[0];
        if (hit?.type) {
          const kind = normalizeMetricKind(hit.type);
          if (kind === "histogram") metricType.value = "histogram";
          else if (kind === "counter" || kind === "sum") metricType.value = "sum";
          else if (kind === "gauge") metricType.value = "gauge";
          const agg = props.spec.aggregations?.[0] || {};
          patch({
            aggregations: [
              {
                ...agg,
                metricName: name,
                metricType: hit.type,
                temporality: hit.temporality || agg.temporality
              }
            ]
          });
        }
      } catch {
      }
    }
    const aggregation = computed({
      get: () => props.spec.signal === "metrics" ? props.spec.aggregations?.[0]?.timeAggregation || "" : props.spec.aggregations?.[0]?.expression || props.spec.aggregations?.[0]?.timeAggregation || "",
      set: (v) => {
        const agg = props.spec.aggregations?.[0] || {};
        if (props.spec.signal === "metrics") {
          const next = {
            ...agg,
            timeAggregation: v || "avg",
            spaceAggregation: agg.spaceAggregation || "avg",
            metricName: agg.metricName || metric.value
          };
          delete next.expression;
          patch({ aggregations: [next] });
          return;
        }
        const expr = v || "count()";
        patch({
          aggregations: [
            {
              expression: expr.includes("(") ? expr : expr === "count" ? "count()" : expr
            }
          ]
        });
      }
    });
    const filter2 = computed({
      get: () => props.spec.filter?.expression || "",
      set: (v) => patch({ filter: { expression: v } })
    });
    const having = computed({
      get: () => props.spec.having?.expression || "",
      set: (v) => patch({ having: { expression: v } })
    });
    const order = computed({
      get: () => {
        const o = props.spec.order?.[0];
        if (!o) return "";
        return (o.direction === "desc" ? "-" : "") + o.key.name;
      },
      set: (v) => {
        const s = String(v || "");
        patch({
          order: s ? [
            {
              key: { name: s.replace(/^-/, "") },
              direction: s.startsWith("-") ? "desc" : "asc"
            }
          ] : []
        });
      }
    });
    const limit = computed({
      get: () => props.spec.limit != null ? String(props.spec.limit) : "",
      set: (v) => patch({ limit: v === "" ? void 0 : Number(v) })
    });
    computed({
      get: () => props.spec.offset != null ? String(props.spec.offset) : "",
      set: (v) => patch({ offset: v === "" ? void 0 : Number(v) })
    });
    const selectFieldsText = computed({
      get: () => (props.spec.selectFields || []).map((f) => f.name).join(","),
      set: (v) => {
        const fields = String(v || "").split(",").map((s) => s.trim()).filter(Boolean).map((name) => ({
          name,
          fieldDataType: "string",
          fieldContext: "tag"
        }));
        patch({ selectFields: fields });
      }
    });
    const limitByText = computed({
      get: () => (props.spec.limitBy?.keys || []).join(","),
      set: (v) => {
        const keys = String(v || "").split(",").map((s) => s.trim()).filter(Boolean);
        if (!keys.length) {
          patch({ limitBy: void 0 });
          return;
        }
        patch({
          limitBy: {
            keys,
            value: props.spec.limitBy?.value ?? props.spec.limit ?? 10
          }
        });
      }
    });
    const limitByValue = computed({
      get: () => props.spec.limitBy?.value != null ? String(props.spec.limitBy.value) : "",
      set: (v) => {
        const keys = props.spec.limitBy?.keys || [];
        if (!keys.length && !v) {
          patch({ limitBy: void 0 });
          return;
        }
        patch({
          limitBy: {
            keys: keys.length ? keys : [],
            value: v === "" ? void 0 : Number(v)
          }
        });
      }
    });
    const secondaryAgg = computed({
      get: () => props.spec.secondaryAggregations?.[0]?.expression || props.spec.secondaryAggregations?.[0]?.timeAggregation || "",
      set: (v) => {
        if (!v) {
          patch({ secondaryAggregations: void 0 });
          return;
        }
        patch({
          secondaryAggregations: [
            {
              expression: v,
              timeAggregation: v,
              metricName: metric.value || void 0
            }
          ]
        });
      }
    });
    const legend = computed({
      get: () => props.spec.legend || "",
      set: (v) => patch({ legend: v })
    });
    const service = computed({
      get: () => props.spec.service || "",
      set: (v) => patch({ service: v })
    });
    const operation = computed({
      get: () => props.spec.operation || "",
      set: (v) => patch({ operation: v })
    });
    const source = computed({
      get: () => props.spec.source || "",
      set: (v) => patch({ source: v })
    });
    const environment = computed({
      get: () => props.spec.environment || "",
      set: (v) => patch({ environment: v })
    });
    const tags = computed({
      get: () => (props.spec.tags || []).map((t) => `${t.key}${t.operator}${t.value}`).join(","),
      set: (v) => {
        const next = String(v || "").split(",").map((s) => s.trim()).filter(Boolean).map((pair) => {
          const m = pair.match(/^([^=!~]+)(=~|!~|=|!=)(.*)$/);
          if (m) {
            return {
              key: m[1].trim(),
              operator: m[2],
              value: m[3].trim()
            };
          }
          const [key, ...rest] = pair.split("=");
          return {
            key: key.trim(),
            operator: "=",
            value: rest.join("=").trim()
          };
        });
        patch({ tags: next });
      }
    });
    const minDuration = computed({
      get: () => props.spec.duration && (props.spec.duration.operator === ">" || props.spec.duration.operator === ">=") ? String(props.spec.duration.value) : "",
      set: (v) => {
        if (!v) {
          patch({ duration: void 0 });
          return;
        }
        patch({ duration: { operator: ">=", value: Number(v) || 0, unit: "ms" } });
      }
    });
    const maxDuration = computed({
      get: () => props.spec.duration && (props.spec.duration.operator === "<" || props.spec.duration.operator === "<=") ? String(props.spec.duration.value) : "",
      set: (v) => {
        if (!v) {
          if (props.spec.duration && (props.spec.duration.operator === ">" || props.spec.duration.operator === ">=")) {
            return;
          }
          patch({ duration: void 0 });
          return;
        }
        patch({ duration: { operator: "<=", value: Number(v) || 0, unit: "ms" } });
      }
    });
    const signal = computed(() => props.spec.signal);
    const showMetrics = computed(() => signal.value === "metrics");
    const metricSelectOptions = computed(
      () => metrics.value.map((m) => ({
        label: m.label,
        value: m.value,
        type: m.type
      }))
    );
    const showLogsTraces = computed(
      () => signal.value === "logs" || signal.value === "traces"
    );
    const showTraces = computed(() => signal.value === "traces");
    async function loadMeta() {
      metaError.value = "";
      metaLoading.value = true;
      services.value = [];
      operations.value = [];
      metrics.value = [];
      try {
        const api = props.datasourceApi;
        if (!api || typeof api.getMetadata !== "function") {
          metaError.value = api ? "" : "未绑定数据源元数据 API";
          return;
        }
        const [svcRes, metricRes] = await Promise.all([
          api.getMetadata({ type: "services" }).catch((e) => {
            throw e;
          }),
          showMetrics.value ? api.getMetadata({ type: "metrics" }).catch(() => ({ values: [] })) : Promise.resolve({ values: [] })
        ]);
        services.value = (svcRes?.values || []).map((v) => ({
          label: String(typeof v === "string" ? v : v.text || v.value || v),
          value: String(typeof v === "string" ? v : v.value || v.text || v)
        }));
        metrics.value = (metricRes?.values || []).map((m) => ({
          label: String(m.metricName || m),
          value: String(m.metricName || m),
          type: m.type || m.metricType || m.temporality || void 0
        }));
        if (props.spec.service) {
          try {
            const opRes = await api.getMetadata({
              type: "operations",
              service: props.spec.service
            });
            operations.value = (opRes?.values || []).map((v) => ({
              label: v,
              value: v
            }));
          } catch {
            operations.value = [];
          }
        }
      } catch (e) {
        const msg = e instanceof Error ? e.message : String(e);
        metaError.value = msg.includes("UNSUPPORTED_CAPABILITY") ? msg : `元数据加载失败: ${msg}`;
        services.value = [];
        operations.value = [];
        metrics.value = [];
      } finally {
        metaLoading.value = false;
      }
    }
    onMounted(() => void loadMeta());
    watch(
      () => [props.datasourceApi, props.spec.signal, props.spec.service],
      () => void loadMeta()
    );
    function filterMetricOption(input, option) {
      const q = String(input || "").toLowerCase();
      if (!q) return true;
      const label = String(option?.label ?? option?.value ?? "").toLowerCase();
      return label.includes(q);
    }
    function onMetricDropdown(visible) {
      if (visible && !metrics.value.length) void loadMeta();
    }
    function onMetricSelect(v) {
      metric.value = v == null ? "" : String(v);
    }
    function onFilterRun(_v) {
      emit("run");
    }
    const tid = (base) => props.isPrimary ? base : `${base}-${props.spec.name}`;
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$c, [
        metaError.value ? (openBlock(), createElementBlock(
          "div",
          _hoisted_2$a,
          toDisplayString(metaError.value),
          1
          /* TEXT */
        )) : createCommentVNode("v-if", true),
        metaLoading.value ? (openBlock(), createElementBlock("div", _hoisted_3$9, " 加载元数据… ")) : createCommentVNode("v-if", true),
        createCommentVNode(" FILTER row — 1:1 argus-web QueryBuilder "),
        createElementVNode("div", _hoisted_4$7, [
          showMetrics.value ? (openBlock(), createBlock(unref(Select), {
            key: 0,
            value: metric.value || void 0,
            "show-search": "",
            "allow-clear": "",
            options: metricSelectOptions.value,
            "filter-option": filterMetricOption,
            loading: metaLoading.value,
            "option-filter-prop": "label",
            "option-label-prop": "label",
            placeholder: "选择指标",
            class: "qb-sel-metric",
            "data-testid": tid("signoz-metric"),
            "popup-class-name": "qb-metric-dropdown",
            onDropdownVisibleChange: onMetricDropdown,
            "onUpdate:value": onMetricSelect
          }, {
            option: withCtx(({ label, type }) => [
              createElementVNode("div", _hoisted_5$7, [
                createElementVNode(
                  "span",
                  _hoisted_6$6,
                  toDisplayString(label),
                  1
                  /* TEXT */
                ),
                type ? (openBlock(), createElementBlock(
                  "span",
                  _hoisted_7$4,
                  toDisplayString(type),
                  1
                  /* TEXT */
                )) : createCommentVNode("v-if", true)
              ])
            ]),
            _: 1
            /* STABLE */
          }, 8, ["value", "options", "loading", "data-testid"])) : createCommentVNode("v-if", true),
          createVNode(FilterExpressionEditor, {
            "model-value": filter2.value,
            signal: __props.spec.signal,
            "metric-name": metric.value || void 0,
            "datasource-api": __props.datasourceApi,
            "test-id": tid("signoz-filter"),
            class: "qb-lqs",
            "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => filter2.value = $event),
            onRun: onFilterRun
          }, null, 8, ["model-value", "signal", "metric-name", "datasource-api", "test-id"])
        ]),
        createCommentVNode(" AGG row "),
        createElementVNode("div", _hoisted_8$2, [
          showMetrics.value ? (openBlock(), createBlock(MetricAggregationFields, {
            key: 0,
            "metric-type": metricType.value,
            "time-aggregation": aggregation.value || "",
            "space-aggregation": __props.spec.aggregations?.[0]?.spaceAggregation || "",
            "step-interval": __props.spec.stepInterval,
            "test-id-prefix": __props.isPrimary ? void 0 : __props.spec.name,
            "onUpdate:metricType": _cache[1] || (_cache[1] = ($event) => metricType.value = $event),
            "onUpdate:timeAggregation": _cache[2] || (_cache[2] = ($event) => aggregation.value = $event),
            "onUpdate:spaceAggregation": _cache[3] || (_cache[3] = ($event) => setSpaceAgg($event)),
            "onUpdate:stepInterval": _cache[4] || (_cache[4] = ($event) => patch({ stepInterval: $event }))
          }, null, 8, ["metric-type", "time-aggregation", "space-aggregation", "step-interval", "test-id-prefix"])) : (openBlock(), createElementBlock(
            Fragment,
            { key: 1 },
            [
              createVNode(ExpressionAggregationEditor, {
                aggregations: __props.spec.aggregations || [],
                signal: __props.spec.signal,
                "datasource-api": __props.datasourceApi,
                multi: "",
                class: "qb-flex",
                "onUpdate:aggregations": _cache[5] || (_cache[5] = ($event) => patch({ aggregations: $event }))
              }, null, 8, ["aggregations", "signal", "datasource-api"]),
              createElementVNode("span", {
                class: "sr-only",
                "data-testid": tid("signoz-aggregation")
              }, null, 8, _hoisted_9$1),
              showLogsTraces.value ? (openBlock(), createBlock(unref(GInput), {
                key: 0,
                modelValue: source.value,
                "onUpdate:modelValue": _cache[6] || (_cache[6] = ($event) => source.value = $event),
                class: "qb-source",
                "test-id": tid("signoz-source"),
                placeholder: "source"
              }, null, 8, ["modelValue", "test-id"])) : createCommentVNode("v-if", true)
            ],
            64
            /* STABLE_FRAGMENT */
          ))
        ]),
        createCommentVNode(" Add-ons content "),
        activeAddons.value.length ? (openBlock(), createElementBlock("div", _hoisted_10$1, [
          addonOn("group_by") ? (openBlock(), createElementBlock("div", _hoisted_11$1, [
            _cache[28] || (_cache[28] = createElementVNode(
              "span",
              { class: "qb-label" },
              "Group By",
              -1
              /* CACHED */
            )),
            createVNode(GroupByFieldSelect, {
              "model-value": __props.spec.groupBy || [],
              signal: __props.spec.signal,
              "metric-name": metric.value,
              "datasource-api": __props.datasourceApi,
              class: "qb-flex",
              "onUpdate:modelValue": _cache[7] || (_cache[7] = ($event) => patch({ groupBy: $event }))
            }, null, 8, ["model-value", "signal", "metric-name", "datasource-api"])
          ])) : createCommentVNode("v-if", true),
          addonOn("having") ? (openBlock(), createElementBlock("div", _hoisted_12$1, [
            _cache[29] || (_cache[29] = createElementVNode(
              "span",
              { class: "qb-label" },
              "Having",
              -1
              /* CACHED */
            )),
            createVNode(unref(GInput), {
              modelValue: having.value,
              "onUpdate:modelValue": _cache[8] || (_cache[8] = ($event) => having.value = $event),
              class: "qb-flex",
              "test-id": tid("signoz-having"),
              placeholder: "avg >= 1"
            }, null, 8, ["modelValue", "test-id"])
          ])) : createCommentVNode("v-if", true),
          addonOn("limit") ? (openBlock(), createElementBlock("div", _hoisted_13$1, [
            _cache[30] || (_cache[30] = createElementVNode(
              "span",
              { class: "qb-label" },
              "Limit",
              -1
              /* CACHED */
            )),
            createVNode(unref(GInput), {
              modelValue: limit.value,
              "onUpdate:modelValue": _cache[9] || (_cache[9] = ($event) => limit.value = $event),
              class: "qb-flex",
              "test-id": tid("signoz-limit"),
              placeholder: "100"
            }, null, 8, ["modelValue", "test-id"])
          ])) : createCommentVNode("v-if", true),
          addonOn("order_by") ? (openBlock(), createElementBlock("div", _hoisted_14$1, [
            _cache[31] || (_cache[31] = createElementVNode(
              "span",
              { class: "qb-label" },
              "Order By",
              -1
              /* CACHED */
            )),
            createVNode(unref(GInput), {
              modelValue: order.value,
              "onUpdate:modelValue": _cache[10] || (_cache[10] = ($event) => order.value = $event),
              class: "qb-flex",
              "test-id": tid("signoz-order"),
              placeholder: "value 或 -value"
            }, null, 8, ["modelValue", "test-id"])
          ])) : createCommentVNode("v-if", true),
          addonOn("legend_format") ? (openBlock(), createElementBlock("div", _hoisted_15$1, [
            _cache[32] || (_cache[32] = createElementVNode(
              "span",
              { class: "qb-label" },
              "Legend",
              -1
              /* CACHED */
            )),
            createVNode(unref(GInput), {
              modelValue: legend.value,
              "onUpdate:modelValue": _cache[11] || (_cache[11] = ($event) => legend.value = $event),
              class: "qb-flex",
              "test-id": tid("signoz-legend"),
              placeholder: "{{service.name}}"
            }, null, 8, ["modelValue", "test-id"])
          ])) : createCommentVNode("v-if", true),
          addonOn("functions") ? (openBlock(), createElementBlock("div", _hoisted_16$1, [
            _cache[33] || (_cache[33] = createElementVNode(
              "span",
              { class: "qb-label" },
              "Functions",
              -1
              /* CACHED */
            )),
            createVNode(FunctionEditor, {
              "model-value": __props.spec.functions || [],
              "test-id": tid("signoz-functions"),
              "onUpdate:modelValue": _cache[12] || (_cache[12] = ($event) => patch({ functions: $event }))
            }, null, 8, ["model-value", "test-id"]),
            unsupportedFns.value.length ? (openBlock(), createElementBlock(
              "span",
              _hoisted_17$1,
              "不支持: " + toDisplayString(unsupportedFns.value.join(", ")),
              1
              /* TEXT */
            )) : createCommentVNode("v-if", true)
          ])) : createCommentVNode("v-if", true),
          addonOn("service") ? (openBlock(), createElementBlock("div", _hoisted_18$1, [
            _cache[34] || (_cache[34] = createElementVNode(
              "span",
              { class: "qb-label" },
              "Service",
              -1
              /* CACHED */
            )),
            createVNode(unref(GSelect), {
              value: service.value || void 0,
              options: services.value,
              "allow-clear": "",
              "test-id": tid("signoz-service"),
              class: "qb-flex",
              "onUpdate:value": _cache[13] || (_cache[13] = ($event) => service.value = String($event || ""))
            }, null, 8, ["value", "options", "test-id"])
          ])) : createCommentVNode("v-if", true),
          addonOn("service") ? (openBlock(), createElementBlock("div", _hoisted_19$1, [
            _cache[35] || (_cache[35] = createElementVNode(
              "span",
              { class: "qb-label" },
              "Operation",
              -1
              /* CACHED */
            )),
            operations.value.length ? (openBlock(), createBlock(unref(GSelect), {
              key: 0,
              value: operation.value || void 0,
              options: operations.value,
              "allow-clear": "",
              "test-id": tid("signoz-operation"),
              class: "qb-flex",
              "onUpdate:value": _cache[14] || (_cache[14] = ($event) => operation.value = String($event || ""))
            }, null, 8, ["value", "options", "test-id"])) : (openBlock(), createBlock(unref(GInput), {
              key: 1,
              modelValue: operation.value,
              "onUpdate:modelValue": _cache[15] || (_cache[15] = ($event) => operation.value = $event),
              class: "qb-flex",
              "test-id": tid("signoz-operation")
            }, null, 8, ["modelValue", "test-id"]))
          ])) : createCommentVNode("v-if", true),
          addonOn("more") ? (openBlock(), createElementBlock("div", _hoisted_20$1, [
            createElementVNode("div", _hoisted_21, [
              _cache[36] || (_cache[36] = createElementVNode(
                "span",
                { class: "qb-label" },
                "Environment",
                -1
                /* CACHED */
              )),
              createVNode(unref(GInput), {
                modelValue: environment.value,
                "onUpdate:modelValue": _cache[16] || (_cache[16] = ($event) => environment.value = $event),
                "test-id": tid("signoz-environment"),
                class: "qb-flex"
              }, null, 8, ["modelValue", "test-id"])
            ]),
            createElementVNode("div", _hoisted_22, [
              _cache[37] || (_cache[37] = createElementVNode(
                "span",
                { class: "qb-label" },
                "Tags",
                -1
                /* CACHED */
              )),
              createVNode(unref(GInput), {
                modelValue: tags.value,
                "onUpdate:modelValue": _cache[17] || (_cache[17] = ($event) => tags.value = $event),
                "test-id": tid("signoz-tags"),
                class: "qb-flex",
                placeholder: "k=v,k2=v2"
              }, null, 8, ["modelValue", "test-id"])
            ]),
            showTraces.value ? (openBlock(), createElementBlock("div", _hoisted_23, [
              _cache[38] || (_cache[38] = createElementVNode(
                "span",
                { class: "qb-label" },
                "Min duration",
                -1
                /* CACHED */
              )),
              createVNode(unref(GInput), {
                modelValue: minDuration.value,
                "onUpdate:modelValue": _cache[18] || (_cache[18] = ($event) => minDuration.value = $event),
                "test-id": tid("signoz-min-duration"),
                class: "qb-flex"
              }, null, 8, ["modelValue", "test-id"])
            ])) : createCommentVNode("v-if", true),
            showTraces.value ? (openBlock(), createElementBlock("div", _hoisted_24, [
              _cache[39] || (_cache[39] = createElementVNode(
                "span",
                { class: "qb-label" },
                "Max duration",
                -1
                /* CACHED */
              )),
              createVNode(unref(GInput), {
                modelValue: maxDuration.value,
                "onUpdate:modelValue": _cache[19] || (_cache[19] = ($event) => maxDuration.value = $event),
                "test-id": tid("signoz-max-duration"),
                class: "qb-flex"
              }, null, 8, ["modelValue", "test-id"])
            ])) : createCommentVNode("v-if", true),
            showMetrics.value ? (openBlock(), createElementBlock("div", _hoisted_25, [
              _cache[40] || (_cache[40] = createElementVNode(
                "span",
                { class: "qb-label" },
                "Secondary agg",
                -1
                /* CACHED */
              )),
              createVNode(unref(GInput), {
                modelValue: secondaryAgg.value,
                "onUpdate:modelValue": _cache[20] || (_cache[20] = ($event) => secondaryAgg.value = $event),
                "test-id": tid("signoz-secondary-agg"),
                class: "qb-flex"
              }, null, 8, ["modelValue", "test-id"])
            ])) : createCommentVNode("v-if", true),
            showMetrics.value ? (openBlock(), createElementBlock("div", _hoisted_26, [
              _cache[41] || (_cache[41] = createElementVNode(
                "span",
                { class: "qb-label" },
                "Sec. step",
                -1
                /* CACHED */
              )),
              createVNode(unref(GInput), {
                "model-value": __props.spec.secondaryAggregations?.[0]?.stepInterval != null ? String(__props.spec.secondaryAggregations?.[0]?.stepInterval) : "",
                "test-id": tid("signoz-secondary-step"),
                class: "qb-flex",
                "onUpdate:modelValue": _cache[21] || (_cache[21] = ($event) => setSecondaryMeta("stepInterval", $event))
              }, null, 8, ["model-value", "test-id"])
            ])) : createCommentVNode("v-if", true),
            showMetrics.value ? (openBlock(), createElementBlock("div", _hoisted_27, [
              _cache[42] || (_cache[42] = createElementVNode(
                "span",
                { class: "qb-label" },
                "Sec. alias",
                -1
                /* CACHED */
              )),
              createVNode(unref(GInput), {
                "model-value": String(__props.spec.secondaryAggregations?.[0]?.alias || ""),
                "test-id": tid("signoz-secondary-alias"),
                class: "qb-flex",
                "onUpdate:modelValue": _cache[22] || (_cache[22] = ($event) => setSecondaryMeta("alias", $event))
              }, null, 8, ["model-value", "test-id"])
            ])) : createCommentVNode("v-if", true),
            showLogsTraces.value ? (openBlock(), createElementBlock("div", _hoisted_28, [
              _cache[43] || (_cache[43] = createElementVNode(
                "span",
                { class: "qb-label" },
                "Cursor",
                -1
                /* CACHED */
              )),
              createVNode(unref(GInput), {
                "model-value": __props.spec.cursor || "",
                "test-id": tid("signoz-cursor"),
                class: "qb-flex",
                "onUpdate:modelValue": _cache[23] || (_cache[23] = ($event) => patch({ cursor: String($event || "") || void 0 }))
              }, null, 8, ["model-value", "test-id"])
            ])) : createCommentVNode("v-if", true),
            showLogsTraces.value ? (openBlock(), createElementBlock("div", _hoisted_29, [
              _cache[44] || (_cache[44] = createElementVNode(
                "span",
                { class: "qb-label" },
                "Offset",
                -1
                /* CACHED */
              )),
              createVNode(unref(GInput), {
                "model-value": __props.spec.offset != null ? String(__props.spec.offset) : "",
                "test-id": tid("signoz-offset-page"),
                class: "qb-flex",
                "onUpdate:modelValue": _cache[24] || (_cache[24] = ($event) => patch({
                  offset: String($event) === "" ? void 0 : Number($event)
                }))
              }, null, 8, ["model-value", "test-id"])
            ])) : createCommentVNode("v-if", true),
            createElementVNode("div", _hoisted_30, [
              _cache[45] || (_cache[45] = createElementVNode(
                "span",
                { class: "qb-label" },
                "Select",
                -1
                /* CACHED */
              )),
              createVNode(unref(GInput), {
                modelValue: selectFieldsText.value,
                "onUpdate:modelValue": _cache[25] || (_cache[25] = ($event) => selectFieldsText.value = $event),
                "test-id": tid("signoz-select-fields"),
                class: "qb-flex",
                placeholder: "field.a,field.b"
              }, null, 8, ["modelValue", "test-id"])
            ]),
            createElementVNode("div", _hoisted_31, [
              _cache[46] || (_cache[46] = createElementVNode(
                "span",
                { class: "qb-label" },
                "Limit by",
                -1
                /* CACHED */
              )),
              createVNode(unref(GInput), {
                modelValue: limitByText.value,
                "onUpdate:modelValue": _cache[26] || (_cache[26] = ($event) => limitByText.value = $event),
                "test-id": tid("signoz-limit-by"),
                class: "qb-flex",
                placeholder: "key1,key2"
              }, null, 8, ["modelValue", "test-id"]),
              createVNode(unref(GInput), {
                modelValue: limitByValue.value,
                "onUpdate:modelValue": _cache[27] || (_cache[27] = ($event) => limitByValue.value = $event),
                "test-id": tid("signoz-limit-by-value"),
                style: { "width": "64px" },
                placeholder: "N"
              }, null, 8, ["modelValue", "test-id"])
            ])
          ])) : createCommentVNode("v-if", true)
        ])) : createCommentVNode("v-if", true),
        createCommentVNode(" always-available anchors for test matrix when advanced fields not opened "),
        createElementVNode("div", _hoisted_32, [
          !addonOn("having") ? (openBlock(), createElementBlock("span", {
            key: 0,
            "data-testid": tid("signoz-having")
          }, null, 8, _hoisted_33)) : createCommentVNode("v-if", true),
          !addonOn("limit") ? (openBlock(), createElementBlock("span", {
            key: 1,
            "data-testid": tid("signoz-limit")
          }, null, 8, _hoisted_34)) : createCommentVNode("v-if", true),
          !addonOn("order_by") ? (openBlock(), createElementBlock("span", {
            key: 2,
            "data-testid": tid("signoz-order")
          }, null, 8, _hoisted_35)) : createCommentVNode("v-if", true),
          !addonOn("legend_format") ? (openBlock(), createElementBlock("span", {
            key: 3,
            "data-testid": tid("signoz-legend")
          }, null, 8, _hoisted_36)) : createCommentVNode("v-if", true),
          !addonOn("functions") ? (openBlock(), createElementBlock("span", {
            key: 4,
            "data-testid": tid("signoz-functions")
          }, null, 8, _hoisted_37)) : createCommentVNode("v-if", true),
          !addonOn("service") ? (openBlock(), createElementBlock("span", {
            key: 5,
            "data-testid": tid("signoz-service")
          }, null, 8, _hoisted_38)) : createCommentVNode("v-if", true),
          !addonOn("service") ? (openBlock(), createElementBlock("span", {
            key: 6,
            "data-testid": tid("signoz-operation")
          }, null, 8, _hoisted_39)) : createCommentVNode("v-if", true),
          !addonOn("group_by") ? (openBlock(), createElementBlock("span", _hoisted_40)) : createCommentVNode("v-if", true),
          !addonOn("more") ? (openBlock(), createElementBlock("span", {
            key: 8,
            "data-testid": tid("signoz-tags")
          }, null, 8, _hoisted_41)) : createCommentVNode("v-if", true),
          !addonOn("more") ? (openBlock(), createElementBlock("span", {
            key: 9,
            "data-testid": tid("signoz-environment")
          }, null, 8, _hoisted_42)) : createCommentVNode("v-if", true),
          !addonOn("more") && showTraces.value ? (openBlock(), createElementBlock("span", {
            key: 10,
            "data-testid": tid("signoz-min-duration")
          }, null, 8, _hoisted_43)) : createCommentVNode("v-if", true),
          !addonOn("more") && showTraces.value ? (openBlock(), createElementBlock("span", {
            key: 11,
            "data-testid": tid("signoz-max-duration")
          }, null, 8, _hoisted_44)) : createCommentVNode("v-if", true),
          !addonOn("more") ? (openBlock(), createElementBlock("span", {
            key: 12,
            "data-testid": tid("signoz-select-fields")
          }, null, 8, _hoisted_45)) : createCommentVNode("v-if", true),
          !addonOn("more") ? (openBlock(), createElementBlock("span", {
            key: 13,
            "data-testid": tid("signoz-limit-by")
          }, null, 8, _hoisted_46)) : createCommentVNode("v-if", true),
          !addonOn("more") ? (openBlock(), createElementBlock("span", {
            key: 14,
            "data-testid": tid("signoz-limit-by-value")
          }, null, 8, _hoisted_47)) : createCommentVNode("v-if", true),
          !addonOn("more") && showMetrics.value ? (openBlock(), createElementBlock("span", {
            key: 15,
            "data-testid": tid("signoz-secondary-agg")
          }, null, 8, _hoisted_48)) : createCommentVNode("v-if", true),
          !addonOn("more") && showMetrics.value ? (openBlock(), createElementBlock("span", {
            key: 16,
            "data-testid": tid("signoz-secondary-step")
          }, null, 8, _hoisted_49)) : createCommentVNode("v-if", true),
          !addonOn("more") && showMetrics.value ? (openBlock(), createElementBlock("span", {
            key: 17,
            "data-testid": tid("signoz-secondary-alias")
          }, null, 8, _hoisted_50)) : createCommentVNode("v-if", true),
          !addonOn("more") && showLogsTraces.value ? (openBlock(), createElementBlock("span", {
            key: 18,
            "data-testid": tid("signoz-cursor")
          }, null, 8, _hoisted_51)) : createCommentVNode("v-if", true),
          !addonOn("more") && showLogsTraces.value ? (openBlock(), createElementBlock("span", {
            key: 19,
            "data-testid": tid("signoz-offset-page")
          }, null, 8, _hoisted_52)) : createCommentVNode("v-if", true)
        ]),
        createCommentVNode(" AddOns toggle bar "),
        createVNode(QueryAddons, {
          active: activeAddons.value,
          onToggle: toggleAddon
        }, null, 8, ["active"])
      ]);
    };
  }
});
const SignalBuilderForm = /* @__PURE__ */ _export_sfc(_sfc_main$d, [["__scopeId", "data-v-96356868"]]);
const _hoisted_1$b = ["data-signal-kind"];
const _sfc_main$c = /* @__PURE__ */ defineComponent({
  __name: "BuilderFields",
  props: {
    spec: {},
    isPrimary: { type: Boolean },
    datasourceApi: {},
    capabilities: {}
  },
  emits: ["update:spec", "run"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const signalKind = computed(
      () => props.spec.signal === "metrics" ? "metrics" : "non-metrics"
    );
    function onUpdate(spec) {
      emit("update:spec", spec);
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", {
        class: "signoz-builder-fields",
        "data-testid": "signoz-builder-fields",
        "data-signal-kind": signalKind.value
      }, [
        createCommentVNode(" metrics: MetricAggregationFields / metric meta path "),
        signalKind.value === "metrics" ? (openBlock(), createBlock(SignalBuilderForm, {
          key: 0,
          spec: __props.spec,
          "is-primary": __props.isPrimary,
          "datasource-api": __props.datasourceApi,
          capabilities: __props.capabilities,
          "onUpdate:spec": onUpdate,
          onRun: _cache[0] || (_cache[0] = ($event) => emit("run"))
        }, null, 8, ["spec", "is-primary", "datasource-api", "capabilities"])) : (openBlock(), createElementBlock(
          Fragment,
          { key: 1 },
          [
            createCommentVNode(" logs | traces | other: ExpressionAggregationEditor / filter path "),
            createVNode(SignalBuilderForm, {
              spec: __props.spec,
              "is-primary": __props.isPrimary,
              "datasource-api": __props.datasourceApi,
              capabilities: __props.capabilities,
              "onUpdate:spec": onUpdate,
              onRun: _cache[1] || (_cache[1] = ($event) => emit("run"))
            }, null, 8, ["spec", "is-primary", "datasource-api", "capabilities"])
          ],
          2112
          /* STABLE_FRAGMENT, DEV_ROOT_FRAGMENT */
        ))
      ], 8, _hoisted_1$b);
    };
  }
});
const BuilderFields = /* @__PURE__ */ _export_sfc(_sfc_main$c, [["__scopeId", "data-v-af9483d6"]]);
function labelKey(labels) {
  if (!labels || !Object.keys(labels).length) return "";
  const entries = Object.entries(labels).filter(([k]) => k !== "__name__").sort(([a], [b]) => a.localeCompare(b));
  return JSON.stringify(Object.fromEntries(entries));
}
function fieldLabels(field) {
  const raw = field?.labels;
  if (!raw || typeof raw !== "object") return {};
  const out = {};
  for (const [k, v] of Object.entries(raw)) {
    if (k === "__name__") continue;
    out[k] = String(v);
  }
  return out;
}
function frameMetaLabels(frame) {
  const metaLabels = frame.meta?.custom?.labels || frame.meta?.labels;
  if (metaLabels && typeof metaLabels === "object" && !Array.isArray(metaLabels)) {
    const out = {};
    for (const [k, v] of Object.entries(metaLabels)) {
      if (k === "__name__") continue;
      out[k] = String(v);
    }
    return out;
  }
  return {};
}
function seriesFromFrames(input) {
  if (!input) return [];
  const frames = Array.isArray(input) ? input : [input];
  const series = [];
  for (const fr of frames) {
    const times = fr.fields.find((f) => f.type === "time" || f.name === "Time")?.values || [];
    const valueFields = fr.fields.filter(
      (f) => f.type === "number" || f.name !== "Time" && f.type !== "time" && f.type !== "string"
    );
    if (!valueFields.length) continue;
    for (const vf of valueFields) {
      const labels = { ...frameMetaLabels(fr), ...fieldLabels(vf) };
      series.push({
        labels,
        times,
        values: vf.values || []
      });
    }
  }
  return series;
}
function emptyErrorFrame(name, text, code = "FORMULA_ERROR") {
  return createDataFrame({
    refId: name,
    name,
    fields: [
      { name: "Time", type: "time", values: [] },
      { name: "Value", type: "number", values: [] }
    ],
    meta: {
      notices: [{ severity: "error", text: `[${code}] ${text}` }],
      custom: { formulaError: code }
    }
  });
}
function evaluateLocalFormula(expression, framesByName, name) {
  const deps = expression.match(/\b[A-Z][A-Z0-9_]*\b/g) ?? [];
  const uniqueDeps = Array.from(new Set(deps));
  for (const d of uniqueDeps) {
    if (!framesByName.has(d)) {
      return emptyErrorFrame(
        name,
        `公式 ${name} 依赖 ${d} 失败`,
        "FORMULA_MISSING_DEP"
      );
    }
  }
  const byDep = /* @__PURE__ */ new Map();
  let multi = false;
  const firstKeys = [];
  for (const d of uniqueDeps) {
    const series = seriesFromFrames(framesByName.get(d));
    if (!series.length) {
      return emptyErrorFrame(
        name,
        `公式 ${name} 依赖 ${d} 无序列`,
        "FORMULA_EMPTY_SERIES"
      );
    }
    if (series.length > 1) multi = true;
    const keys = series.map((s) => labelKey(s.labels));
    if (!firstKeys.length) firstKeys.push(...keys);
    else if (keys.join("|") !== firstKeys.join("|")) multi = true;
    if (series.some((s) => Object.keys(s.labels).length) && series.length > 1)
      multi = true;
    byDep.set(d, series);
  }
  const allSingle = uniqueDeps.every((d) => (byDep.get(d) || []).length === 1);
  const singleKeys = uniqueDeps.map(
    (d) => labelKey((byDep.get(d) || [])[0]?.labels)
  );
  const sameOrEmpty = new Set(singleKeys).size <= 1;
  if (allSingle && sameOrEmpty && !multi) {
    return evaluateSingleSeries(expression, uniqueDeps, byDep, name);
  }
  if (allSingle && !sameOrEmpty) {
    return emptyErrorFrame(
      name,
      "公式依赖的序列标签不一致，无法配对",
      "FORMULA_LABEL_MISMATCH"
    );
  }
  const keySets = uniqueDeps.map(
    (d) => new Set((byDep.get(d) || []).map((s) => labelKey(s.labels)))
  );
  let intersection = new Set(keySets[0] || []);
  for (let i = 1; i < keySets.length; i++) {
    intersection = new Set([...intersection].filter((k) => keySets[i].has(k)));
  }
  const union = /* @__PURE__ */ new Set();
  for (const s of keySets) for (const k of s) union.add(k);
  const missing = [];
  for (const k of union) {
    if (!intersection.has(k)) missing.push(k || "(empty)");
  }
  if (!intersection.size) {
    return emptyErrorFrame(
      name,
      "公式依赖的序列标签不一致，无法配对",
      "FORMULA_LABEL_MISMATCH"
    );
  }
  const firstDep = uniqueDeps[0];
  const firstSeries = byDep.get(firstDep) || [];
  const matched = [...intersection].sort();
  const fields = [];
  let times = [];
  const notices = [];
  if (missing.length) {
    notices.push({
      severity: "error",
      text: `[FORMULA_LABEL_MISMATCH] 部分标签未在全部依赖中出现: ${missing.slice(0, 5).join(", ")}`
    });
  }
  for (const key of matched) {
    const envSeries = {};
    for (const d of uniqueDeps) {
      const hit = (byDep.get(d) || []).find((s) => labelKey(s.labels) === key);
      if (!hit) {
        return emptyErrorFrame(
          name,
          `标签 ${key || "(empty)"} 缺少依赖 ${d}`,
          "FORMULA_LABEL_MISMATCH"
        );
      }
      envSeries[d] = hit;
    }
    const base = envSeries[firstDep];
    if (!times.length) times = base.times;
    const values = [];
    for (let i = 0; i < times.length; i++) {
      const env = {};
      let ok2 = true;
      for (const d of uniqueDeps) {
        const v = Number(envSeries[d].values[i]);
        if (!Number.isFinite(v)) {
          ok2 = false;
          break;
        }
        env[d] = v;
      }
      if (!ok2) {
        values.push(null);
        continue;
      }
      try {
        values.push(evalArithmetic(expression, env));
      } catch {
        values.push(null);
      }
    }
    const labels = firstSeries.find((s) => labelKey(s.labels) === key)?.labels || {};
    const display = Object.keys(labels).length ? Object.entries(labels).map(([k, v]) => `${k}=${v}`).join(", ") : name;
    fields.push({
      name: matched.length === 1 ? name : display,
      type: "number",
      values,
      labels,
      config: { displayNameFromDS: display }
    });
  }
  return createDataFrame({
    refId: name,
    name,
    fields: [{ name: "Time", type: "time", values: times }, ...fields],
    meta: notices.length ? { notices } : void 0
  });
}
function evaluateSingleSeries(expression, deps, byDep, name) {
  const first = (byDep.get(deps[0] || "") || [])[0];
  const times = first?.times || [];
  const values = [];
  for (let i = 0; i < times.length; i++) {
    const env = {};
    let ok2 = true;
    for (const d of deps) {
      const s = (byDep.get(d) || [])[0];
      const v = Number(s?.values[i]);
      if (!Number.isFinite(v)) {
        ok2 = false;
        break;
      }
      env[d] = v;
    }
    if (!ok2) {
      values.push(null);
      continue;
    }
    try {
      values.push(evalArithmetic(expression, env));
    } catch {
      values.push(null);
    }
  }
  const labels = first?.labels || {};
  return createDataFrame({
    refId: name,
    name,
    fields: [
      { name: "Time", type: "time", values: times },
      {
        name,
        type: "number",
        values,
        labels: Object.keys(labels).length ? labels : void 0
      }
    ]
  });
}
function evalArithmetic(expr, env) {
  const tokens = expr.match(
    /[A-Z][A-Z0-9_]*|\d+(\.\d+)?|<=|>=|==|!=|<|>|[+\-*/()]/g
  );
  if (!tokens) throw new Error("empty");
  let i = 0;
  function peek() {
    return tokens[i];
  }
  function next() {
    return tokens[i++];
  }
  function parseComparison() {
    let v2 = parseExpr();
    while (peek() === "<" || peek() === ">" || peek() === "<=" || peek() === ">=" || peek() === "==" || peek() === "!=") {
      const op = next();
      const r = parseExpr();
      let ok2 = false;
      if (op === "<") ok2 = v2 < r;
      else if (op === ">") ok2 = v2 > r;
      else if (op === "<=") ok2 = v2 <= r;
      else if (op === ">=") ok2 = v2 >= r;
      else if (op === "==") ok2 = v2 === r;
      else if (op === "!=") ok2 = v2 !== r;
      v2 = ok2 ? 1 : 0;
    }
    return v2;
  }
  function parseExpr() {
    let v2 = parseTerm();
    while (peek() === "+" || peek() === "-") {
      const op = next();
      const r = parseTerm();
      v2 = op === "+" ? v2 + r : v2 - r;
    }
    return v2;
  }
  function parseTerm() {
    let v2 = parseFactor();
    while (peek() === "*" || peek() === "/") {
      const op = next();
      const r = parseFactor();
      v2 = op === "*" ? v2 * r : v2 / r;
    }
    return v2;
  }
  function parseFactor() {
    const t = next();
    if (t === "(") {
      const v2 = parseComparison();
      if (next() !== ")") throw new Error("paren");
      return v2;
    }
    if (t === "-") return -parseFactor();
    if (/^\d/.test(t)) return Number(t);
    if (env[t] == null) throw new Error(`unknown ${t}`);
    return env[t];
  }
  const v = parseComparison();
  if (i !== tokens.length) throw new Error("trailing");
  return v;
}
function validateFormulaExpression(expression, availableNames, formulaNames = []) {
  const expr = String(expression || "").trim();
  if (!expr) return { ok: false, message: "表达式不能为空" };
  const refs = expr.match(/\b[A-Z][A-Z0-9_]*\b/g) ?? [];
  if (!refs.length) return { ok: false, message: "缺少查询引用" };
  const available = new Set(availableNames);
  for (const r of refs) {
    if (!available.has(r)) return { ok: false, message: `缺少引用 ${r}` };
  }
  const current = formulaNames.length ? formulaNames[formulaNames.length - 1] : "";
  if (current && refs.includes(current)) {
    return { ok: false, message: "循环引用" };
  }
  return { ok: true };
}
function detectFormulaCycle(formulas) {
  const map = new Map(formulas.map((f) => [f.name, f.expression]));
  const formulaSet = new Set(formulas.map((f) => f.name));
  const deps = (name) => {
    const expr = map.get(name) || "";
    return (expr.match(/\b[A-Z][A-Z0-9_]*\b/g) ?? []).filter(
      (r) => formulaSet.has(r)
    );
  };
  const visited = /* @__PURE__ */ new Set();
  const stack = /* @__PURE__ */ new Set();
  function dfs(n) {
    if (stack.has(n)) return true;
    if (visited.has(n)) return false;
    visited.add(n);
    stack.add(n);
    for (const d of deps(n)) {
      if (dfs(d)) return true;
    }
    stack.delete(n);
    return false;
  }
  for (const f of formulas) {
    if (dfs(f.name)) return f.name;
  }
  return null;
}
const _hoisted_1$a = {
  class: "formula-fields",
  "data-testid": "signoz-formula-fields"
};
const _hoisted_2$9 = { class: "row" };
const _hoisted_3$8 = {
  key: 0,
  class: "err",
  "data-testid": "signoz-formula-error",
  role: "alert"
};
const _hoisted_4$6 = { class: "row" };
const _hoisted_5$6 = { class: "row" };
const _hoisted_6$5 = { class: "row" };
const _sfc_main$b = /* @__PURE__ */ defineComponent({
  __name: "FormulaFields",
  props: {
    item: {},
    allItems: {}
  },
  emits: ["update"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const availableNames = computed(() => props.allItems.map((i) => i.spec.name));
    const formulaNames = computed(
      () => props.allItems.filter((i) => i.type === "builder_formula").map((i) => i.spec.name)
    );
    const validation = computed(() => {
      const v = validateFormulaExpression(
        props.item.spec.expression,
        availableNames.value,
        [
          ...formulaNames.value.filter((n) => n !== props.item.spec.name),
          props.item.spec.name
        ]
      );
      if (!v.ok) return v;
      const cycle = detectFormulaCycle(
        props.allItems.filter(
          (i) => i.type === "builder_formula"
        ).map(
          (i) => i.spec.name === props.item.spec.name ? { name: i.spec.name, expression: props.item.spec.expression } : { name: i.spec.name, expression: i.spec.expression }
        )
      );
      if (cycle) return { ok: false, message: `循环引用: ${cycle}` };
      return { ok: true };
    });
    function patch(partial) {
      emit("update", {
        type: "builder_formula",
        spec: { ...props.item.spec, ...partial }
      });
    }
    const orderText = computed({
      get: () => {
        const o = props.item.spec.order?.[0];
        if (!o) return "";
        return (o.direction === "desc" ? "-" : "") + o.key.name;
      },
      set: (v) => {
        const s = String(v || "");
        patch({
          order: s ? [
            {
              key: { name: s.replace(/^-/, "") },
              direction: s.startsWith("-") ? "desc" : "asc"
            }
          ] : []
        });
      }
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$a, [
        createElementVNode("div", _hoisted_2$9, [
          _cache[4] || (_cache[4] = createElementVNode(
            "label",
            null,
            "Expression",
            -1
            /* CACHED */
          )),
          createVNode(unref(GInput), {
            "model-value": __props.item.spec.expression,
            "test-id": "signoz-formula-expression",
            "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => patch({ expression: String($event) }))
          }, null, 8, ["model-value"])
        ]),
        !validation.value.ok ? (openBlock(), createElementBlock(
          "div",
          _hoisted_3$8,
          toDisplayString(validation.value.message),
          1
          /* TEXT */
        )) : createCommentVNode("v-if", true),
        createElementVNode("div", _hoisted_4$6, [
          _cache[5] || (_cache[5] = createElementVNode(
            "label",
            null,
            "Legend",
            -1
            /* CACHED */
          )),
          createVNode(unref(GInput), {
            "model-value": __props.item.spec.legend,
            "test-id": "signoz-formula-legend",
            "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => patch({ legend: String($event) }))
          }, null, 8, ["model-value"])
        ]),
        createElementVNode("div", _hoisted_5$6, [
          _cache[6] || (_cache[6] = createElementVNode(
            "label",
            null,
            "Order",
            -1
            /* CACHED */
          )),
          createVNode(unref(GInput), {
            "model-value": orderText.value,
            "test-id": "signoz-formula-order",
            placeholder: "value or -value",
            "onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => orderText.value = String($event))
          }, null, 8, ["model-value"])
        ]),
        createElementVNode("div", _hoisted_6$5, [
          _cache[7] || (_cache[7] = createElementVNode(
            "label",
            null,
            "Limit",
            -1
            /* CACHED */
          )),
          createVNode(unref(GInput), {
            "model-value": __props.item.spec.limit != null ? String(__props.item.spec.limit) : "",
            "test-id": "signoz-formula-limit",
            "onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => patch({ limit: String($event) === "" ? void 0 : Number($event) }))
          }, null, 8, ["model-value"])
        ])
      ]);
    };
  }
});
const FormulaFields = /* @__PURE__ */ _export_sfc(_sfc_main$b, [["__scopeId", "data-v-493000e4"]]);
const FORBIDDEN_SQL_START = /^(insert|update|delete|drop|alter|truncate|create|replace|grant|revoke)\b/i;
function validateRawQuery(mode2, text) {
  const raw = String(text ?? "");
  if (mode2 === "promql") {
    if (!raw.trim()) return { ok: true, diagnostics: [] };
    const r = parsePromqlToAst(raw);
    const diagnostics = (r.diagnostics || []).filter((d) => d.severity === "error").map((d) => ({
      from: d.range?.from ?? 0,
      to: d.range?.to ?? raw.length,
      message: d.message || "PromQL 语法错误"
    }));
    return { ok: diagnostics.length === 0, diagnostics };
  }
  if (mode2 === "clickhouse_sql" || mode2 === "sql") {
    return validateSql(raw);
  }
  return { ok: true, diagnostics: [] };
}
function validateSql(raw) {
  const trimmed = raw.trim();
  if (!trimmed) return { ok: true, diagnostics: [] };
  let i = 0;
  let depth = 0;
  let inSingle = false;
  let inDouble = false;
  let inLineComment = false;
  let inBlockComment = false;
  const statements = [];
  let start = 0;
  let buf = "";
  const pushStmt = (end) => {
    const t = buf.trim();
    if (t) statements.push({ from: start, text: t });
    buf = "";
    start = end + 1;
  };
  while (i < raw.length) {
    const c = raw[i];
    const n = raw[i + 1];
    if (inLineComment) {
      if (c === "\n") inLineComment = false;
      i += 1;
      continue;
    }
    if (inBlockComment) {
      if (c === "*" && n === "/") {
        inBlockComment = false;
        i += 2;
        continue;
      }
      i += 1;
      continue;
    }
    if (inSingle) {
      if (c === "\\") {
        buf += c + (n || "");
        i += 2;
        continue;
      }
      if (c === "'") {
        inSingle = false;
      }
      buf += c;
      i += 1;
      continue;
    }
    if (inDouble) {
      if (c === "\\") {
        buf += c + (n || "");
        i += 2;
        continue;
      }
      if (c === '"') {
        inDouble = false;
      }
      buf += c;
      i += 1;
      continue;
    }
    if (c === "-" && n === "-") {
      inLineComment = true;
      i += 2;
      continue;
    }
    if (c === "/" && n === "*") {
      inBlockComment = true;
      i += 2;
      continue;
    }
    if (c === "'") {
      inSingle = true;
      buf += c;
      i += 1;
      continue;
    }
    if (c === '"') {
      inDouble = true;
      buf += c;
      i += 1;
      continue;
    }
    if (c === "(") {
      depth += 1;
      buf += c;
      i += 1;
      continue;
    }
    if (c === ")") {
      depth = Math.max(0, depth - 1);
      buf += c;
      i += 1;
      continue;
    }
    if (c === ";" && depth === 0) {
      pushStmt(i);
      const rest = raw.slice(i + 1).trim();
      if (rest) {
        return {
          ok: false,
          diagnostics: [
            {
              from: i + 1,
              to: raw.length,
              message: "只允许单个 SELECT/WITH 语句"
            }
          ]
        };
      }
      i += 1;
      continue;
    }
    buf += c;
    i += 1;
  }
  if (buf.trim()) pushStmt(raw.length - 1);
  if (statements.length === 0) return { ok: true, diagnostics: [] };
  if (statements.length > 1) {
    return {
      ok: false,
      diagnostics: [
        {
          from: statements[1].from,
          to: raw.length,
          message: "只允许单个 SELECT/WITH 语句"
        }
      ]
    };
  }
  const stmt = statements[0].text;
  if (FORBIDDEN_SQL_START.test(stmt)) {
    return {
      ok: false,
      diagnostics: [
        {
          from: statements[0].from,
          to: statements[0].from + Math.min(12, stmt.length),
          message: "禁止 INSERT/UPDATE/DELETE/DROP 等写语句"
        }
      ]
    };
  }
  if (!/^(with|select)\b/i.test(stmt)) {
    return {
      ok: false,
      diagnostics: [
        {
          from: statements[0].from,
          to: statements[0].from + Math.min(12, stmt.length),
          message: "SQL 必须以 SELECT 或 WITH 开头"
        }
      ]
    };
  }
  return { ok: true, diagnostics: [] };
}
function formatRawQuery(mode2, text) {
  const raw = String(text ?? "");
  const v = validateRawQuery(mode2, raw);
  if (!v.ok) return raw;
  if (mode2 === "promql") {
    return raw.replace(/[ \t]+/g, " ").replace(/\s*\n\s*/g, "\n").trim();
  }
  if (mode2 === "clickhouse_sql" || mode2 === "sql") {
    return formatSql(raw);
  }
  return raw;
}
function formatSql(raw) {
  const clauses = [
    "SELECT",
    "FROM",
    "WHERE",
    "GROUP BY",
    "ORDER BY",
    "LIMIT",
    "HAVING",
    "WITH"
  ];
  let out = "";
  let i = 0;
  let inSingle = false;
  let inDouble = false;
  while (i < raw.length) {
    const c = raw[i];
    if (inSingle) {
      out += c;
      if (c === "'" && raw[i - 1] !== "\\") inSingle = false;
      i += 1;
      continue;
    }
    if (inDouble) {
      out += c;
      if (c === '"' && raw[i - 1] !== "\\") inDouble = false;
      i += 1;
      continue;
    }
    if (c === "'") {
      inSingle = true;
      out += c;
      i += 1;
      continue;
    }
    if (c === '"') {
      inDouble = true;
      out += c;
      i += 1;
      continue;
    }
    let matched = false;
    for (const cl of clauses) {
      if (raw.slice(i, i + cl.length).toUpperCase() === cl) {
        const before = out.trimEnd();
        if (before && !before.endsWith("\n")) out = before + "\n";
        out += cl;
        i += cl.length;
        matched = true;
        break;
      }
    }
    if (matched) continue;
    if (c === " " || c === "	" || c === "\n" || c === "\r") {
      if (!out.endsWith(" ") && !out.endsWith("\n") && out.length) out += " ";
      i += 1;
      continue;
    }
    out += c;
    i += 1;
  }
  return out.trim();
}
const _hoisted_1$9 = {
  class: "raw-qe",
  "data-testid": "signoz-raw-query-editor"
};
const _hoisted_2$8 = { class: "row" };
const _hoisted_3$7 = ["id"];
const _sfc_main$a = /* @__PURE__ */ defineComponent({
  __name: "RawQueryEditor",
  props: {
    modelValue: {},
    mode: {},
    testId: {}
  },
  emits: ["update:modelValue"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const validation = computed(
      () => validateRawQuery(props.mode, props.modelValue)
    );
    const describedBy = computed(
      () => validation.value.ok ? void 0 : `${props.testId || "signoz-raw"}-diag`
    );
    const language = computed(() => {
      if (props.mode === "clickhouse_sql" || props.mode === "sql") return "sql";
      if (props.mode === "promql") return "promql";
      return "plaintext";
    });
    function format() {
      emit("update:modelValue", formatRawQuery(props.mode, props.modelValue));
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$9, [
        createElementVNode("div", _hoisted_2$8, [
          createVNode(unref(GCodeEditor), {
            value: __props.modelValue,
            language: language.value,
            height: "140",
            "test-id": __props.testId || "signoz-raw-editor",
            "onUpdate:value": _cache[0] || (_cache[0] = ($event) => emit("update:modelValue", String($event)))
          }, null, 8, ["value", "language", "test-id"]),
          createVNode(unref(GButton), {
            size: "sm",
            variant: "secondary",
            type: "button",
            "test-id": "signoz-raw-format",
            title: "格式化（仅在校验通过时生效）",
            onClick: format
          }, {
            default: withCtx(() => [..._cache[1] || (_cache[1] = [
              createTextVNode(
                " 格式化 ",
                -1
                /* CACHED */
              )
            ])]),
            _: 1
            /* STABLE */
          })
        ]),
        !validation.value.ok ? (openBlock(), createElementBlock("div", {
          key: 0,
          id: describedBy.value,
          class: "diag",
          role: "alert",
          "data-testid": "signoz-raw-diagnostics"
        }, [
          (openBlock(true), createElementBlock(
            Fragment,
            null,
            renderList(validation.value.diagnostics, (d, i) => {
              return openBlock(), createElementBlock(
                "div",
                { key: i },
                " [" + toDisplayString(d.from) + "-" + toDisplayString(d.to) + "] " + toDisplayString(d.message),
                1
                /* TEXT */
              );
            }),
            128
            /* KEYED_FRAGMENT */
          ))
        ], 8, _hoisted_3$7)) : createCommentVNode("v-if", true)
      ]);
    };
  }
});
const RawQueryEditor = /* @__PURE__ */ _export_sfc(_sfc_main$a, [["__scopeId", "data-v-fc4435e8"]]);
const _hoisted_1$8 = {
  class: "trace-op",
  "data-testid": "signoz-trace-operator-fields"
};
const _hoisted_2$7 = { class: "row" };
const _hoisted_3$6 = { class: "row" };
const _hoisted_4$5 = { class: "row" };
const _hoisted_5$5 = { class: "row" };
const _hoisted_6$4 = { class: "row" };
const _hoisted_7$3 = { class: "row" };
const _hoisted_8$1 = { class: "row" };
const _sfc_main$9 = /* @__PURE__ */ defineComponent({
  __name: "TraceOperatorFields",
  props: {
    item: {}
  },
  emits: ["update"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    function patch(partial) {
      emit("update", {
        type: "builder_trace_operator",
        spec: { ...props.item.spec, ...partial }
      });
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$8, [
        createElementVNode("div", _hoisted_2$7, [
          _cache[7] || (_cache[7] = createElementVNode(
            "label",
            null,
            "Expression",
            -1
            /* CACHED */
          )),
          createVNode(unref(GInput), {
            "model-value": __props.item.spec.expression,
            placeholder: "A => B",
            "test-id": "signoz-trace-op-expression",
            "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => patch({ expression: String($event) }))
          }, null, 8, ["model-value"])
        ]),
        createElementVNode("div", _hoisted_3$6, [
          _cache[8] || (_cache[8] = createElementVNode(
            "label",
            null,
            "Return spans",
            -1
            /* CACHED */
          )),
          createVNode(unref(GSelect), {
            value: __props.item.spec.returnSpansFrom || "all",
            options: [
              { label: "all", value: "all" },
              { label: "root", value: "root" },
              { label: "leaves", value: "leaves" },
              { label: "matched", value: "matched" }
            ],
            "test-id": "signoz-trace-op-return",
            "onUpdate:value": _cache[1] || (_cache[1] = ($event) => patch({ returnSpansFrom: String($event) }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_4$5, [
          _cache[9] || (_cache[9] = createElementVNode(
            "label",
            null,
            "Filter",
            -1
            /* CACHED */
          )),
          createVNode(unref(GInput), {
            "model-value": __props.item.spec.filter?.expression || "",
            placeholder: "hasError = true",
            "test-id": "signoz-trace-op-filter",
            "onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => patch({ filter: { expression: String($event) } }))
          }, null, 8, ["model-value"])
        ]),
        createElementVNode("div", _hoisted_5$5, [
          _cache[10] || (_cache[10] = createElementVNode(
            "label",
            null,
            "Group by",
            -1
            /* CACHED */
          )),
          createVNode(unref(GInput), {
            "model-value": (__props.item.spec.groupBy || []).map((f) => f.name || f).join(","),
            placeholder: "service.name,name",
            "test-id": "signoz-trace-op-groupby",
            "onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => patch({
              groupBy: String($event || "").split(",").map((s) => s.trim()).filter(Boolean).map((name) => ({
                name,
                fieldDataType: "string",
                fieldContext: "tag"
              }))
            }))
          }, null, 8, ["model-value"])
        ]),
        createElementVNode("div", _hoisted_6$4, [
          _cache[11] || (_cache[11] = createElementVNode(
            "label",
            null,
            "Having",
            -1
            /* CACHED */
          )),
          createVNode(unref(GInput), {
            "model-value": __props.item.spec.having?.expression || "",
            placeholder: "count() > 1",
            "test-id": "signoz-trace-op-having",
            "onUpdate:modelValue": _cache[4] || (_cache[4] = ($event) => patch({ having: { expression: String($event) } }))
          }, null, 8, ["model-value"])
        ]),
        createElementVNode("div", _hoisted_7$3, [
          _cache[12] || (_cache[12] = createElementVNode(
            "label",
            null,
            "Aggregations",
            -1
            /* CACHED */
          )),
          createVNode(unref(GInput), {
            "model-value": (__props.item.spec.aggregations || []).map((a) => a.expression || a.timeAggregation || "").join(";"),
            placeholder: "count(); p95(durationNano)",
            "test-id": "signoz-trace-op-aggs",
            "onUpdate:modelValue": _cache[5] || (_cache[5] = ($event) => {
              patch({
                aggregations: String($event || "").split(";").map((s) => s.trim()).filter(Boolean).map((expression) => ({ expression }))
              });
            })
          }, null, 8, ["model-value"])
        ]),
        createElementVNode("div", _hoisted_8$1, [
          _cache[13] || (_cache[13] = createElementVNode(
            "label",
            null,
            "Legend",
            -1
            /* CACHED */
          )),
          createVNode(unref(GInput), {
            "model-value": __props.item.spec.legend || "",
            "test-id": "signoz-trace-op-legend",
            "onUpdate:modelValue": _cache[6] || (_cache[6] = ($event) => patch({ legend: String($event) }))
          }, null, 8, ["model-value"])
        ])
      ]);
    };
  }
});
const TraceOperatorFields = /* @__PURE__ */ _export_sfc(_sfc_main$9, [["__scopeId", "data-v-f0fb0a41"]]);
const _hoisted_1$7 = {
  class: "join",
  "data-testid": "signoz-join-fields"
};
const _hoisted_2$6 = { class: "row" };
const _hoisted_3$5 = { class: "row" };
const _hoisted_4$4 = { class: "row" };
const _hoisted_5$4 = { class: "row" };
const _hoisted_6$3 = { class: "row" };
const _sfc_main$8 = /* @__PURE__ */ defineComponent({
  __name: "JoinFields",
  props: {
    item: {}
  },
  emits: ["update"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    function patch(partial) {
      emit("update", {
        type: "builder_join",
        spec: { ...props.item.spec, ...partial }
      });
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$7, [
        createElementVNode("div", _hoisted_2$6, [
          _cache[5] || (_cache[5] = createElementVNode(
            "label",
            null,
            "Left",
            -1
            /* CACHED */
          )),
          createVNode(unref(GInput), {
            "model-value": __props.item.spec.left,
            "test-id": "signoz-join-left",
            "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => patch({ left: String($event) }))
          }, null, 8, ["model-value"])
        ]),
        createElementVNode("div", _hoisted_3$5, [
          _cache[6] || (_cache[6] = createElementVNode(
            "label",
            null,
            "Right",
            -1
            /* CACHED */
          )),
          createVNode(unref(GInput), {
            "model-value": __props.item.spec.right,
            "test-id": "signoz-join-right",
            "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => patch({ right: String($event) }))
          }, null, 8, ["model-value"])
        ]),
        createElementVNode("div", _hoisted_4$4, [
          _cache[7] || (_cache[7] = createElementVNode(
            "label",
            null,
            "Type",
            -1
            /* CACHED */
          )),
          createVNode(unref(GSelect), {
            value: __props.item.spec.type,
            options: [
              { label: "inner", value: "inner" },
              { label: "left", value: "left" },
              { label: "right", value: "right" },
              { label: "full", value: "full" }
            ],
            "test-id": "signoz-join-type",
            "onUpdate:value": _cache[2] || (_cache[2] = ($event) => patch({ type: String($event) }))
          }, null, 8, ["value"])
        ]),
        createElementVNode("div", _hoisted_5$4, [
          _cache[8] || (_cache[8] = createElementVNode(
            "label",
            null,
            "On",
            -1
            /* CACHED */
          )),
          createVNode(unref(GInput), {
            "model-value": __props.item.spec.on || "",
            placeholder: "A.service = B.service AND A.env = B.env",
            "test-id": "signoz-join-on",
            "onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => patch({ on: String($event) }))
          }, null, 8, ["model-value"])
        ]),
        createElementVNode("div", _hoisted_6$3, [
          _cache[9] || (_cache[9] = createElementVNode(
            "label",
            null,
            "Limit",
            -1
            /* CACHED */
          )),
          createVNode(unref(GInput), {
            "model-value": __props.item.spec.limit != null ? String(__props.item.spec.limit) : "",
            "test-id": "signoz-join-limit",
            "onUpdate:modelValue": _cache[4] || (_cache[4] = ($event) => patch({ limit: String($event) === "" ? void 0 : Number($event) }))
          }, null, 8, ["model-value"])
        ])
      ]);
    };
  }
});
const JoinFields = /* @__PURE__ */ _export_sfc(_sfc_main$8, [["__scopeId", "data-v-8d63785f"]]);
const _hoisted_1$6 = { class: "qb-row qb-row--where" };
const _hoisted_2$5 = ["title", "data-testid"];
const _hoisted_3$4 = ["data-testid"];
const _hoisted_4$3 = ["data-testid", "title"];
const _hoisted_5$3 = ["data-testid"];
const _hoisted_6$2 = { class: "qb-row-actions" };
const _hoisted_7$2 = ["title", "data-testid"];
const _hoisted_8 = ["data-testid"];
const _hoisted_9 = ["disabled", "data-testid"];
const _hoisted_10 = {
  key: 0,
  class: "qb-warn",
  "data-testid": "signoz-mode-blocked",
  role: "status"
};
const _hoisted_11 = {
  key: 1,
  class: "qb-warn",
  "data-testid": "signoz-item-capability-error",
  role: "status"
};
const _hoisted_12 = { class: "qb-body-inner" };
const _hoisted_13 = {
  key: 3,
  class: "qb-row qb-row--filter",
  "data-testid": "signoz-subquery-fields"
};
const _hoisted_14 = { class: "subq-note" };
const _hoisted_15 = {
  key: 1,
  class: "qb-row qb-row--filter qb-raw-row"
};
const _hoisted_16 = { class: "qb-label" };
const _hoisted_17 = {
  key: 2,
  class: "hidden-anchors",
  "aria-hidden": "true",
  "data-testid": "signoz-matrix-anchors"
};
const _hoisted_18 = {
  key: 3,
  class: "hidden-anchors",
  "aria-hidden": "true",
  "data-testid": "signoz-matrix-anchors"
};
const _hoisted_19 = {
  key: 0,
  "data-matrix-id": "signoz-expr"
};
const _hoisted_20 = {
  key: 1,
  "data-matrix-id": "signoz-raw-editor"
};
const _sfc_main$7 = /* @__PURE__ */ defineComponent({
  __name: "QueryItemRow",
  props: {
    item: {},
    index: {},
    allItems: {},
    profile: {},
    capabilities: {},
    isPrimary: { type: Boolean },
    canDelete: { type: Boolean },
    datasourceApi: {},
    globalMode: {}
  },
  emits: ["update", "copy", "remove", "run"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const collapsed = ref(false);
    const isFormula = computed(() => props.item.type === "builder_formula");
    const isTraceOp = computed(() => props.item.type === "builder_trace_operator");
    const isJoin = computed(() => props.item.type === "builder_join");
    const isSubQuery = computed(() => props.item.type === "builder_sub_query");
    const isBuilderQuery = computed(() => props.item.type === "builder_query");
    const itemValidation = computed(
      () => validateSavedItem(props.item, props.capabilities)
    );
    const signal = computed(() => {
      if (props.item.type === "builder_query")
        return props.item.spec.signal || "metrics";
      if (props.item.type === "builder_sub_query")
        return props.item.spec.signal || "metrics";
      return "metrics";
    });
    const mode2 = computed(() => {
      if (props.globalMode) return props.globalMode;
      if (props.item.type === "builder_query")
        return props.item.queryType || "builder";
      return "builder";
    });
    const lockMode = computed(() => props.globalMode != null);
    const modeBlockedReason = computed(() => {
      if (!isBuilderQuery.value) return "";
      if (!props.profile.signals.includes(signal.value)) {
        return `当前 profile 不支持 signal=${signal.value}`;
      }
      if (!isModeAllowed(props.profile, signal.value, mode2.value)) {
        return `当前 profile 不允许 ${signal.value}/${mode2.value}`;
      }
      if (mode2.value === "builder" && !props.capabilities.builder) {
        return "builder 当前 capability 不可用";
      }
      if (mode2.value === "promql" && !props.capabilities.promql) {
        return "promql 当前 capability 不可用";
      }
      if (mode2.value === "clickhouse_sql" && !props.capabilities.clickhouseSql) {
        return "clickhouse_sql 当前 capability 不可用";
      }
      return "";
    });
    const signalOptions = computed(() => {
      const all = ["metrics", "logs", "traces"];
      return all.map((s) => ({
        label: s,
        value: s,
        disabled: !props.profile.signals.includes(s)
      }));
    });
    const modeOptions = computed(() => {
      const allowed = props.profile.queryModesBySignal?.[signal.value] || [];
      return [
        { label: "Builder", value: "builder", cap: props.capabilities.builder },
        { label: "PromQL", value: "promql", cap: props.capabilities.promql },
        {
          label: "ClickHouse SQL",
          value: "clickhouse_sql",
          cap: props.capabilities.clickhouseSql
        }
      ].map((o) => ({
        label: o.label,
        value: o.value,
        disabled: !o.cap || (allowed.length > 0 ? !allowed.includes(o.value) : true)
      }));
    });
    function updateItem(next) {
      emit("update", next);
    }
    function setSignal(v) {
      if (props.item.type !== "builder_query") return;
      const s = String(v);
      const prev = props.item.spec.signal || "metrics";
      if (s === prev) {
        updateItem({ ...props.item, spec: { ...props.item.spec, signal: s } });
        return;
      }
      const aggregations = defaultAggregationsForSignal(
        s
      );
      updateItem({
        ...props.item,
        spec: {
          ...props.item.spec,
          signal: s,
          aggregations,
          source: s === "metrics" ? props.item.spec.source : void 0
        }
      });
    }
    function setMode(v) {
      if (props.item.type !== "builder_query") return;
      const m = String(v);
      const next = {
        ...props.item,
        queryType: m
      };
      if (m === "promql" && !String(next.rawQuery || "").trim()) {
        next.rawQuery = "up";
      }
      if (m === "clickhouse_sql" && !String(next.rawQuery || "").trim()) {
        next.rawQuery = "SELECT 1";
      }
      updateItem(next);
    }
    function toggleDisabled() {
      if (props.item.type === "builder_formula") {
        updateItem({
          type: "builder_formula",
          spec: { ...props.item.spec, disabled: !props.item.spec.disabled }
        });
        return;
      }
      if (props.item.type === "builder_trace_operator") {
        updateItem({
          type: "builder_trace_operator",
          spec: { ...props.item.spec, disabled: !props.item.spec.disabled }
        });
        return;
      }
      if (props.item.type === "builder_join") {
        updateItem({
          type: "builder_join",
          spec: { ...props.item.spec, disabled: !props.item.spec.disabled }
        });
        return;
      }
      if (props.item.type === "builder_sub_query") {
        updateItem({
          type: "builder_sub_query",
          spec: { ...props.item.spec, disabled: !props.item.spec.disabled }
        });
        return;
      }
      updateItem({
        ...props.item,
        spec: { ...props.item.spec, disabled: !props.item.spec.disabled }
      });
    }
    function setRaw(v) {
      if (props.item.type !== "builder_query") return;
      updateItem({ ...props.item, rawQuery: v });
    }
    function setSpec(spec) {
      if (props.item.type !== "builder_query") return;
      updateItem({
        type: "builder_query",
        queryType: props.item.queryType,
        rawQuery: props.item.rawQuery,
        rawLegend: props.item.rawLegend,
        spec: {
          ...defaultBuilderSpec(props.item.spec.name, props.item.spec.signal),
          ...spec
        }
      });
    }
    const disabled = computed(() => Boolean(props.item.spec.disabled));
    const tid = (base) => props.isPrimary ? base : `${base}-${props.item.spec.name}`;
    const nameLabel = computed(() => String(props.item.spec?.name || "?"));
    const typeBadge = computed(() => {
      if (isFormula.value) return "Formula";
      if (isTraceOp.value) return "Trace Operator";
      if (isJoin.value) return "Join";
      if (isSubQuery.value) return "Sub Query";
      return "";
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock(
        "div",
        {
          class: normalizeClass(["qb-body query-row", { "qb-body--disabled": disabled.value, disabled: disabled.value, collapsed: collapsed.value }]),
          "data-testid": "signoz-query-item-row"
        },
        [
          createCommentVNode(" WHERE row: chevron + chip + signal + mode + actions "),
          createElementVNode("div", _hoisted_1$6, [
            createElementVNode("button", {
              type: "button",
              class: "qb-btn-icon qb-collapse-btn",
              title: collapsed.value ? "展开" : "折叠",
              "data-testid": tid("signoz-row-collapse"),
              onClick: _cache[0] || (_cache[0] = ($event) => collapsed.value = !collapsed.value)
            }, toDisplayString(collapsed.value ? "▸" : "▾"), 9, _hoisted_2$5),
            createElementVNode("span", {
              class: normalizeClass(["qb-chip", { "qb-chip--formula": isFormula.value }]),
              "data-testid": tid("signoz-row-name")
            }, toDisplayString(nameLabel.value), 11, _hoisted_3$4),
            isBuilderQuery.value ? (openBlock(), createElementBlock(
              Fragment,
              { key: 0 },
              [
                createVNode(unref(GSelect), {
                  value: signal.value,
                  options: signalOptions.value,
                  "test-id": tid("signoz-signal"),
                  class: "qb-sel-signal",
                  "onUpdate:value": setSignal
                }, null, 8, ["value", "options", "test-id"]),
                !lockMode.value ? (openBlock(), createBlock(unref(GSelect), {
                  key: 0,
                  value: mode2.value,
                  options: modeOptions.value,
                  "test-id": tid("signoz-mode"),
                  class: "qb-sel-mode",
                  "onUpdate:value": setMode
                }, null, 8, ["value", "options", "test-id"])) : (openBlock(), createElementBlock("span", {
                  key: 1,
                  class: "qb-mode-badge",
                  "data-testid": tid("signoz-mode-locked"),
                  title: "全局模式: " + mode2.value
                }, toDisplayString(mode2.value), 9, _hoisted_4$3))
              ],
              64
              /* STABLE_FRAGMENT */
            )) : (openBlock(), createElementBlock("span", {
              key: 1,
              class: "qb-type-badge",
              "data-testid": isFormula.value ? "signoz-formula-badge" : "signoz-item-badge"
            }, toDisplayString(typeBadge.value), 9, _hoisted_5$3)),
            _cache[4] || (_cache[4] = createElementVNode(
              "div",
              { class: "qb-spacer" },
              null,
              -1
              /* CACHED */
            )),
            createElementVNode("div", _hoisted_6$2, [
              createElementVNode("button", {
                type: "button",
                class: "qb-btn-icon",
                title: disabled.value ? "启用" : "禁用",
                "data-testid": tid("signoz-row-enable"),
                onClick: toggleDisabled
              }, toDisplayString(disabled.value ? "○" : "●"), 9, _hoisted_7$2),
              createElementVNode("button", {
                type: "button",
                class: "qb-btn-icon",
                title: "复制",
                "data-testid": tid("signoz-row-copy"),
                onClick: _cache[1] || (_cache[1] = ($event) => emit("copy"))
              }, " ⧉ ", 8, _hoisted_8),
              createElementVNode("button", {
                type: "button",
                class: "qb-btn-icon qb-btn-icon--danger",
                title: "删除",
                disabled: !__props.canDelete,
                "data-testid": tid("signoz-row-delete"),
                onClick: _cache[2] || (_cache[2] = ($event) => emit("remove"))
              }, " ✕ ", 8, _hoisted_9)
            ])
          ]),
          modeBlockedReason.value ? (openBlock(), createElementBlock(
            "div",
            _hoisted_10,
            toDisplayString(modeBlockedReason.value) + "（已保留查询文本，运行前请切换） ",
            1
            /* TEXT */
          )) : createCommentVNode("v-if", true),
          !itemValidation.value.ok ? (openBlock(), createElementBlock(
            "div",
            _hoisted_11,
            toDisplayString(itemValidation.value.message),
            1
            /* TEXT */
          )) : createCommentVNode("v-if", true),
          withDirectives(createElementVNode(
            "div",
            _hoisted_12,
            [
              isFormula.value && __props.item.type === "builder_formula" ? (openBlock(), createBlock(FormulaFields, {
                key: 0,
                item: __props.item,
                "all-items": __props.allItems,
                onUpdate: updateItem
              }, null, 8, ["item", "all-items"])) : isTraceOp.value && __props.item.type === "builder_trace_operator" ? (openBlock(), createBlock(TraceOperatorFields, {
                key: 1,
                item: __props.item,
                onUpdate: updateItem
              }, null, 8, ["item"])) : isJoin.value && __props.item.type === "builder_join" ? (openBlock(), createBlock(JoinFields, {
                key: 2,
                item: __props.item,
                onUpdate: updateItem
              }, null, 8, ["item"])) : isSubQuery.value && __props.item.type === "builder_sub_query" ? (openBlock(), createElementBlock("div", _hoisted_13, [
                _cache[5] || (_cache[5] = createElementVNode(
                  "span",
                  { class: "qb-label" },
                  "Expression",
                  -1
                  /* CACHED */
                )),
                createElementVNode(
                  "span",
                  _hoisted_14,
                  toDisplayString(__props.item.spec.expression || "(sub_query)"),
                  1
                  /* TEXT */
                )
              ])) : __props.item.type === "builder_query" ? (openBlock(), createElementBlock(
                Fragment,
                { key: 4 },
                [
                  mode2.value === "builder" ? (openBlock(), createBlock(BuilderFields, {
                    key: 0,
                    spec: __props.item.spec,
                    "is-primary": __props.isPrimary,
                    "datasource-api": __props.datasourceApi,
                    capabilities: __props.capabilities,
                    "onUpdate:spec": setSpec,
                    onRun: _cache[3] || (_cache[3] = ($event) => emit("run"))
                  }, null, 8, ["spec", "is-primary", "datasource-api", "capabilities"])) : (openBlock(), createElementBlock("div", _hoisted_15, [
                    createElementVNode(
                      "span",
                      _hoisted_16,
                      toDisplayString(mode2.value === "promql" ? "PromQL" : "SQL"),
                      1
                      /* TEXT */
                    ),
                    createVNode(RawQueryEditor, {
                      "model-value": __props.item.rawQuery || "",
                      mode: mode2.value,
                      "test-id": tid(mode2.value === "promql" ? "signoz-expr" : "signoz-raw-editor"),
                      class: "qb-flex",
                      "onUpdate:modelValue": setRaw
                    }, null, 8, ["model-value", "mode", "test-id"])
                  ])),
                  __props.isPrimary && mode2.value === "builder" ? (openBlock(), createElementBlock("div", _hoisted_17, [..._cache[6] || (_cache[6] = [
                    createElementVNode(
                      "span",
                      { "data-matrix-id": "signoz-expr" },
                      null,
                      -1
                      /* CACHED */
                    ),
                    createElementVNode(
                      "span",
                      { "data-matrix-id": "signoz-raw-editor" },
                      null,
                      -1
                      /* CACHED */
                    ),
                    createElementVNode(
                      "span",
                      { "data-matrix-id": "signoz-min-duration" },
                      null,
                      -1
                      /* CACHED */
                    ),
                    createElementVNode(
                      "span",
                      { "data-matrix-id": "signoz-max-duration" },
                      null,
                      -1
                      /* CACHED */
                    )
                  ])])) : createCommentVNode("v-if", true),
                  __props.isPrimary && mode2.value !== "builder" ? (openBlock(), createElementBlock("div", _hoisted_18, [
                    mode2.value !== "promql" ? (openBlock(), createElementBlock("span", _hoisted_19)) : createCommentVNode("v-if", true),
                    mode2.value === "promql" ? (openBlock(), createElementBlock("span", _hoisted_20)) : createCommentVNode("v-if", true),
                    _cache[7] || (_cache[7] = createStaticVNode('<span data-matrix-id="signoz-metric" data-v-9aca9681></span><span data-matrix-id="signoz-aggregation" data-v-9aca9681></span><span data-matrix-id="signoz-filter" data-v-9aca9681></span><span data-matrix-id="signoz-having" data-v-9aca9681></span><span data-matrix-id="signoz-group-by" data-v-9aca9681></span><span data-matrix-id="signoz-order" data-v-9aca9681></span><span data-matrix-id="signoz-limit" data-v-9aca9681></span><span data-matrix-id="signoz-legend" data-v-9aca9681></span><span data-matrix-id="signoz-functions" data-v-9aca9681></span><span data-matrix-id="signoz-service" data-v-9aca9681></span><span data-matrix-id="signoz-operation" data-v-9aca9681></span><span data-matrix-id="signoz-tags" data-v-9aca9681></span><span data-matrix-id="signoz-min-duration" data-v-9aca9681></span><span data-matrix-id="signoz-max-duration" data-v-9aca9681></span>', 14))
                  ])) : createCommentVNode("v-if", true)
                ],
                64
                /* STABLE_FRAGMENT */
              )) : createCommentVNode("v-if", true)
            ],
            512
            /* NEED_PATCH */
          ), [
            [vShow, !collapsed.value]
          ])
        ],
        2
        /* CLASS */
      );
    };
  }
});
const QueryItemRow = /* @__PURE__ */ _export_sfc(_sfc_main$7, [["__scopeId", "data-v-9aca9681"]]);
const _sfc_main$6 = /* @__PURE__ */ defineComponent({
  __name: "BuilderQueryRow",
  props: {
    item: {},
    index: {},
    allItems: {},
    profile: {},
    capabilities: {},
    isPrimary: { type: Boolean },
    canDelete: { type: Boolean },
    datasourceApi: {},
    globalMode: {}
  },
  emits: ["update", "copy", "remove", "run"],
  setup(__props) {
    return (_ctx, _cache) => {
      return openBlock(), createBlock(QueryItemRow, {
        item: __props.item,
        index: __props.index,
        "all-items": __props.allItems,
        profile: __props.profile,
        capabilities: __props.capabilities,
        "is-primary": __props.isPrimary,
        "can-delete": __props.canDelete,
        "datasource-api": __props.datasourceApi,
        "global-mode": __props.globalMode,
        onUpdate: _cache[0] || (_cache[0] = ($event) => _ctx.$emit("update", $event)),
        onCopy: _cache[1] || (_cache[1] = ($event) => _ctx.$emit("copy")),
        onRemove: _cache[2] || (_cache[2] = ($event) => _ctx.$emit("remove")),
        onRun: _cache[3] || (_cache[3] = ($event) => _ctx.$emit("run"))
      }, null, 8, ["item", "index", "all-items", "profile", "capabilities", "is-primary", "can-delete", "datasource-api", "global-mode"]);
    };
  }
});
const _hoisted_1$5 = {
  class: "signoz-builder-editor",
  "data-testid": "signoz-builder-editor"
};
const _sfc_main$5 = /* @__PURE__ */ defineComponent({
  __name: "BuilderEditor",
  props: {
    items: {},
    profile: {},
    capabilities: {},
    datasourceApi: {},
    globalMode: {}
  },
  emits: ["update", "copy", "remove", "run"],
  setup(__props, { emit: __emit }) {
    const emit = __emit;
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$5, [
        (openBlock(true), createElementBlock(
          Fragment,
          null,
          renderList(__props.items, (item, index2) => {
            return openBlock(), createBlock(_sfc_main$6, {
              key: item.spec.name + "-" + index2,
              item,
              index: index2,
              "all-items": __props.items,
              profile: __props.profile,
              capabilities: __props.capabilities,
              "is-primary": index2 === 0,
              "can-delete": __props.items.length > 1,
              "datasource-api": __props.datasourceApi,
              "global-mode": __props.globalMode,
              onUpdate: ($event) => emit("update", index2, $event),
              onCopy: ($event) => emit("copy", index2),
              onRemove: ($event) => emit("remove", index2),
              onRun: _cache[0] || (_cache[0] = ($event) => emit("run"))
            }, null, 8, ["item", "index", "all-items", "profile", "capabilities", "is-primary", "can-delete", "datasource-api", "global-mode", "onUpdate", "onCopy", "onRemove"]);
          }),
          128
          /* KEYED_FRAGMENT */
        ))
      ]);
    };
  }
});
const BuilderEditor = /* @__PURE__ */ _export_sfc(_sfc_main$5, [["__scopeId", "data-v-2a339bb2"]]);
const _hoisted_1$4 = {
  class: "signoz-query-type-tabs",
  "data-testid": "signoz-query-type-tabs",
  role: "tablist"
};
const _hoisted_2$4 = ["aria-selected", "aria-disabled", "disabled", "title", "data-testid", "onClick"];
const _hoisted_3$3 = {
  key: 0,
  class: "signoz-qtt-legacy",
  "data-testid": "signoz-legacy-mixed-warning",
  role: "status"
};
const _sfc_main$4 = /* @__PURE__ */ defineComponent({
  __name: "QueryTypeTabs",
  props: {
    mode: {},
    blocked: {},
    legacyMixed: { type: Boolean }
  },
  emits: ["update:mode"],
  setup(__props, { emit: __emit }) {
    const props = __props;
    const emit = __emit;
    const TABS = [
      { value: "builder", label: "Query Builder" },
      { value: "promql", label: "PromQL" },
      { value: "clickhouse_sql", label: "ClickHouse SQL" }
    ];
    function isBlocked(mode2) {
      return Boolean(props.blocked?.[mode2]);
    }
    function select(mode2) {
      if (isBlocked(mode2) || mode2 === props.mode) return;
      emit("update:mode", mode2);
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$4, [
        (openBlock(), createElementBlock(
          Fragment,
          null,
          renderList(TABS, (tab) => {
            return createElementVNode("button", {
              key: tab.value,
              type: "button",
              role: "tab",
              class: normalizeClass(["signoz-qtt-tab", {
                "signoz-qtt-tab--active": __props.mode === tab.value,
                "signoz-qtt-tab--disabled": isBlocked(tab.value)
              }]),
              "aria-selected": __props.mode === tab.value,
              "aria-disabled": isBlocked(tab.value) ? "true" : "false",
              disabled: isBlocked(tab.value),
              title: __props.blocked?.[tab.value] || tab.label,
              "data-testid": tab.value === "builder" ? "signoz-mode" : `signoz-mode-${tab.value}`,
              onClick: ($event) => select(tab.value)
            }, toDisplayString(tab.label), 11, _hoisted_2$4);
          }),
          64
          /* STABLE_FRAGMENT */
        )),
        __props.legacyMixed ? (openBlock(), createElementBlock("p", _hoisted_3$3, " 检测到旧版混合查询模式。请选择全局模式以升级；未确认前仍使用原 schema 序列化。 ")) : createCommentVNode("v-if", true)
      ]);
    };
  }
});
const QueryTypeTabs = /* @__PURE__ */ _export_sfc(_sfc_main$4, [["__scopeId", "data-v-73ad8c79"]]);
const _hoisted_1$3 = {
  class: "signoz-qe",
  "data-testid": "query-editor-signoz"
};
const _hoisted_2$3 = {
  key: 0,
  class: "err"
};
const _hoisted_3$2 = { class: "qe-toolbar" };
const _hoisted_4$2 = { class: "qe-request-type" };
const _hoisted_5$2 = { class: "qb-footer" };
const _sfc_main$3 = /* @__PURE__ */ defineComponent({
  __name: "QueryEditor",
  props: {
    query: {},
    onChange: { type: Function },
    onRunQuery: { type: Function },
    datasource: {},
    range: {},
    datasourceApi: {}
  },
  setup(__props) {
    const props = __props;
    const query = computed(() => migrateSigNozQuery(props.query || {}));
    const editorState = computed(() => toEditorState(query.value));
    const items = computed(() => {
      const q = query.value;
      if (Array.isArray(q.queries) && q.queries.length) return q.queries;
      return fromEditorState(editorState.value, q).queries;
    });
    const globalMode = computed(
      () => editorState.value.activeQueryType || "builder"
    );
    const jsonData = computed(
      () => props.datasource?.jsonData || {}
    );
    const profile = computed(() => {
      const jd = jsonData.value;
      const apiProfile = jd.apiProfile || query.value.apiProfile || "signoz-v5";
      return resolveSigNozProfile({ ...jd, apiProfile });
    });
    const capabilities = computed(
      () => resolveEditorCapabilities({
        profile: profile.value,
        options: jsonData.value
      })
    );
    const requestTypeOptions = computed(
      () => allowedRequestTypes(capabilities.value).map((t) => ({ label: t, value: t }))
    );
    const modeBlocked = computed(() => {
      const out = {};
      if (!capabilities.value.builder)
        out.builder = "builder 当前 capability 不可用";
      if (!capabilities.value.promql) out.promql = "promql 当前 capability 不可用";
      if (!capabilities.value.clickhouseSql)
        out.clickhouse_sql = "clickhouse_sql 当前 capability 不可用";
      return out;
    });
    const validationErrors = computed(
      () => items.value.map((item) => {
        const v = validateSavedItem(item, capabilities.value);
        return v.ok ? null : { name: item.spec.name, message: v.message };
      }).filter(Boolean)
    );
    const metaApi = ref(null);
    const metaError = ref("");
    function resolveApi2() {
      const uid = String(
        props.datasource?.uid || props.query?.datasource?.uid || ""
      );
      if (uid) {
        const registered2 = getRuntimeDataSource(uid);
        if (registered2) return registered2;
      }
      return props.datasourceApi || props.datasource || null;
    }
    onMounted(() => {
      metaApi.value = resolveApi2();
    });
    watch(
      () => [props.datasource?.uid, props.datasourceApi],
      () => {
        metaApi.value = resolveApi2();
      }
    );
    function commitQueries(nextItems, extra = {}) {
      const base = props.query;
      const first = nextItems.find((i) => i.type === "builder_query") || nextItems[0];
      const flat = {};
      if (first && first.type === "builder_query") {
        flat.signal = first.spec.signal;
        flat.expr = first.rawQuery || "";
        flat.service = first.spec.service;
        flat.operation = first.spec.operation;
        flat.legendFormat = first.rawLegend || first.spec.legend || "";
        flat.limit = first.spec.limit;
      }
      const formula = nextItems.find((i) => i.type === "builder_formula");
      if (formula && formula.type === "builder_formula") {
        flat.formula = formula.spec.expression;
      }
      const rebuilt = toEditorState({ queries: nextItems });
      rebuilt.activeQueryType = globalMode.value;
      const stillMixed = Boolean(editorState.value.legacyMixed && !extra && false);
      const next = {
        ...query.value,
        ...flat,
        ...extra,
        refId: base?.refId ?? query.value.refId,
        datasource: base?.datasource ?? query.value.datasource,
        hide: base?.hide ?? query.value.hide,
        schema: stillMixed ? 1 : 2,
        queries: nextItems,
        editor: rebuilt
      };
      if (editorState.value.legacyMixed && editorState.value.legacySchema1) {
        next.editor.legacyMixed = true;
        next.editor.legacySchema1 = editorState.value.legacySchema1;
        next.schema = 1;
      }
      props.onChange(next);
    }
    function commitEditor(nextState, extra = {}) {
      const base = props.query;
      const wire = fromEditorState(nextState, {
        ...query.value,
        ...extra,
        refId: base?.refId ?? query.value.refId,
        datasource: base?.datasource ?? query.value.datasource,
        hide: base?.hide ?? query.value.hide
      });
      const first = wire.queries.find((i) => i.type === "builder_query");
      if (first && first.type === "builder_query") {
        wire.signal = first.spec.signal;
        wire.expr = first.rawQuery || "";
        wire.legendFormat = first.rawLegend || first.spec.legend || "";
        wire.limit = first.spec.limit;
      }
      props.onChange(wire);
    }
    function setGlobalMode(mode2) {
      if (modeBlocked.value[mode2]) return;
      let st = commitGlobalMode(editorState.value, mode2);
      if (mode2 === "promql" && !st.promql.length) {
        st = {
          ...st,
          promql: [{ name: "A", query: "up" }]
        };
      }
      if (mode2 === "clickhouse_sql" && !st.clickhouseSql.length) {
        st = {
          ...st,
          clickhouseSql: [{ name: "A", query: "SELECT 1" }]
        };
      }
      if (mode2 === "builder" && !st.builder.queries.length) {
        st = {
          ...st,
          builder: {
            ...st.builder,
            queries: [defaultBuilderSpec("A", "traces")]
          }
        };
      }
      commitEditor(st);
    }
    function setRequestType(v) {
      commitQueries(items.value, { requestType: String(v) });
    }
    function updateAt(index2, item) {
      const next = items.value.map((it, i) => i === index2 ? item : it);
      commitQueries(next);
    }
    function addQuery() {
      if (!capabilities.value.builder && !capabilities.value.promql) return;
      const name = nextQueryName(items.value);
      const signal = profile.value.signals[0] || "traces";
      const mode2 = globalMode.value;
      const item = mode2 === "promql" ? defaultPromItem(name, "") : mode2 === "clickhouse_sql" ? {
        type: "builder_query",
        queryType: "clickhouse_sql",
        spec: defaultBuilderSpec(
          name,
          signal === "metrics" ? "logs" : signal
        ),
        rawQuery: "",
        rawLegend: ""
      } : {
        type: "builder_query",
        queryType: "builder",
        spec: defaultBuilderSpec(name, signal),
        rawQuery: "",
        rawLegend: ""
      };
      commitQueries([...items.value, item]);
    }
    function addFormula() {
      if (!capabilities.value.formula) return;
      if (globalMode.value !== "builder") {
        setGlobalMode("builder");
      }
      const current = items.value;
      const name = nextFormulaName(current);
      const item = {
        type: "builder_formula",
        spec: {
          name,
          expression: current.find((i) => i.type === "builder_query")?.spec.name || "A",
          disabled: false,
          legend: "",
          order: []
        }
      };
      const asBuilder = current.map((it) => {
        if (it.type !== "builder_query") return it;
        return { ...it, queryType: "builder" };
      });
      commitQueries([...asBuilder, item]);
    }
    function addTraceOperator() {
      if (!capabilities.value.traceOperator || globalMode.value !== "builder")
        return;
      const name = nextQueryName(items.value);
      const item = {
        type: "builder_trace_operator",
        spec: { name, expression: "", disabled: false, legend: "" }
      };
      commitQueries([...items.value, item]);
    }
    function addJoin() {
      if (!capabilities.value.join || globalMode.value !== "builder") return;
      const name = nextQueryName(items.value);
      const item = {
        type: "builder_join",
        spec: {
          name,
          left: "A",
          right: "B",
          type: "inner",
          on: "",
          disabled: false
        }
      };
      commitQueries([...items.value, item]);
    }
    function copyAt(index2) {
      const src = items.value[index2];
      if (!src) return;
      if (src.type === "builder_formula") {
        const name2 = nextFormulaName(items.value);
        commitQueries([
          ...items.value,
          {
            type: "builder_formula",
            spec: { ...src.spec, name: name2 }
          }
        ]);
        return;
      }
      const name = nextQueryName(items.value);
      commitQueries([
        ...items.value,
        {
          ...src,
          spec: { ...src.spec, name },
          rawQuery: src.rawQuery,
          rawLegend: src.rawLegend
        }
      ]);
    }
    function removeAt(index2) {
      if (items.value.length <= 1) return;
      commitQueries(items.value.filter((_, i) => i !== index2));
    }
    onMounted(() => {
      if (!items.value.length) {
        commitQueries([
          {
            type: "builder_query",
            queryType: "builder",
            spec: defaultBuilderSpec("A", "traces"),
            rawQuery: "",
            rawLegend: ""
          }
        ]);
      }
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$3, [
        metaError.value ? (openBlock(), createElementBlock(
          "div",
          _hoisted_2$3,
          toDisplayString(metaError.value),
          1
          /* TEXT */
        )) : createCommentVNode("v-if", true),
        createCommentVNode(" Time range comes from Grafana Explore/Dashboard external picker (no internal clock). "),
        createElementVNode("div", _hoisted_3$2, [
          _cache[3] || (_cache[3] = createElementVNode(
            "div",
            {
              class: "qe-toolbar-note",
              "data-testid": "signoz-external-time-note"
            },
            " 时间范围使用页面顶部时间选择器 ",
            -1
            /* CACHED */
          )),
          createElementVNode("div", _hoisted_4$2, [
            _cache[2] || (_cache[2] = createElementVNode(
              "span",
              { class: "qe-rt-label" },
              "requestType",
              -1
              /* CACHED */
            )),
            createVNode(unref(GSelect), {
              value: query.value.requestType || "time_series",
              options: requestTypeOptions.value,
              "test-id": "signoz-request-type",
              "onUpdate:value": setRequestType
            }, null, 8, ["value", "options"])
          ])
        ]),
        createVNode(QueryTypeTabs, {
          mode: globalMode.value,
          blocked: modeBlocked.value,
          "legacy-mixed": Boolean(editorState.value.legacyMixed),
          "onUpdate:mode": setGlobalMode
        }, null, 8, ["mode", "blocked", "legacy-mixed"]),
        (openBlock(true), createElementBlock(
          Fragment,
          null,
          renderList(validationErrors.value, (err) => {
            return openBlock(), createElementBlock(
              "div",
              {
                key: err.name + err.message,
                class: "warn",
                "data-testid": "signoz-capability-error",
                role: "status"
              },
              toDisplayString(err.name) + ": " + toDisplayString(err.message),
              1
              /* TEXT */
            );
          }),
          128
          /* KEYED_FRAGMENT */
        )),
        createVNode(BuilderEditor, {
          items: items.value,
          profile: profile.value,
          capabilities: capabilities.value,
          "datasource-api": metaApi.value,
          "global-mode": globalMode.value,
          onUpdate: updateAt,
          onCopy: copyAt,
          onRemove: removeAt,
          onRun: _cache[0] || (_cache[0] = ($event) => props.onRunQuery?.())
        }, null, 8, ["items", "profile", "capabilities", "datasource-api", "global-mode"]),
        createElementVNode("div", _hoisted_5$2, [
          createElementVNode("button", {
            type: "button",
            class: "qb-add-btn",
            "data-testid": "signoz-add-query",
            onClick: addQuery
          }, " + 添加查询 "),
          capabilities.value.formula ? (openBlock(), createElementBlock("button", {
            key: 0,
            type: "button",
            class: "qb-add-btn",
            "data-testid": "signoz-add-formula",
            onClick: addFormula
          }, " + 添加公式 ")) : createCommentVNode("v-if", true),
          capabilities.value.traceOperator && globalMode.value === "builder" ? (openBlock(), createElementBlock("button", {
            key: 1,
            type: "button",
            class: "qb-add-btn",
            "data-testid": "signoz-add-trace-operator",
            onClick: addTraceOperator
          }, " + Trace Operator ")) : createCommentVNode("v-if", true),
          capabilities.value.join && globalMode.value === "builder" ? (openBlock(), createElementBlock("button", {
            key: 2,
            type: "button",
            class: "qb-add-btn",
            "data-testid": "signoz-add-join",
            onClick: addJoin
          }, " + Join ")) : createCommentVNode("v-if", true),
          _cache[5] || (_cache[5] = createElementVNode(
            "div",
            { class: "qb-footer-spacer" },
            null,
            -1
            /* CACHED */
          )),
          createVNode(unref(GButton), {
            size: "sm",
            variant: "primary",
            type: "button",
            "test-id": "run-query",
            onClick: _cache[1] || (_cache[1] = ($event) => props.onRunQuery?.())
          }, {
            default: withCtx(() => [..._cache[4] || (_cache[4] = [
              createTextVNode(
                " 运行查询 ",
                -1
                /* CACHED */
              )
            ])]),
            _: 1
            /* STABLE */
          })
        ])
      ]);
    };
  }
});
const QueryEditor = /* @__PURE__ */ _export_sfc(_sfc_main$3, [["__scopeId", "data-v-82079c89"]]);
const refreshInflight = /* @__PURE__ */ new Map();
function jwtExpiry(token) {
  if (!token) return null;
  try {
    const part = token.split(".")[1];
    if (!part) return null;
    const b64 = part.replace(/-/g, "+").replace(/_/g, "/");
    const padded = b64 + "=".repeat((4 - b64.length % 4) % 4);
    const json = typeof atob === "function" ? atob(padded) : Buffer.from(padded, "base64").toString("utf8");
    const payload = JSON.parse(json);
    return typeof payload.exp === "number" ? payload.exp * 1e3 : null;
  } catch {
    return null;
  }
}
function isHttp401(err) {
  if (!err) return false;
  const e = err;
  if (e?.status === 401 || e?.statusCode === 401) return true;
  if (e?.code === "AUTH_REQUIRED" || e?.code === "AUTH_REJECTED") return true;
  const msg = String(e?.message || e || "");
  return /\b401\b|unauthorized|AUTH_REQUIRED|session expired/i.test(msg);
}
function unwrapData(body) {
  if (!body || typeof body !== "object") return body;
  if (body.data && typeof body.data === "object") return body.data;
  return body;
}
function assertJsonObject(data, label) {
  if (!data || typeof data !== "object" || Array.isArray(data)) {
    throw new DataSourceError(
      "AUTH_REJECTED",
      `${label} returned non-JSON object (possible SPA HTML)`
    );
  }
  const s = JSON.stringify(data).slice(0, 200).toLowerCase();
  if (s.includes("<!doctype") || s.includes("<html")) {
    throw new DataSourceError(
      "AUTH_REJECTED",
      `${label} returned HTML instead of JSON`
    );
  }
  return data;
}
async function loadLatestSessionCredential(uid, fallback) {
  try {
    const latest = asSessionCredential(await getRuntimeCredential(uid));
    if (latest) {
      return {
        ...fallback,
        ...latest,
        kind: "session",
        // Keep password only if rememberPassword (or latest still has it)
        password: latest.password ?? fallback.password,
        email: latest.email ?? fallback.email,
        orgID: latest.orgID ?? fallback.orgID,
        rememberPassword: latest.rememberPassword ?? fallback.rememberPassword
      };
    }
  } catch {
  }
  return fallback;
}
async function refreshSession(ctx, http = datasourceHttp) {
  const existing = refreshInflight.get(ctx.uid);
  if (existing) return existing;
  const promise = doRefreshSession(ctx, http).finally(() => {
    if (refreshInflight.get(ctx.uid) === promise) {
      refreshInflight.delete(ctx.uid);
    }
  });
  refreshInflight.set(ctx.uid, promise);
  return promise;
}
async function doRefreshSession(ctx, http) {
  const c = await loadLatestSessionCredential(ctx.uid, ctx.credential);
  const base = {
    uid: ctx.uid,
    baseUrl: ctx.baseUrl,
    forceNetwork: true,
    signal: ctx.signal
  };
  if (c.refreshToken && c.value) {
    try {
      const r = await http({
        ...base,
        path: "/api/v2/sessions/rotate",
        method: "POST",
        headers: { Authorization: `Bearer ${c.value}` },
        body: { refreshToken: c.refreshToken },
        credential: null
      });
      const body = assertJsonObject(unwrapData(r.data), "sessions/rotate");
      const accessToken2 = String(body.accessToken || body.accessJwt || "");
      const refreshToken2 = String(
        body.refreshToken || body.refreshJwt || c.refreshToken || ""
      );
      if (!accessToken2) {
        throw new DataSourceError(
          "AUTH_REJECTED",
          "sessions/rotate missing accessToken"
        );
      }
      const next2 = {
        ...c,
        kind: "session",
        value: accessToken2,
        refreshToken: refreshToken2
      };
      setRuntimeCredential(ctx.uid, next2);
      return next2;
    } catch {
    }
  }
  if (!c.email || !c.password) {
    throw new DataSourceError("AUTH_REQUIRED", "SigNoz 会话已过期,请重新登录");
  }
  let orgID = c.orgID;
  try {
    const ctxResp = await http({
      ...base,
      method: "GET",
      path: "/api/v2/sessions/context",
      query: { email: c.email, ref: `${ctx.baseUrl.replace(/\/$/, "")}/login` },
      credential: null
    });
    const body = assertJsonObject(unwrapData(ctxResp.data), "sessions/context");
    const orgs = body.orgs || body.organizations || [];
    if (!orgID && orgs[0]) {
      orgID = String(orgs[0].id || orgs[0].orgId || orgs[0].orgID || "");
    }
  } catch {
  }
  if (!orgID) {
    throw new DataSourceError(
      "AUTH_REQUIRED",
      "SigNoz 登录需要 orgID,请在配置中填写 Organization ID 或重新登录"
    );
  }
  const login = await http({
    ...base,
    path: "/api/v2/sessions/email_password",
    method: "POST",
    body: { email: c.email, password: c.password, orgID },
    credential: null
  });
  const loginBody = assertJsonObject(
    unwrapData(login.data),
    "sessions/email_password"
  );
  const accessToken = String(
    loginBody.accessToken || loginBody.accessJwt || ""
  );
  const refreshToken = String(
    loginBody.refreshToken || loginBody.refreshJwt || ""
  );
  if (!accessToken) {
    throw new DataSourceError(
      "AUTH_REJECTED",
      "email_password login missing accessToken"
    );
  }
  const next = {
    kind: "session",
    value: accessToken,
    refreshToken: refreshToken || void 0,
    orgID,
    email: c.email,
    password: c.rememberPassword ? c.password : void 0,
    rememberPassword: c.rememberPassword
  };
  setRuntimeCredential(ctx.uid, next);
  return next;
}
async function withAuthRetry(fn, ctx, http = datasourceHttp) {
  let cred = await loadLatestSessionCredential(ctx.uid, ctx.credential);
  const exp = jwtExpiry(cred.value);
  if (exp && exp - Date.now() < 5 * 6e4) {
    cred = await refreshSession({ ...ctx, credential: cred }, http);
  }
  try {
    return await fn();
  } catch (e) {
    if (!isHttp401(e)) throw e;
    cred = await refreshSession(
      {
        ...ctx,
        credential: await loadLatestSessionCredential(ctx.uid, cred)
      },
      http
    );
    return await fn();
  }
}
function asSessionCredential(cred) {
  if (!cred) return null;
  if (cred.kind === "session") return cred;
  if (cred.kind === "bearer" && cred.refreshToken) {
    return { ...cred, kind: "session" };
  }
  return null;
}
function schemaSummaryOf(value, depth = 0) {
  if (depth > 4) return "...";
  if (value == null) return String(value);
  if (Array.isArray(value)) return `array(${value.length})`;
  if (typeof value !== "object") return typeof value;
  const keys = Object.keys(value).slice(0, 20);
  return `{${keys.map((k) => `${k}:${schemaSummaryOf(value[k], depth + 1)}`).join(",")}}`;
}
function asWarnings(v) {
  if (v == null) return void 0;
  if (Array.isArray(v)) return v.map(String);
  return [String(v)];
}
function normalizeType(t) {
  const s = t.toLowerCase();
  if (s.includes("matrix") || s.includes("time_series") || s === "series")
    return "time_series";
  if (s.includes("vector") || s.includes("scalar")) return "scalar";
  if (s.includes("raw_stream") || s === "stream") return "raw_stream";
  if (s.includes("raw")) return "raw";
  if (s.includes("trace")) return "trace";
  if (s.includes("distribution") || s.includes("histogram"))
    return "distribution";
  return "unknown";
}
function inferType(data, list) {
  const explicit = String(
    data.resultType ?? data.type ?? data.requestType ?? ""
  ).toLowerCase();
  if (explicit) {
    const n = normalizeType(explicit);
    if (n !== "unknown") return n;
    if (!["", "matrix", "vector", "success"].includes(explicit))
      return "unknown";
  }
  const first = list[0];
  if (!first) return "unknown";
  if (first.aggregations || first.series || first.values || first.timestamps)
    return "time_series";
  if (first.spans || first.traceID || first.traceId || first.list)
    return "trace";
  if (first.columns && first.data) return "scalar";
  if (first.rows || first.nextCursor != null) return "raw";
  return list.length ? "time_series" : "unknown";
}
function extractSignozEnvelope(body, profile = "native", opts) {
  if (body == null || typeof body !== "object") {
    throw new DataSourceError(
      "INVALID_RESPONSE",
      "SigNoz response is not an object"
    );
  }
  const root = body;
  if (profile === "argus" || profile === "flat") {
    const status2 = root.status != null ? String(root.status) : root.code != null ? String(root.code) : void 0;
    if (status2 && /error|fail/i.test(status2) && status2 !== "200") {
      throw new DataSourceError("INVALID_RESPONSE", `SigNoz status=${status2}`);
    }
    const outer = root.data && typeof root.data === "object" ? root.data : root;
    const nested2 = outer.data && typeof outer.data === "object" ? outer.data : null;
    const data = nested2 || outer;
    const results = data.results ?? data.result ?? outer.results ?? outer.result ?? [];
    const list2 = Array.isArray(results) ? results : results != null ? [results] : [];
    return {
      status: status2,
      type: inferType(outer, list2) || inferType(data, list2),
      results: list2,
      warning: asWarnings(root.warning ?? outer.warning ?? data.warning),
      meta: {
        ...typeof outer.meta === "object" && outer.meta ? outer.meta : {},
        ...typeof data.meta === "object" && data.meta ? data.meta : {}
      },
      raw: body,
      schemaSummary: schemaSummaryOf(body)
    };
  }
  if (!("data" in root) && !("result" in root)) {
    throw new DataSourceError(
      "UNSUPPORTED_RESPONSE_SHAPE",
      `missing data envelope; schema=${schemaSummaryOf(body)}`
    );
  }
  const dataLayer = root.data && typeof root.data === "object" ? root.data : null;
  if (!dataLayer) {
    throw new DataSourceError(
      "UNSUPPORTED_RESPONSE_SHAPE",
      `missing data object; schema=${schemaSummaryOf(body)}`
    );
  }
  const status = root.status != null ? String(root.status) : dataLayer.status != null ? String(dataLayer.status) : void 0;
  if (status && /error|fail/i.test(status) && status.toLowerCase() !== "success") {
    throw new DataSourceError("INVALID_RESPONSE", `SigNoz status=${status}`, {
      upstreamCode: status
    });
  }
  const nested = dataLayer.data && typeof dataLayer.data === "object" ? dataLayer.data : null;
  let resultsRaw;
  let typeSource = dataLayer;
  if (nested && (nested.results != null || nested.result != null)) {
    resultsRaw = nested.results ?? nested.result;
    typeSource = { ...dataLayer, ...nested };
  } else if (opts?.strictV5) {
    if (dataLayer.results != null && nested == null) {
      throw new DataSourceError(
        "UNSUPPORTED_RESPONSE_SHAPE",
        `Native V5 requires data.data.results, not data.results; schema=${schemaSummaryOf(body)}`
      );
    }
    resultsRaw = dataLayer.result;
    if (resultsRaw == null) {
      throw new DataSourceError(
        "UNSUPPORTED_RESPONSE_SHAPE",
        `missing data.data.results; schema=${schemaSummaryOf(body)}`
      );
    }
  } else {
    resultsRaw = dataLayer.result ?? dataLayer.results;
  }
  if (resultsRaw == null) {
    throw new DataSourceError(
      "UNSUPPORTED_RESPONSE_SHAPE",
      `missing results; schema=${schemaSummaryOf(body)}`
    );
  }
  const list = Array.isArray(resultsRaw) ? resultsRaw : [resultsRaw];
  const type = inferType(typeSource, list);
  const known = /* @__PURE__ */ new Set([
    "status",
    "data",
    "type",
    "resultType",
    "result",
    "results",
    "meta",
    "warning",
    "error"
  ]);
  const extras = {};
  for (const [k, v] of Object.entries(dataLayer)) {
    if (!known.has(k)) extras[k] = v;
  }
  return {
    status,
    type,
    results: list,
    warning: asWarnings(root.warning ?? dataLayer.warning ?? nested?.warning),
    meta: {
      ...typeof dataLayer.meta === "object" && dataLayer.meta ? dataLayer.meta : {},
      ...nested && typeof nested.meta === "object" && nested.meta ? nested.meta : {},
      resultType: dataLayer.resultType ?? dataLayer.type
    },
    extras: Object.keys(extras).length ? extras : void 0,
    raw: body,
    schemaSummary: schemaSummaryOf(body)
  };
}
function schemaSummary(value) {
  return schemaSummaryOf(value);
}
function liveMeta$3(extra = {}) {
  return { source: "live", preferredVisualisationType: "table", ...extra };
}
function labelsToRecord$1(labels) {
  const out = {};
  if (Array.isArray(labels)) {
    for (const l of labels) {
      const name = String(
        l?.key?.name ?? l?.name ?? ""
      ).trim();
      if (name) out[name] = String(l?.value ?? "");
    }
  } else if (labels && typeof labels === "object") {
    for (const [k, v] of Object.entries(labels)) out[k] = String(v);
  }
  return out;
}
function emptyScalarFrame(opts, extraMeta = {}) {
  return createDataFrame({
    refId: opts.refId,
    name: String(extraMeta.queryName || "scalar"),
    meta: liveMeta$3({
      requestType: "scalar",
      empty: true,
      warnings: opts.warnings,
      ...extraMeta
    }),
    fields: [{ name: "Value", type: "number", values: [] }]
  });
}
function asArray$1(v) {
  return Array.isArray(v) ? v : [];
}
function isColumnsDataShape(r) {
  if (!r || typeof r !== "object") return false;
  if ("columns" in r || "data" in r) return true;
  if (r.table && typeof r.table === "object") return true;
  return false;
}
function isAggSeriesShape(r) {
  if (!r || typeof r !== "object") return false;
  if ("aggregations" in r) return true;
  if (Array.isArray(r.series)) return true;
  return false;
}
function isPromVectorShape(r) {
  if (!r || typeof r !== "object") return false;
  return Array.isArray(r.value) && r.value.length >= 2 && (r.metric != null || r.labels != null);
}
function fieldFromValues(name, values) {
  const isNum = values.every(
    (v) => v == null || typeof v === "number" || typeof v === "string" && v !== "" && Number.isFinite(Number(v))
  );
  return {
    name,
    type: isNum ? "number" : "string",
    values: isNum ? values.map((v) => v == null || v === "" ? null : Number(v)) : values.map((v) => v == null ? null : String(v))
  };
}
function mapColumnsDataResult(r, qi, opts) {
  const table = r?.table && typeof r.table === "object" ? r.table : r;
  const cols = asArray$1(table.columns);
  const rows = asArray$1(table.data ?? table.rows);
  const isObjectRows = rows.length > 0 && rows.every(
    (row) => row != null && typeof row === "object" && !Array.isArray(row)
  );
  if (isObjectRows) {
    const fieldNames = cols.length > 0 ? cols.map(
      (c, ci) => typeof c === "string" ? c : String(c?.name || c?.title || c?.id || `col${ci}`)
    ) : Array.from(
      new Set(
        rows.flatMap(
          (row) => Object.keys(
            row?.data && typeof row.data === "object" ? row.data : row
          )
        )
      )
    );
    const fields2 = fieldNames.map((name) => {
      const values = rows.map((row) => {
        const obj = row?.data && typeof row.data === "object" ? row.data : row;
        return obj?.[name] ?? null;
      });
      return fieldFromValues(name, values);
    });
    return createDataFrame({
      refId: opts.refId,
      name: String(r.queryName || r.name || `scalar-${qi}`),
      meta: liveMeta$3({
        requestType: "scalar",
        shape: "columns",
        queryName: r.queryName,
        empty: !fields2.length || fields2.every(
          (f) => !Array.isArray(f.values) || f.values.length === 0
        ) || void 0,
        warnings: opts.warnings
      }),
      fields: fields2.length ? fields2 : [{ name: "Value", type: "number", values: [] }]
    });
  }
  const matrixRows = rows.map(
    (row) => Array.isArray(row) ? row : []
  );
  const fields = cols.map((c, ci) => {
    const name = typeof c === "string" ? c : String(c?.name || c?.title || `col${ci}`);
    const values = matrixRows.map(
      (row) => ci < row.length ? row[ci] : null
    );
    return fieldFromValues(name, values);
  });
  return createDataFrame({
    refId: opts.refId,
    name: String(r.queryName || r.name || `scalar-${qi}`),
    meta: liveMeta$3({
      requestType: "scalar",
      shape: "columns",
      queryName: r.queryName,
      empty: !fields.length || fields.every(
        (f) => !Array.isArray(f.values) || f.values.length === 0
      ) || void 0,
      warnings: opts.warnings
    }),
    fields: fields.length ? fields : [{ name: "Value", type: "number", values: [] }]
  });
}
function mapAggSeriesResult(result, ri, opts) {
  const frames = [];
  const aggs = Array.isArray(result.aggregations) ? result.aggregations : result.series ? [{ series: result.series }] : [];
  aggs.forEach((agg, ai) => {
    const seriesList = asArray$1(agg?.series);
    seriesList.forEach((s, si) => {
      const labels = labelsToRecord$1(s.labels);
      const rawVal = s.values?.[0]?.value ?? s.value ?? s.values?.[0] ?? null;
      const n = rawVal == null || rawVal === "" ? null : Number(rawVal);
      const name = String(
        agg.alias || result.queryName || labels.__name__ || `A${ri}_${ai}_${si}`
      );
      frames.push(
        createDataFrame({
          refId: opts.refId,
          name,
          meta: liveMeta$3({
            requestType: "scalar",
            shape: "aggregations",
            aggregationIndex: ai,
            alias: agg.alias,
            queryName: result.queryName,
            labels,
            unit: agg.unit || agg.meta?.unit || s.unit,
            warnings: opts.warnings
          }),
          fields: [
            {
              name: "Value",
              type: "number",
              values: [Number.isFinite(n) ? n : null],
              labels,
              config: { displayNameFromDS: name }
            },
            {
              name: "ValueRaw",
              type: "string",
              values: [rawVal == null ? null : String(rawVal)]
            }
          ]
        })
      );
    });
  });
  return frames;
}
function mapPromVectorResult(r, i, opts) {
  const labels = labelsToRecord$1(r.metric ?? r.labels);
  const rawVal = Array.isArray(r.value) ? r.value[1] : r.value;
  const n = rawVal == null || rawVal === "" ? null : Number(rawVal);
  const name = String(
    labels.__name__ || r.queryName || opts.refId || `vector-${i}`
  );
  return createDataFrame({
    refId: opts.refId,
    name,
    meta: liveMeta$3({
      requestType: "scalar",
      shape: "prom_vector",
      labels,
      warnings: opts.warnings
    }),
    fields: [
      {
        name: "Value",
        type: "number",
        values: [Number.isFinite(n) ? n : null],
        labels,
        config: { displayNameFromDS: name }
      },
      {
        name: "ValueRaw",
        type: "string",
        values: [rawVal == null ? null : String(rawVal)]
      }
    ]
  });
}
function mapScalarResponse(results, opts) {
  if (!results.length) {
    return [emptyScalarFrame(opts)];
  }
  const frames = [];
  results.forEach((raw, qi) => {
    const r = raw;
    if (r == null || typeof r !== "object") {
      frames.push(emptyScalarFrame(opts, { index: qi }));
      return;
    }
    if (isColumnsDataShape(r)) {
      frames.push(mapColumnsDataResult(r, qi, opts));
      return;
    }
    if (isAggSeriesShape(r)) {
      const mapped = mapAggSeriesResult(r, qi, opts);
      if (mapped.length) frames.push(...mapped);
      else
        frames.push(
          emptyScalarFrame(opts, {
            shape: "aggregations",
            queryName: r.queryName
          })
        );
      return;
    }
    if (isPromVectorShape(r)) {
      frames.push(mapPromVectorResult(r, qi, opts));
      return;
    }
    if (r.queryName != null || r.name != null) {
      frames.push(
        emptyScalarFrame(opts, {
          shape: "empty",
          queryName: r.queryName ?? r.name,
          index: qi
        })
      );
      return;
    }
    throw new DataSourceError(
      "UNSUPPORTED_RESPONSE_SHAPE",
      `scalar results match neither aggregations.series nor columns/data shape; keys=${JSON.stringify(
        Object.keys(r).slice(0, 12)
      )}`
    );
  });
  return frames.length ? frames : [emptyScalarFrame(opts)];
}
function liveMeta$2(extra = {}) {
  return { source: "live", preferredVisualisationType: "logs", ...extra };
}
function toMs(v) {
  const n = Number(v ?? 0);
  if (!Number.isFinite(n) || n <= 0) return 0;
  return n < 1e12 ? n * 1e3 : n;
}
function mapRawRows(results, opts) {
  const frames = [];
  for (const result of results) {
    const r = result;
    const rows = Array.isArray(r?.rows) ? r.rows : Array.isArray(r?.data) ? r.data : Array.isArray(r) ? r : [];
    const keySet = /* @__PURE__ */ new Set([
      "timestamp",
      "body",
      "severity",
      "trace_id",
      "span_id",
      "service",
      "resources_string",
      "attributes_string"
    ]);
    for (const row of rows) {
      if (row && typeof row === "object") {
        for (const k of Object.keys(row)) keySet.add(k);
        if (row.data && typeof row.data === "object") {
          for (const k of Object.keys(row.data)) keySet.add(`data.${k}`);
        }
      }
    }
    const keys = [...keySet];
    const colValues = {};
    for (const k of keys) colValues[k] = [];
    for (const row of rows) {
      const o = row && typeof row === "object" ? row : {};
      for (const k of keys) {
        if (k.startsWith("data.")) {
          colValues[k].push(o.data ? o.data[k.slice(5)] : null);
        } else {
          colValues[k].push(o[k] ?? null);
        }
      }
    }
    const times = rows.map(
      (row) => toMs(row?.timestamp ?? row?.time ?? row?.ts)
    );
    const lines = rows.map(
      (row) => String(
        row?.body ?? row?.message ?? row?.line ?? (typeof row === "string" ? row : JSON.stringify(row ?? ""))
      )
    );
    const fields = [
      { name: "Time", type: "time", values: times },
      { name: "Line", type: "string", values: lines },
      {
        name: "severity",
        type: "string",
        values: rows.map(
          (row) => String(row?.severity ?? row?.level ?? "")
        )
      },
      {
        name: "traceId",
        type: "string",
        values: rows.map(
          (row) => String(row?.trace_id ?? row?.traceId ?? "")
        )
      },
      {
        name: "spanId",
        type: "string",
        values: rows.map(
          (row) => String(row?.span_id ?? row?.spanId ?? "")
        )
      },
      {
        name: "service",
        type: "string",
        values: rows.map(
          (row) => String(
            row?.service ?? row?.resources_string?.["service.name"] ?? row?.["service.name"] ?? ""
          )
        )
      }
    ];
    for (const k of keys) {
      if ([
        "timestamp",
        "body",
        "message",
        "line",
        "severity",
        "level",
        "trace_id",
        "traceId",
        "span_id",
        "spanId",
        "service"
      ].includes(k)) {
        continue;
      }
      fields.push({
        name: k,
        type: "string",
        values: colValues[k].map(
          (v) => v == null ? null : typeof v === "string" ? v : JSON.stringify(v)
        )
      });
    }
    frames.push(
      createDataFrame({
        refId: opts.refId,
        name: String(r?.queryName || (opts.stream ? "raw_stream" : "raw")),
        meta: liveMeta$2({
          requestType: opts.stream ? "raw_stream" : "raw",
          queryName: r?.queryName,
          nextCursor: r?.nextCursor ?? r?.cursor ?? null,
          selectFields: r?.selectFields,
          rowCount: rows.length,
          warnings: opts.warnings
        }),
        fields
      })
    );
  }
  if (!frames.length) {
    frames.push(
      createDataFrame({
        refId: opts.refId,
        name: opts.stream ? "raw_stream" : "raw",
        meta: liveMeta$2({
          requestType: opts.stream ? "raw_stream" : "raw",
          empty: true
        }),
        fields: [
          { name: "Time", type: "time", values: [] },
          { name: "Line", type: "string", values: [] }
        ]
      })
    );
  }
  return frames;
}
function mapRawResponse(body, opts) {
  const b = body;
  const results = b?.data?.data?.results ?? b?.data?.results ?? b?.results;
  if (Array.isArray(results)) return mapRawRows(results, opts);
  if (Array.isArray(b?.data?.result)) return mapRawRows(b.data.result, opts);
  if (Array.isArray(b?.logs)) {
    return mapRawRows([{ rows: b.logs }], { ...opts, stream: false });
  }
  if (Array.isArray(b?.traces)) {
    return mapRawRows([{ rows: b.traces }], { ...opts, stream: false });
  }
  if (Array.isArray(b?.rows)) {
    return mapRawRows([{ rows: b.rows }], { ...opts, stream: false });
  }
  return [
    createDataFrame({
      refId: opts.refId,
      name: "raw",
      meta: {
        source: "live",
        preferredVisualisationType: opts.signal === "logs" ? "logs" : void 0,
        notices: [
          {
            severity: "warning",
            text: "raw mapper: unstructured payload retained as JSON column"
          }
        ]
      },
      fields: [
        {
          name: "raw",
          type: "string",
          values: [
            typeof body === "string" ? body : JSON.stringify(body ?? null)
          ]
        }
      ]
    })
  ];
}
function mapRawStreamResponse(results, opts) {
  return mapRawRows(results, { ...opts, stream: true });
}
function liveMeta$1(extra = {}) {
  return { source: "live", preferredVisualisationType: "histogram", ...extra };
}
function mapDistributionResponse(results, opts) {
  if (!opts.experimentalDistribution) {
    throw new DataSourceError(
      "UNSUPPORTED_CAPABILITY",
      "distribution 仅实验能力，需要 experimentalDistribution=VERIFIED"
    );
  }
  const list = Array.isArray(results) ? results : results != null ? [results] : [];
  const frames = [];
  for (const result of list) {
    const r = result;
    const bucketsDirect = r?.buckets || r?.data?.buckets;
    const aggs = r?.aggregations || r?.data?.aggregations || [];
    const seriesBuckets = [];
    if (Array.isArray(bucketsDirect)) {
      seriesBuckets.push({ labels: {}, buckets: bucketsDirect });
    }
    for (const agg of aggs) {
      for (const s of agg?.series || []) {
        if (Array.isArray(s?.buckets) || Array.isArray(s?.values)) {
          seriesBuckets.push({
            labels: labelsOf(s?.labels),
            buckets: s.buckets || s.values
          });
        }
      }
    }
    for (const s of r?.series || []) {
      if (Array.isArray(s?.buckets) || Array.isArray(s?.values)) {
        seriesBuckets.push({
          labels: labelsOf(s?.labels),
          buckets: s.buckets || s.values
        });
      }
    }
    for (const series of seriesBuckets) {
      const bounds = [];
      const counts = [];
      for (const b of series.buckets || []) {
        const le = Number(b?.le ?? b?.upperBound ?? b?.bound ?? b?.[0]);
        const count = Number(b?.count ?? b?.value ?? b?.[1]);
        if (!Number.isFinite(le) || !Number.isFinite(count)) continue;
        bounds.push(le);
        counts.push(count);
      }
      if (!bounds.length) continue;
      const labelStr = Object.entries(series.labels || {}).map(([k, v]) => `${k}=${v}`).join(", ");
      frames.push(
        createDataFrame({
          refId: opts.refId,
          name: labelStr || "histogram",
          meta: liveMeta$1({
            preferredVisualisationType: "histogram",
            requestType: "distribution",
            labels: series.labels
          }),
          fields: [
            {
              name: "le",
              type: "number",
              values: bounds,
              config: { displayNameFromDS: "le" }
            },
            {
              name: "count",
              type: "number",
              values: counts,
              labels: series.labels,
              config: { displayNameFromDS: "count" }
            }
          ]
        })
      );
    }
  }
  if (frames.length) return frames;
  return [
    createDataFrame({
      refId: opts.refId,
      name: "distribution",
      meta: liveMeta$1({
        preferredVisualisationType: "histogram",
        requestType: "distribution",
        empty: true,
        notices: [
          { severity: "warning", text: "distribution response had no buckets" }
        ]
      }),
      fields: [
        { name: "le", type: "number", values: [] },
        { name: "count", type: "number", values: [] }
      ]
    })
  ];
}
function labelsOf(raw) {
  if (!raw) return {};
  if (Array.isArray(raw)) {
    const out = {};
    for (const l of raw) {
      const k = l?.key?.name || l?.key || l?.name;
      if (k) out[String(k)] = String(l?.value ?? "");
    }
    return out;
  }
  if (typeof raw === "object") {
    const out = {};
    for (const [k, v] of Object.entries(raw)) {
      if (k === "__name__") continue;
      out[k] = String(v);
    }
    return out;
  }
  return {};
}
function normalizeStatus(raw) {
  if (raw == null || raw === "") return "unset";
  const s = String(raw).toLowerCase().trim();
  if (s === "ok" || s === "success" || s === "unset" || s === "0" || s === "status_code_unset" || s === "status_ok" || s === "statuscode.ok" || s === "status_code_ok") {
    if (s === "unset" || s === "0" || s === "status_code_unset") return "unset";
    return "ok";
  }
  if (s === "error" || s === "err" || s === "failed" || s === "1" || s === "2" || s === "status_code_error" || s === "status_error" || s === "statuscode.error") {
    return "error";
  }
  if (typeof raw === "number") {
    if (raw === 0) return "unset";
    if (raw === 1) return "ok";
    if (raw === 2) return "error";
  }
  return "unset";
}
function statusFor(t) {
  if (t.status != null && String(t.status).trim() !== "") {
    return normalizeStatus(t.status);
  }
  const errCount = Number(t.errorCount ?? 0);
  if (Number.isFinite(errCount) && errCount > 0) return "error";
  if (t.hasError === true || t.hasError === 1 || t.hasError === "true") {
    return "error";
  }
  return "ok";
}
function asRecord(v) {
  if (v == null) return {};
  if (typeof v === "object" && !Array.isArray(v)) {
    return { ...v };
  }
  if (typeof v === "string" && v.trim()) {
    try {
      const parsed = JSON.parse(v);
      if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
        return parsed;
      }
    } catch {
    }
  }
  return {};
}
function asObjectArray(v) {
  if (Array.isArray(v)) {
    return v.map((item) => {
      if (item && typeof item === "object" && !Array.isArray(item)) {
        return { ...item };
      }
      if (typeof item === "string") {
        try {
          const parsed = JSON.parse(item);
          if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
            return parsed;
          }
        } catch {
          return { value: item };
        }
      }
      return { value: item };
    });
  }
  if (typeof v === "string" && v.trim()) {
    try {
      const parsed = JSON.parse(v);
      if (Array.isArray(parsed)) return asObjectArray(parsed);
      if (parsed && typeof parsed === "object") {
        return [parsed];
      }
    } catch {
      return [];
    }
  }
  return [];
}
function pickString(...vals) {
  for (const v of vals) {
    if (v == null || v === "") continue;
    return String(v);
  }
  return "";
}
function toDurationNs(span) {
  const nano = span.durationNs ?? span.duration_nano ?? span.durationNano ?? span.duration_nanos;
  if (nano != null && nano !== "") {
    if (typeof nano === "bigint") return nano.toString();
    if (typeof nano === "number" && Number.isFinite(nano)) {
      return String(Math.trunc(nano));
    }
    const s = String(nano).trim();
    if (/^\d+$/.test(s)) return s;
  }
  const ms = span.durationMs ?? span.duration_ms ?? span.duration ?? span.latency;
  if (ms != null && ms !== "") {
    const n = Number(ms);
    if (Number.isFinite(n)) {
      if (n > 1e12) return String(Math.trunc(n));
      return String(Math.round(n * 1e6));
    }
  }
  return "0";
}
function coerceEpochMs(raw, unitHint) {
  if (raw == null || raw === "") return 0;
  if (typeof raw === "string" && /^\d+$/.test(raw)) {
    if (unitHint === "ms" || raw.length >= 12 && raw.length <= 13) {
      const n3 = Number(raw);
      return Number.isFinite(n3) ? n3 : 0;
    }
    if (unitHint === "ns" || raw.length >= 16) {
      const ms = Number(raw.slice(0, -6));
      return Number.isFinite(ms) ? ms : 0;
    }
    if (unitHint === "us" || raw.length === 14 || raw.length === 15) {
      const n3 = Number(raw);
      return Number.isFinite(n3) ? Math.floor(n3 / 1e3) : 0;
    }
    const n2 = Number(raw);
    if (!Number.isFinite(n2)) return 0;
    if (unitHint === "s" || n2 > 0 && n2 < 1e11) return Math.floor(n2 * 1e3);
    return n2;
  }
  const n = Number(raw);
  if (!Number.isFinite(n)) return 0;
  if (unitHint === "ms") return n;
  if (unitHint === "ns" || n > 1e16) return Math.floor(n / 1e6);
  if (unitHint === "us" || n > 1e14) return Math.floor(n / 1e3);
  if (unitHint === "s" || n > 0 && n < 1e11) return Math.floor(n * 1e3);
  return n;
}
function toStartTimeMs(span) {
  if (span.startTimeMs != null && span.startTimeMs !== "") {
    return coerceEpochMs(span.startTimeMs, "ms");
  }
  if (span.startTimeUnixNano != null || span.startTimeUnixNanoStr != null || span.startTimeNano != null) {
    return coerceEpochMs(
      span.startTimeUnixNano ?? span.startTimeUnixNanoStr ?? span.startTimeNano,
      "ns"
    );
  }
  const raw = span.startTime ?? span.start_time ?? span.timestamp ?? span.time_unix;
  return coerceEpochMs(raw);
}
function toDurationMsFromNs(durationNs) {
  if (!durationNs || !/^\d+$/.test(durationNs)) return 0;
  if (durationNs.length <= 6) return Number(durationNs) / 1e6;
  const whole = Number(durationNs.slice(0, -6));
  const frac = Number(durationNs.slice(-6)) / 1e6;
  return (Number.isFinite(whole) ? whole : 0) + (Number.isFinite(frac) ? frac : 0);
}
function normalizeSpan(raw) {
  const span = raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
  const durationNs = toDurationNs(span);
  const tagsOrAttrs = span.attributes ?? span.tags ?? span.spanAttributes;
  const resource = span.resource ?? span.process ?? (span.process && typeof span.process === "object" ? span.process.tags : void 0);
  return {
    traceId: pickString(span.traceId, span.traceID, span.trace_id),
    spanId: pickString(span.spanId, span.span_id, span.id, span.spanID),
    parentSpanId: pickString(
      span.parentSpanId,
      span.parent_span_id,
      span.parentId,
      span.parent_id
    ) || void 0,
    startTimeMs: toStartTimeMs(span),
    durationNs,
    durationMs: toDurationMsFromNs(durationNs),
    serviceName: pickString(
      span.serviceName,
      span.service,
      span.service_name,
      span.resource?.service?.name,
      span.resource?.["service.name"]
    ),
    operationName: pickString(
      span.operationName,
      span.name,
      span.operation,
      span.spanName
    ),
    status: statusFor({
      status: span.status ?? (typeof span.statusCode !== "undefined" ? span.statusCode : span.status?.code),
      errorCount: span.errorCount ?? span.error_count,
      hasError: span.hasError ?? span.has_error
    }),
    resource: asRecord(resource),
    attributes: asRecord(tagsOrAttrs),
    events: asObjectArray(span.events ?? span.logs),
    links: asObjectArray(span.links),
    references: asObjectArray(span.references)
  };
}
function baseMeta(opts, semanticKind, extra = {}) {
  return {
    source: "signoz",
    preferredVisualisationType: semanticKind === "trace.detail" ? "trace" : "table",
    signal: "traces",
    requestType: "trace",
    ...opts.datasourceUid ? { datasourceUid: opts.datasourceUid } : {},
    ...opts.profile ? { profile: opts.profile } : {},
    ...opts.requestId ? { requestId: opts.requestId } : {},
    custom: {
      source: "signoz",
      signal: "traces",
      semanticKind,
      complete: true,
      truncated: false,
      ...opts.datasourceUid ? { datasourceUid: opts.datasourceUid } : {},
      ...opts.profile ? { profile: opts.profile } : {},
      ...opts.requestId ? { requestId: opts.requestId } : {}
    },
    ...opts.warnings?.length ? { warnings: opts.warnings } : {},
    ...extra
  };
}
function spansToDetailFrame(spans, opts, extraMeta = {}) {
  return createDataFrame({
    refId: opts.refId,
    name: "trace",
    meta: baseMeta(opts, "trace.detail", extraMeta),
    fields: [
      { name: "traceId", type: "string", values: spans.map((s) => s.traceId) },
      { name: "spanId", type: "string", values: spans.map((s) => s.spanId) },
      {
        name: "parentSpanId",
        type: "string",
        values: spans.map((s) => s.parentSpanId ?? "")
      },
      {
        name: "operationName",
        type: "string",
        values: spans.map((s) => s.operationName)
      },
      // Grafana TraceView also reads `name`
      {
        name: "name",
        type: "string",
        values: spans.map((s) => s.operationName)
      },
      {
        name: "serviceName",
        type: "string",
        values: spans.map((s) => s.serviceName)
      },
      {
        name: "service",
        type: "string",
        values: spans.map((s) => s.serviceName)
      },
      {
        name: "startTimeMs",
        type: "number",
        values: spans.map((s) => s.startTimeMs)
      },
      {
        name: "startTime",
        type: "number",
        values: spans.map((s) => s.startTimeMs)
      },
      {
        name: "durationNs",
        type: "string",
        values: spans.map((s) => s.durationNs)
      },
      {
        name: "durationMs",
        type: "number",
        values: spans.map((s) => s.durationMs)
      },
      {
        name: "duration",
        type: "number",
        values: spans.map((s) => s.durationMs)
      },
      {
        name: "status",
        type: "string",
        values: spans.map((s) => s.status)
      },
      {
        name: "resource",
        type: "other",
        values: spans.map((s) => s.resource)
      },
      {
        name: "attributes",
        type: "other",
        values: spans.map((s) => s.attributes)
      },
      {
        name: "events",
        type: "other",
        values: spans.map((s) => s.events)
      },
      {
        name: "links",
        type: "other",
        values: spans.map((s) => s.links)
      },
      {
        name: "references",
        type: "other",
        values: spans.map((s) => s.references)
      }
    ]
  });
}
function normalizeSearchRow(raw) {
  const t = raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
  const durationNs = toDurationNs({
    durationNano: t.durationNano,
    duration_nano: t.duration_nano,
    durationNs: t.durationNs,
    durationMs: t.durationMs ?? t.duration,
    duration: t.durationNano ?? t.duration_nano ?? t.duration
  });
  let ns = durationNs;
  if (t.durationNano != null || t.duration_nano != null) {
    const v = t.durationNano ?? t.duration_nano;
    ns = typeof v === "bigint" ? v.toString() : String(v);
  }
  return {
    traceId: pickString(t.traceId, t.traceID, t.trace_id),
    serviceName: pickString(
      t.rootServiceName,
      t.serviceName,
      t.service,
      t.rootService
    ),
    operationName: pickString(
      t.rootTraceName,
      t.name,
      t.operationName,
      t.operation
    ),
    durationNs: ns,
    durationMs: toDurationMsFromNs(ns),
    spanCount: Number(t.spanCount ?? t.span_count ?? 0) || 0,
    status: statusFor({
      status: t.status,
      errorCount: t.errorCount ?? t.error_count,
      hasError: t.hasError
    }),
    startTimeMs: toStartTimeMs(t)
  };
}
function searchRowsToFrame(rows, opts) {
  return createDataFrame({
    refId: opts.refId,
    name: "traces",
    meta: baseMeta(opts, "trace.search", {
      ...opts.nextCursor != null ? { nextCursor: opts.nextCursor } : {}
    }),
    fields: [
      { name: "traceId", type: "string", values: rows.map((r) => r.traceId) },
      {
        name: "service",
        type: "string",
        values: rows.map((r) => r.serviceName)
      },
      {
        name: "serviceName",
        type: "string",
        values: rows.map((r) => r.serviceName)
      },
      {
        name: "operation",
        type: "string",
        values: rows.map((r) => r.operationName)
      },
      {
        name: "operationName",
        type: "string",
        values: rows.map((r) => r.operationName)
      },
      {
        name: "durationNs",
        type: "string",
        values: rows.map((r) => r.durationNs)
      },
      {
        name: "duration",
        type: "number",
        values: rows.map((r) => r.durationMs)
      },
      {
        name: "durationMs",
        type: "number",
        values: rows.map((r) => r.durationMs)
      },
      {
        name: "spanCount",
        type: "number",
        values: rows.map((r) => r.spanCount)
      },
      { name: "status", type: "string", values: rows.map((r) => r.status) },
      {
        name: "startTimeMs",
        type: "number",
        values: rows.map((r) => r.startTimeMs)
      }
    ]
  });
}
function extractSpanList(body) {
  if (body == null) return [];
  if (Array.isArray(body)) return body;
  if (typeof body !== "object") return [];
  const b = body;
  const data = b.data && typeof b.data === "object" ? b.data : void 0;
  const candidates = [
    b.spans,
    data?.spans,
    data?.data?.spans,
    b.list,
    data?.list,
    b.results
  ];
  for (const c of candidates) {
    if (Array.isArray(c) && c.length) {
      if (c[0] && typeof c[0] === "object" && !Array.isArray(c[0])) {
        const first = c[0];
        if (Array.isArray(first.spans)) {
          const all = [];
          for (const r of c) {
            const spans = r?.spans;
            if (Array.isArray(spans)) all.push(...spans);
          }
          if (all.length) return all;
        }
        if (Array.isArray(first.list) || Array.isArray(first.traces)) {
          return [];
        }
        if (first.spanId || first.span_id || first.traceId || first.traceID) {
          return c;
        }
      } else {
        return c;
      }
    }
  }
  return [];
}
function extractSearchRows(results) {
  const rows = [];
  for (const r of results) {
    if (r == null) continue;
    if (Array.isArray(r)) {
      rows.push(...r);
      continue;
    }
    if (typeof r !== "object") continue;
    const obj = r;
    const list = obj.list ?? obj.traces;
    if (Array.isArray(list)) {
      rows.push(...list);
    } else if (obj.traceId || obj.traceID || obj.trace_id) {
      rows.push(obj);
    }
  }
  return rows;
}
function mapTraceDetailBody(body, opts, options) {
  const list = extractSpanList(body);
  if (!list.length) {
    if (body != null && typeof body === "object") {
      const keys = Object.keys(body);
      if (keys.length === 0) {
        return [spansToDetailFrame([], opts, { empty: true })];
      }
      const b = body;
      if (Array.isArray(b.spans) || Array.isArray(b?.data?.spans) || Array.isArray(b?.data?.data?.spans)) {
        return [spansToDetailFrame([], opts, { empty: true })];
      }
      throw new DataSourceError(
        "INVALID_RESPONSE",
        "无法解析 trace detail 响应：缺少 spans",
        { bodyKeys: keys }
      );
    }
    throw new DataSourceError(
      "INVALID_RESPONSE",
      "无法解析 trace detail 响应：payload 为空"
    );
  }
  const spans = list.map((s) => normalizeSpan(s));
  if (!spans.some((s) => s.spanId || s.traceId)) {
    throw new DataSourceError(
      "INVALID_RESPONSE",
      "无法解析 trace detail 响应：span 缺少 traceId/spanId"
    );
  }
  const payload = body && typeof body === "object" ? body.data && typeof body.data === "object" ? body.data : body : {};
  return [
    spansToDetailFrame(spans, opts, {
      rootService: opts.rootService ?? payload?.rootService,
      entryPoint: opts.entryPoint ?? payload?.entryPoint,
      totalCount: opts.totalCount ?? payload?.totalCount ?? spans.length,
      errorCount: opts.errorCount ?? payload?.errorCount,
      hasMore: opts.hasMore ?? payload?.hasMore
    })
  ];
}
function mapTraceSearchResults(results, opts) {
  const rawRows = extractSearchRows(results);
  const rows = rawRows.map((r) => normalizeSearchRow(r));
  return [searchRowsToFrame(rows, opts)];
}
function normalizeTraceFrames(frames) {
  return (frames ?? []).map((frame) => {
    const meta2 = { ...frame.meta || {} };
    const custom = {
      ...meta2.custom && typeof meta2.custom === "object" ? meta2.custom : {}
    };
    const name = String(frame.name || "").toLowerCase();
    const viz = String(meta2.preferredVisualisationType || "").toLowerCase();
    let semanticKind = custom.semanticKind || meta2.semanticKind;
    if (!semanticKind) {
      if (viz === "trace" || name === "trace") semanticKind = "trace.detail";
      else semanticKind = "trace.search";
    }
    custom.semanticKind = semanticKind;
    custom.signal = custom.signal ?? "traces";
    custom.source = custom.source ?? "signoz";
    meta2.custom = custom;
    meta2.signal = meta2.signal ?? "traces";
    if (semanticKind === "trace.detail" && !meta2.preferredVisualisationType) {
      meta2.preferredVisualisationType = "trace";
    }
    const fields = frame.fields.map((f) => {
      if (f.name === "events" || f.name === "links" || f.name === "references" || f.name === "attributes" || f.name === "resource") {
        const values = f.values.map((v) => {
          if (typeof v === "string") {
            if (f.name === "events" || f.name === "links" || f.name === "references") {
              return asObjectArray(v);
            }
            return asRecord(v);
          }
          return v;
        });
        return { ...f, type: "other", values };
      }
      return f;
    });
    return {
      ...frame,
      meta: meta2,
      fields,
      length: fields.reduce((m, f) => Math.max(m, f.values?.length ?? 0), 0)
    };
  });
}
function liveMeta(extra = {}, datasourceUid) {
  return {
    source: "live",
    ...{},
    ...extra
  };
}
function labelsToRecord(labels) {
  const out = {};
  if (!Array.isArray(labels)) return out;
  for (const l of labels) {
    const name = String(l?.key?.name ?? l?.name ?? "").trim();
    if (!name) continue;
    out[name] = String(l?.value ?? "");
  }
  return out;
}
function seriesName(labels, legend, fallback = "Value") {
  if (legend && legend.includes("{{")) {
    return legend.replace(
      /\{\{\s*([\w.-]+)\s*\}\}/g,
      (_, k) => labels[k] ?? ""
    );
  }
  if (legend) return legend;
  const pairs = Object.entries(labels);
  if (!pairs.length) return fallback;
  return pairs.map(([k, v]) => `${k}=${v}`).join(", ");
}
function mapSignozV5AggResponse(body, opts) {
  const results = body?.data?.results ?? body?.results ?? [];
  if (!Array.isArray(results) || !results.length) {
    return [
      createDataFrame({
        refId: opts.refId,
        name: opts.signal || "metrics",
        meta: liveMeta({
          preferredVisualisationType: "graph",
          apiProfile: "signoz-v5"
        }),
        fields: [
          { name: "Time", type: "time", values: [] },
          { name: "Value", type: "number", values: [] }
        ]
      })
    ];
  }
  const frames = [];
  for (const result of results) {
    const aggs = result?.aggregations ?? [];
    for (const bucket of aggs) {
      const seriesList = bucket?.series ?? [];
      for (const s of seriesList) {
        const labels = labelsToRecord(s?.labels);
        const pts = Array.isArray(s?.values) ? s.values : [];
        const times = pts.map((p) => {
          const t = Number(p?.timestamp ?? p?.[0] ?? 0);
          return t > 0 && t < 1e12 ? t * 1e3 : t;
        });
        const values = pts.map((p) => {
          const raw = p?.value ?? p?.[1];
          if (raw == null || raw === "NaN") return null;
          const n = Number(raw);
          return Number.isFinite(n) ? n : null;
        });
        const name = seriesName(
          labels,
          opts.legendFormat,
          String(bucket?.alias || result?.queryName || "Value")
        );
        frames.push(
          createDataFrame({
            refId: opts.refId,
            name,
            meta: liveMeta({
              preferredVisualisationType: "graph",
              apiProfile: "signoz-v5",
              labels
            }),
            fields: [
              { name: "Time", type: "time", values: times },
              {
                name: "Value",
                type: "number",
                values,
                labels,
                config: { displayNameFromDS: name }
              }
            ]
          })
        );
      }
    }
  }
  if (frames.length) return frames;
  return [
    createDataFrame({
      refId: opts.refId,
      name: opts.signal || "metrics",
      meta: liveMeta({
        preferredVisualisationType: "table",
        apiProfile: "signoz-v5",
        empty: true,
        notices: [
          {
            severity: "warning",
            text: "signoz response produced no series; full body not truncated-inlined"
          }
        ]
      }),
      fields: [
        { name: "Time", type: "time", values: [] },
        { name: "Value", type: "number", values: [] }
      ]
    })
  ];
}
function parsePointTime(p) {
  if (Array.isArray(p)) {
    const t2 = Number(p[0]);
    return t2 > 0 && t2 < 1e12 ? t2 * 1e3 : t2;
  }
  const t = Number(p?.timestamp ?? p?.ts ?? p?.time ?? 0);
  return t > 0 && t < 1e12 ? t * 1e3 : t;
}
function parsePointValue(p) {
  const raw = Array.isArray(p) ? p[1] : p?.value ?? p?.v;
  if (raw == null || raw === "NaN") return null;
  const n = Number(raw);
  return Number.isFinite(n) ? n : null;
}
function labelsFromUnknown(raw) {
  const labels = {};
  if (!raw) return labels;
  if (Array.isArray(raw)) {
    for (const item of raw) {
      const key = item?.key?.name ?? item?.key ?? item?.name;
      if (key == null) continue;
      if (String(key) === "__name__") continue;
      labels[String(key)] = String(item?.value ?? "");
    }
    return labels;
  }
  if (typeof raw === "object") {
    for (const [k, v] of Object.entries(raw)) {
      if (k === "__name__") continue;
      labels[k] = String(v);
    }
  }
  return labels;
}
function mapSignozV3Response(body, opts) {
  const resultList = body?.data?.result ?? body?.data?.results ?? body?.result;
  if (Array.isArray(resultList) && resultList.length === 0) {
    return [
      createDataFrame({
        refId: opts.refId,
        name: opts.signal || "metrics",
        meta: liveMeta({
          preferredVisualisationType: "graph",
          apiProfile: "signoz-v3",
          empty: true
        }),
        fields: [
          { name: "Time", type: "time", values: [] },
          { name: "Value", type: "number", values: [] }
        ]
      })
    ];
  }
  const result = body?.data?.result ?? body?.data?.data?.result ?? body?.result;
  if (Array.isArray(result) && result.length) {
    const frames = [];
    for (let idx = 0; idx < result.length; idx++) {
      const entry = result[idx];
      if (Array.isArray(entry?.series)) {
        for (const s of entry.series) {
          const labels2 = labelsFromUnknown(
            s?.labels ?? s?.labelsArray ?? entry?.metric
          );
          const pts = Array.isArray(s?.values) ? s.values : [];
          const times2 = pts.map(parsePointTime);
          const values2 = pts.map(parsePointValue);
          const baseName = entry.queryName && String(entry.queryName) || labels2.__name__ || `series ${idx}`;
          const name2 = seriesName(labels2, opts.legendFormat, baseName);
          frames.push(
            createDataFrame({
              refId: opts.refId,
              name: name2,
              meta: liveMeta({
                preferredVisualisationType: "graph",
                apiProfile: "signoz-v3",
                labels: labels2
              }),
              fields: [
                { name: "Time", type: "time", values: times2 },
                {
                  name: "Value",
                  type: "number",
                  values: values2,
                  labels: labels2,
                  config: { displayNameFromDS: name2 }
                }
              ]
            })
          );
        }
        continue;
      }
      const metric = entry.metric || entry.labels || {};
      const labels = labelsFromUnknown(metric);
      const name = seriesName(
        labels,
        opts.legendFormat,
        metric.__name__ || `series ${idx}`
      );
      let times = [];
      let values = [];
      if (entry.values) {
        times = entry.values.map(parsePointTime);
        values = entry.values.map(parsePointValue);
      } else if (entry.value) {
        times = [parsePointTime(entry.value)];
        values = [parsePointValue(entry.value)];
      }
      frames.push(
        createDataFrame({
          refId: opts.refId,
          name,
          meta: liveMeta({
            preferredVisualisationType: "graph",
            apiProfile: "signoz-v3",
            labels
          }),
          fields: [
            { name: "Time", type: "time", values: times },
            {
              name: "Value",
              type: "number",
              values,
              labels,
              config: { displayNameFromDS: name }
            }
          ]
        })
      );
    }
    if (frames.length) return frames;
  }
  throw new DataSourceError(
    "UNSUPPORTED_RESPONSE_SHAPE",
    `无法映射 time_series/legacy body; schema=${schemaSummary(body)}`
  );
}
function mapSignozResponse(body, profileId, opts) {
  const isNative = profileId.startsWith("signoz") || profileId === "prometheus-compatible";
  const profileShape = isNative ? "native" : "custom";
  if (profileId === "custom" && body == null) {
    throw new DataSourceError(
      "UNSUPPORTED_RESPONSE_SHAPE",
      "custom profile empty body"
    );
  }
  const strictV5 = profileId === "signoz-v5";
  let envelope;
  try {
    envelope = extractSignozEnvelope(
      body,
      profileShape === "custom" ? "native" : profileShape,
      {
        strictV5: strictV5 && !body?.data?.resultType
      }
    );
  } catch (e) {
    if (body?.data?.resultType || body?.data?.result) {
      return mapSignozV3Response(body, opts);
    }
    const signal = String(opts.signal || "").toLowerCase();
    if (signal === "logs" || signal === "traces" || body && typeof body === "object" && (Array.isArray(body.logs) || Array.isArray(body.traces) || Array.isArray(body.rows))) {
      return mapRawResponse(body, opts);
    }
    throw e;
  }
  const type = (opts.requestType || envelope.type || "").toLowerCase() || envelope.type;
  const warnings = envelope.warning;
  if (type === "distribution" || envelope.type === "distribution") {
    return mapDistributionResponse(envelope.results, {
      ...opts,
      experimentalDistribution: opts.experimentalDistribution
    });
  }
  if (type === "scalar" || envelope.type === "scalar") {
    return mapScalarResponse(envelope.results, { ...opts, warnings });
  }
  if (type === "raw_stream" || envelope.type === "raw_stream") {
    return mapRawStreamResponse(envelope.results, { ...opts, warnings });
  }
  if (type === "raw" || envelope.type === "raw" || opts.signal === "logs") {
    if (envelope.type === "raw" || type === "raw") {
      return mapRawRows(envelope.results, { ...opts, warnings });
    }
  }
  const envelopeIsAggregation = envelope.type === "time_series";
  if ((type === "trace" || envelope.type === "trace" || opts.signal === "traces") && !envelopeIsAggregation) {
    if (envelope.results.some((r) => r?.spans || r?.list)) {
      return mapTraceList(envelope.results, opts, warnings);
    }
    return mapTraceDetail(body, opts);
  }
  const hasAggSeries = (envelope.results || []).some(
    (r) => Array.isArray(r?.aggregations) || Array.isArray(r?.series)
  );
  if (hasAggSeries && (envelope.type === "time_series" || type === "time_series")) {
    return mapSignozV5AggResponse(
      {
        status: envelope.status || "success",
        data: { results: envelope.results }
      },
      { ...opts, signal: opts.signal || "metrics" }
    );
  }
  if (body?.data?.resultType || body?.data?.result)
    return mapSignozV3Response(body, opts);
  if (envelope.type === "time_series" || type === "time_series") {
    const asV3 = {
      status: envelope.status || "success",
      data: {
        resultType: "matrix",
        result: envelope.results
      }
    };
    return mapSignozV3Response(asV3, opts);
  }
  if (envelope.type === "unknown" && !envelope.results.length) {
    return [
      createDataFrame({
        refId: opts.refId,
        name: opts.signal || "empty",
        meta: liveMeta({ source: "live", empty: true, warnings }),
        fields: [
          { name: "Time", type: "time", values: [] },
          { name: "Value", type: "number", values: [] }
        ]
      })
    ];
  }
  throw new DataSourceError(
    "UNSUPPORTED_RESPONSE_SHAPE",
    `unknown result type=${envelope.type}; schema=${envelope.schemaSummary || schemaSummary(body)}`
  );
}
function mapTraceDetail(body, opts) {
  return normalizeTraceFrames(
    mapTraceDetailBody(body, {
      refId: opts.refId,
      datasourceUid: opts.datasourceUid,
      profile: opts.profile,
      requestId: opts.requestId
    })
  );
}
function mapTraceList(results, opts, warnings) {
  return normalizeTraceFrames(
    mapTraceSearchResults(results, {
      refId: opts.refId,
      datasourceUid: opts.datasourceUid,
      profile: opts.profile,
      requestId: opts.requestId,
      warnings,
      nextCursor: results[0]?.nextCursor
    })
  );
}
function mapAlertsResponse(body, opts) {
  const rows = body?.data || body?.alerts || body || [];
  const list = Array.isArray(rows) ? rows : [];
  return [
    createDataFrame({
      refId: opts.refId,
      name: "alerts",
      meta: { preferredVisualisationType: "table", signal: "alerts" },
      fields: [
        {
          name: "id",
          type: "string",
          values: list.map(
            (r, i) => String(r.id || r.alertId || i)
          )
        },
        {
          name: "title",
          type: "string",
          values: list.map(
            (r) => String(r.title || r.name || r.alertname || "")
          )
        },
        {
          name: "service",
          type: "string",
          values: list.map(
            (r) => String(r.service || r.labels?.service || "")
          )
        },
        {
          name: "severity",
          type: "string",
          values: list.map(
            (r) => String(r.severity || r.labels?.severity || "")
          )
        },
        {
          name: "status",
          type: "string",
          values: list.map((r) => String(r.status || r.state || "firing"))
        },
        {
          name: "Time",
          type: "time",
          values: list.map(
            (r) => Number(r.startsAt || r.time || Date.now())
          )
        },
        {
          name: "alertId",
          type: "string",
          values: list.map(
            (r, i) => String(r.alertId || r.id || i)
          )
        }
      ]
    })
  ];
}
const OFFLINE_METRICS = [
  {
    metricName: "up",
    description: "offline",
    type: "gauge",
    unit: "",
    temporality: "",
    isMonotonic: false
  },
  {
    metricName: "http_requests_total",
    description: "offline",
    type: "counter",
    unit: "",
    temporality: "Cumulative",
    isMonotonic: true
  }
];
const OFFLINE_SERVICES = ["frontend", "api", "checkout"];
function asArray(data) {
  if (Array.isArray(data)) return data;
  if (data && typeof data === "object") {
    const o = data;
    if (Array.isArray(o.data)) return o.data;
    if (Array.isArray(o.result)) return o.result;
    if (Array.isArray(o.metrics)) return o.metrics;
    if (Array.isArray(o.keys)) return o.keys;
    if (Array.isArray(o.values)) return o.values;
    if (o.data && typeof o.data === "object") {
      if (Array.isArray(o.data.metrics)) return o.data.metrics;
      if (Array.isArray(o.data.keys)) return o.data.keys;
      if (Array.isArray(o.data.values)) return o.data.values;
      if (o.data.keys && typeof o.data.keys === "object" && !Array.isArray(o.data.keys)) {
        return flattenKeysDict(o.data.keys);
      }
    }
    if (o.keys && typeof o.keys === "object" && !Array.isArray(o.keys)) {
      return flattenKeysDict(o.keys);
    }
  }
  return [];
}
function flattenKeysDict(dict) {
  const out = [];
  for (const [k, v] of Object.entries(dict || {})) {
    if (Array.isArray(v)) {
      for (const item of v) {
        if (item && typeof item === "object") out.push({ name: k, ...item });
        else out.push({ name: k });
      }
    } else if (v && typeof v === "object") {
      out.push({ name: k, ...v });
    } else {
      out.push({ name: k });
    }
  }
  return out;
}
function mapMetric(row) {
  return {
    metricName: String(row.metricName || row.name || row.metric || ""),
    description: String(row.description || row.desc || ""),
    type: String(row.type || row.metricType || ""),
    unit: String(row.unit || ""),
    temporality: String(row.temporality || ""),
    isMonotonic: Boolean(row.isMonotonic)
  };
}
function mapField(row) {
  return {
    name: String(row.name || row.key || row.attributeKey || ""),
    fieldDataType: String(
      row.fieldDataType || row.dataType || "string"
    ).toLowerCase() || "string",
    fieldContext: String(row.fieldContext || row.type || "tag").toLowerCase() || "tag"
  };
}
function mapStringValues(rows) {
  return rows.map(
    (r) => typeof r === "string" || typeof r === "number" ? String(r) : String(r?.value ?? r?.name ?? r?.serviceName ?? "")
  ).filter(Boolean);
}
function createSigNozMetadataApi(opts) {
  const cache = opts.cache || sharedSigNozMetadataCache;
  const ttlMs = opts.ttlMs ?? 3e5;
  const profile = opts.profile;
  const profileId = String(profile.id);
  async function liveHttp(req) {
    if (!opts.http) {
      throw new DataSourceError(
        "UNSUPPORTED_CAPABILITY",
        "SigNoz metadata http 未注入"
      );
    }
    try {
      return await opts.http(req);
    } catch (e) {
      const msg = e instanceof Error ? e.message : String(e);
      const code = e instanceof DataSourceError ? e.code : void 0;
      if (code === "AUTH_REQUIRED" || code === "AUTH_REJECTED" || /401|403/.test(msg)) {
        cache.clearUid(opts.identity.uid);
      }
      throw e;
    }
  }
  async function cachedGet(method, path, params, signal, loader) {
    const key = {
      ...opts.identity,
      method,
      path,
      paramsHash: hashParams(params)
    };
    const hit = cache.get(key);
    if (hit !== void 0) return hit;
    try {
      const value = await loader();
      if (signal?.aborted) throw new DOMException("Aborted", "AbortError");
      cache.set(key, value, ttlMs);
      return value;
    } catch (e) {
      throw e;
    }
  }
  function endpointOrThrow(kind, label) {
    const ep = profile.endpoints[kind] || (kind === "metricsList" ? profile.endpoints.metadata : void 0) || (kind === "fieldsKeys" ? profile.endpoints.attributeKeys : void 0) || (kind === "fieldsValues" ? profile.endpoints.attributeValues : void 0);
    if (!ep?.path) {
      throw new DataSourceError(
        "UNSUPPORTED_CAPABILITY",
        `profile ${profileId} 未定义 ${label} endpoint（禁止假空列表）`
      );
    }
    return ep;
  }
  return {
    async getMetadata(request, signal) {
      if (opts.offline) return offlineMetadata(request);
      switch (request.type) {
        case "metrics": {
          const ep = endpointOrThrow("metricsList", "metrics");
          const values = await cachedGet(
            "GET",
            ep.path,
            { search: request.search || "" },
            signal,
            async () => {
              const res = await liveHttp({
                path: ep.path,
                method: ep.method || "GET",
                query: request.search ? { search: request.search } : void 0,
                signal
              });
              return asArray(res.data).map(mapMetric).filter((m) => m.metricName);
            }
          );
          const filtered = request.search ? values.filter((m) => m.metricName.includes(request.search)) : values;
          return { type: "metrics", values: filtered };
        }
        case "attributeKeys": {
          const ep = profile.endpoints.fieldsKeys || profile.endpoints.attributeKeys || endpointOrThrow("fieldsKeys", "fields/keys");
          const path = ep.path;
          const useMetricAttrs = request.metricName && profileId.startsWith("signoz") ? { path: "/api/v2/metrics/attributes", method: "GET" } : { path, method: ep.method || "GET" };
          const values = await cachedGet(
            useMetricAttrs.method,
            useMetricAttrs.path,
            {
              signal: request.signal,
              metricName: request.metricName || "",
              search: request.search || ""
            },
            signal,
            async () => {
              const res = await liveHttp({
                path: useMetricAttrs.path,
                method: useMetricAttrs.method,
                query: {
                  ...request.signal ? { dataSource: request.signal } : {},
                  ...request.metricName ? { metricName: request.metricName } : {},
                  ...request.search ? { search: request.search } : {}
                },
                signal
              });
              return asArray(res.data).map(mapField).filter((f) => f.name);
            }
          );
          return { type: "attributeKeys", values };
        }
        case "attributeValues": {
          const ep = profile.endpoints.fieldsValues || profile.endpoints.attributeValues;
          if (!ep?.path) {
            throw new DataSourceError(
              "UNSUPPORTED_CAPABILITY",
              `profile ${profileId} 未定义 fields/values endpoint`
            );
          }
          const values = await cachedGet(
            ep.method || "GET",
            ep.path,
            {
              key: request.key,
              signal: request.signal,
              search: request.search || ""
            },
            signal,
            async () => {
              const res = await liveHttp({
                path: ep.path,
                method: ep.method || "GET",
                query: {
                  fieldName: request.key,
                  name: request.key,
                  ...request.signal ? { dataSource: request.signal } : {},
                  ...request.search ? { search: request.search } : {}
                },
                signal
              });
              return mapStringValues(asArray(res.data));
            }
          );
          return { type: "attributeValues", values };
        }
        case "services": {
          const ep = profile.endpoints.services || profile.endpoints.fieldsValues || profile.endpoints.attributeValues;
          if (!ep?.path) {
            throw new DataSourceError(
              "UNSUPPORTED_CAPABILITY",
              `profile ${profileId} 未定义 services endpoint`
            );
          }
          const values = await cachedGet(
            ep.method || "GET",
            ep.path,
            { kind: "services", search: request.search || "", path: ep.path },
            signal,
            async () => {
              const isPost = (ep.method || "GET").toUpperCase() === "POST" || ep.path.includes("/v2/services");
              try {
                const endNs = String(Date.now()) + "000000";
                const startNs = String(Date.now() - 36e5) + "000000";
                const res = await liveHttp({
                  path: ep.path,
                  method: isPost ? "POST" : ep.method || "GET",
                  ...isPost ? {
                    body: {
                      start: startNs,
                      end: endNs,
                      tags: [],
                      ...request.search ? { search: request.search } : {}
                    }
                  } : {
                    query: {
                      fieldName: "service.name",
                      name: "service.name",
                      dataSource: "traces",
                      ...request.search ? { search: request.search } : {}
                    }
                  },
                  signal
                });
                return mapStringValues(asArray(res.data));
              } catch (e) {
                if (isPost && profile.endpoints.fieldsValues?.path) {
                  const fb = profile.endpoints.fieldsValues;
                  const res = await liveHttp({
                    path: fb.path,
                    method: fb.method || "GET",
                    query: {
                      fieldName: "service.name",
                      name: "service.name",
                      dataSource: "traces",
                      ...request.search ? { search: request.search } : {}
                    },
                    signal
                  });
                  return mapStringValues(asArray(res.data));
                }
                throw e;
              }
            }
          );
          const filtered = request.search ? values.filter((s) => s.includes(String(request.search))) : values;
          return { type: "services", values: filtered };
        }
        case "operations": {
          const ep = profile.endpoints.fieldsValues || profile.endpoints.attributeValues;
          if (!ep?.path) {
            throw new DataSourceError(
              "UNSUPPORTED_CAPABILITY",
              `profile ${profileId} 未定义 operations endpoint`
            );
          }
          if (!request.service) {
            throw new DataSourceError(
              "INVALID_QUERY",
              "operations 需要 service filter"
            );
          }
          const values = await cachedGet(
            ep.method || "GET",
            ep.path,
            {
              key: "name",
              service: request.service,
              search: request.search || ""
            },
            signal,
            async () => {
              const res = await liveHttp({
                path: ep.path,
                method: ep.method || "GET",
                query: {
                  fieldName: "name",
                  name: "name",
                  dataSource: "traces",
                  service: request.service,
                  "service.name": request.service,
                  ...request.search ? { search: request.search } : {}
                },
                signal
              });
              return mapStringValues(asArray(res.data));
            }
          );
          return { type: "operations", values };
        }
        case "traceById": {
          const ep = profile.endpoints.traceById;
          if (!ep?.path) {
            throw new DataSourceError(
              "UNSUPPORTED_CAPABILITY",
              `profile ${profileId} 未定义 traceById`
            );
          }
          const path = ep.path.replace(
            "{id}",
            encodeURIComponent(request.traceId)
          );
          const res = await liveHttp({
            path,
            method: ep.method || "GET",
            signal
          });
          return {
            type: "traceById",
            frames: [
              createDataFrame({
                fields: [
                  {
                    name: "payload",
                    type: "string",
                    values: [JSON.stringify(res.data)]
                  }
                ],
                meta: { signal: "traces" }
              })
            ]
          };
        }
        case "relatedLogs": {
          const logsPath = profile.endpoints.logsQuery?.path || profile.endpoints.metricsQuery?.path;
          if (!logsPath) {
            throw new DataSourceError(
              "UNSUPPORTED_CAPABILITY",
              "related logs 需要 logs query_range"
            );
          }
          const frames = await fetchRelatedLogs({
            traceId: request.traceId,
            fromMs: request.fromMs,
            toMs: request.toMs,
            http: async (req) => {
              const res = await liveHttp({
                path: req.path,
                method: req.method,
                body: req.body,
                signal: req.signal
              });
              return { status: Number(res.status ?? 200), data: res.data };
            },
            logsQueryPath: logsPath,
            signal
          });
          return { type: "relatedLogs", frames };
        }
        case "alerts": {
          const ep = profile.endpoints.alertsQuery;
          if (!ep?.path) {
            throw new DataSourceError(
              "UNSUPPORTED_CAPABILITY",
              `alerts 需要 alertsQuery capability 证据，当前不返回假空`
            );
          }
          const res = await liveHttp({
            path: ep.path,
            method: ep.method || "GET",
            query: (ep.method || "GET").toUpperCase() === "GET" ? {
              ...request.service ? { service: request.service } : {},
              ...request.environment ? { environment: request.environment } : {}
            } : void 0,
            body: (ep.method || "GET").toUpperCase() === "POST" ? {
              start: request.fromMs,
              end: request.toMs,
              service: request.service,
              environment: request.environment,
              severities: request.severities
            } : void 0,
            signal
          });
          const rows = asArray(res.data);
          const frames = mapAlertsResponse(
            { data: rows.length ? rows : res.data },
            { refId: "alerts" }
          );
          return { type: "alerts", frames };
        }
        default:
          throw new DataSourceError("INVALID_QUERY", `未知 metadata 请求`);
      }
    }
  };
}
function offlineMetadata(request) {
  switch (request.type) {
    case "metrics":
      return {
        type: "metrics",
        values: OFFLINE_METRICS.filter(
          (m) => !request.search || m.metricName.includes(request.search)
        )
      };
    case "services":
      return {
        type: "services",
        values: OFFLINE_SERVICES.filter(
          (s) => !request.search || s.includes(String(request.search))
        )
      };
    case "operations":
      return { type: "operations", values: ["HTTP GET", "HTTP POST", "gRPC"] };
    case "attributeKeys":
      return {
        type: "attributeKeys",
        values: [
          {
            name: "service.name",
            fieldDataType: "string",
            fieldContext: "resource"
          },
          {
            name: "http.status_code",
            fieldDataType: "int64",
            fieldContext: "tag"
          }
        ]
      };
    case "attributeValues":
      return { type: "attributeValues", values: ["prod", "staging"] };
    case "traceById": {
      const frames = [
        createDataFrame({
          fields: [
            { name: "spanId", values: ["root"] },
            { name: "name", values: ["GET /"] },
            { name: "service", values: ["frontend"] }
          ],
          meta: { signal: "traces" }
        })
      ];
      return { type: "traceById", frames };
    }
    case "relatedLogs":
      return {
        type: "relatedLogs",
        frames: [
          createDataFrame({
            fields: [
              { name: "Time", type: "time", values: [request.fromMs] },
              {
                name: "Line",
                type: "string",
                values: ["offline error log line"]
              },
              { name: "service", type: "string", values: ["frontend"] },
              { name: "severity", type: "string", values: ["error"] },
              { name: "traceId", type: "string", values: [request.traceId] },
              { name: "spanId", type: "string", values: ["span-offline"] }
            ],
            meta: {
              signal: "logs",
              source: "fixture",
              relatedTraceId: request.traceId
            }
          })
        ]
      };
    case "alerts":
      return {
        type: "alerts",
        frames: [
          createDataFrame({
            fields: [
              { name: "id", values: ["al-1"] },
              { name: "title", values: ["High error rate"] },
              { name: "service", values: [request.service || "api"] },
              { name: "severity", values: ["critical"] },
              { name: "status", values: ["firing"] },
              { name: "Time", values: [request.fromMs] },
              { name: "alertId", values: ["al-1"] }
            ],
            meta: { signal: "alerts" }
          })
        ]
      };
    default:
      throw new DataSourceError(
        "INVALID_QUERY",
        "unknown offline metadata request"
      );
  }
}
const REQUEST_TO_PANEL = {
  time_series: "graph",
  scalar: "value",
  raw: "list",
  raw_stream: "list",
  trace: "trace",
  distribution: "histogram"
};
const V3_OP_MAP = {
  "=": "=",
  "!=": "!=",
  in: "in",
  nin: "nin",
  contains: "contains",
  ncontains: "ncontains",
  regex: "regex",
  nregex: "nregex",
  like: "like",
  nlike: "nlike",
  exists: "exists",
  nexists: "nexists",
  has: "has",
  nhas: "nhas",
  ">": ">",
  ">=": ">=",
  "<": "<",
  "<=": "<=",
  "=~": "regex",
  "!~": "nregex"
};
function exprToV3Filters(expression) {
  const expr = String(expression || "").trim();
  if (!expr) return { items: [], op: "AND" };
  if (/\(|\)/.test(expr)) return { error: "complex_parens" };
  if (/\bOR\b/i.test(expr) && /\bAND\b/i.test(expr))
    return { error: "mixed_and_or" };
  const op = /\bOR\b/i.test(expr) ? "OR" : "AND";
  const parts = expr.split(/\bAND\b|\bOR\b/i).map((s) => s.trim()).filter(Boolean);
  const items = [];
  for (const part of parts) {
    const m = part.match(
      /^([a-zA-Z0-9_./-]+)\s*(!=|=~|!~|>=|<=|=|>|<|contains|ncontains|in|nin|regex|nregex|like|nlike|exists|nexists|has|nhas)\s*(.*)$/i
    );
    if (!m) return { error: `unsupported_clause:${part}` };
    const key = m[1];
    const rawOp = m[2];
    let valueRaw = m[3].trim();
    const mapped = V3_OP_MAP[rawOp] || V3_OP_MAP[rawOp.toLowerCase()] || rawOp;
    if (mapped === "exists" || mapped === "nexists") {
      items.push({
        key: { key, type: "tag", dataType: "string" },
        op: mapped,
        value: true
      });
      continue;
    }
    if (valueRaw.startsWith("'") && valueRaw.endsWith("'") || valueRaw.startsWith('"') && valueRaw.endsWith('"')) {
      valueRaw = valueRaw.slice(1, -1);
    }
    let value = valueRaw;
    if (mapped === "in" || mapped === "nin") {
      value = valueRaw.split(",").map((s) => s.trim().replace(/^['"]|['"]$/g, ""));
    }
    items.push({
      key: { key, type: "tag", dataType: "string" },
      op: mapped,
      value
    });
  }
  return { items, op };
}
function fieldToAttr(f) {
  return {
    key: f.name,
    type: f.fieldContext === "resource" ? "resource" : "tag",
    dataType: f.fieldDataType === "float64" || f.fieldDataType === "int64" ? f.fieldDataType : "string"
  };
}
function primaryAgg(spec) {
  return spec.aggregations && spec.aggregations[0] || {};
}
function specToV3Builder(spec, version = "v3") {
  const agg = primaryAgg(spec);
  const metricName = agg.metricName || "";
  const aggregateOperator = (agg.spaceAggregation || agg.timeAggregation || "count").toLowerCase();
  const filterParsed = exprToV3Filters(spec.filter?.expression || "");
  const filters = "error" in filterParsed ? {
    items: [],
    op: "AND",
    _conversionError: filterParsed.error
  } : { items: filterParsed.items, op: filterParsed.op };
  const groupBy = (spec.groupBy || []).map(fieldToAttr);
  const orderBy = (spec.order || []).map((o) => ({
    columnName: o.key?.name || "",
    order: o.direction || "asc"
  }));
  const having = [];
  const havingExpr = String(spec.having?.expression || "").trim();
  if (havingExpr) {
    const hm = havingExpr.match(/^(.+?)\s*(>=|<=|!=|=|>|<)\s*(.+)$/);
    if (hm) {
      having.push({
        columnName: hm[1].trim(),
        op: hm[2],
        value: hm[3].trim().replace(/^['"]|['"]$/g, "")
      });
    }
  }
  const out = {
    dataSource: spec.signal,
    aggregateOperator,
    aggregateAttribute: {
      key: metricName,
      type: agg.metricType || "",
      dataType: "float64"
    },
    filters: {
      items: filters.items,
      op: filters.op
    },
    groupBy,
    orderBy,
    having,
    legend: spec.legend || "",
    disabled: Boolean(spec.disabled),
    reduceTo: agg.reduceTo || "avg",
    limit: spec.limit,
    stepInterval: spec.stepInterval
  };
  if (version === "v4") {
    out.timeAggregation = agg.timeAggregation || "rate";
    out.spaceAggregation = agg.spaceAggregation || "sum";
  }
  if (spec.functions?.length) {
    out.functions = spec.functions.map((f) => ({
      name: f.name,
      args: normalizeFunctionArgs(String(f.name || ""), f.args)
    }));
  }
  const lb = spec.limitBy;
  if (lb) {
    if (Array.isArray(lb) && lb.length) {
      const keys = lb.map((x) => x?.key || x).filter(Boolean);
      const value = lb[0]?.value != null ? Number(lb[0].value) : void 0;
      out.limitBy = { keys, value };
    } else if (typeof lb === "object" && Array.isArray(lb.keys) && lb.keys.length) {
      out.limitBy = {
        keys: lb.keys.map(String),
        value: lb.value != null ? Number(lb.value) : void 0
      };
    }
  }
  if ("error" in filterParsed) {
    out._filterConversionError = filterParsed.error;
  }
  return out;
}
function requestTypeToPanelType(requestType, signal, opts) {
  if (requestType === "scalar") {
    return opts?.formatTable ? "table" : "value";
  }
  if (requestType === "trace" || signal === "traces") return "trace";
  return REQUEST_TO_PANEL[requestType] || "graph";
}
function isBareMetricsOp(expr) {
  const e = expr.trim().toLowerCase();
  return Boolean(e) && !e.includes("(") && /^(avg|sum|min|max|count|rate|increase|last|p\d+)$/.test(e);
}
function optString(v) {
  if (v == null) return void 0;
  const s = String(v);
  return s === "" ? void 0 : s;
}
function toV5MetricAggregation(a, metricMetadata) {
  const metricName = String(a.metricName || "");
  const expr = a.expression != null ? String(a.expression) : "";
  const simple = expr && !expr.includes("(");
  const timeAggregation = String(
    a.timeAggregation || (simple ? expr : "") || "avg"
  );
  const temporality = String(
    a.temporality || metricMetadata?.get(metricName)?.temporality || "Unspecified"
  ) || "Unspecified";
  const out = {
    metricName,
    temporality,
    timeAggregation,
    spaceAggregation: String(a.spaceAggregation || "avg")
  };
  const reduceTo = optString(a.reduceTo);
  const alias = optString(a.alias);
  if (reduceTo) out.reduceTo = reduceTo;
  if (alias) out.alias = alias;
  if (expr && expr.includes("(")) out.expression = expr;
  return out;
}
function toV5ExpressionAggregation(a) {
  let expression = a.expression != null && String(a.expression).trim() ? String(a.expression).trim() : "";
  if (!expression && a.timeAggregation && String(a.timeAggregation).includes("(")) {
    expression = String(a.timeAggregation).trim();
  }
  if (!expression || isBareMetricsOp(expression)) {
    expression = "count()";
  }
  const out = { expression };
  const alias = optString(a.alias);
  const reduceTo = optString(a.reduceTo);
  if (alias) out.alias = alias;
  if (reduceTo) out.reduceTo = reduceTo;
  return out;
}
function normalizeFilterExpression(expression) {
  if (expression == null) return "";
  let s = String(expression).trim();
  if (!s) return "";
  const vacuousEq = /(?:^|\s+)([A-Za-z_][\w./-]*)\s*(?:=|!=|LIKE|NOT_LIKE|ILIKE)\s*(?:''|"")(?=\s|$|\))/gi;
  s = s.replace(vacuousEq, " ").replace(/\(\s*\)/g, " ").replace(/\s+(AND|OR)\s+(AND|OR)\s+/gi, " $1 ").replace(/^\s*(?:AND|OR)\s+/i, "").replace(/\s+(?:AND|OR)\s*$/i, "").replace(/\s+/g, " ").trim();
  return s;
}
const LIST_ONLY_ORDER_KEYS = /* @__PURE__ */ new Set(["timestamp", "id"]);
function isAggregationRequestType(requestType) {
  if (requestType === "raw" || requestType === "trace" || requestType === "raw_stream") {
    return false;
  }
  return true;
}
function orderKeyName(entry) {
  if (entry == null) return "";
  if (typeof entry === "string") return entry.trim();
  const o = entry;
  const key = o.key;
  if (key && typeof key === "object") {
    return String(key.name ?? key.key ?? "").trim();
  }
  return String(o.columnName ?? o.name ?? o.key ?? "").trim();
}
function groupByName(entry) {
  if (entry == null) return "";
  if (typeof entry === "string") return entry.trim();
  const o = entry;
  return String(o.name ?? o.key?.name ?? o.key ?? "").trim();
}
function sanitizeV5Order(order, opts) {
  if (!Array.isArray(order) || order.length === 0) return void 0;
  if (!isAggregationRequestType(opts.requestType)) {
    return order;
  }
  const groupByNames = new Set(
    (opts.groupBy || []).map(groupByName).filter(Boolean)
  );
  const aggKeys = /* @__PURE__ */ new Set();
  (opts.aggregations || []).forEach((a, i) => {
    aggKeys.add(String(i));
    if (a?.alias != null && String(a.alias).trim()) {
      aggKeys.add(String(a.alias).trim());
    }
    if (a?.expression != null && String(a.expression).trim()) {
      aggKeys.add(String(a.expression).trim());
    }
  });
  const filtered = order.filter((entry) => {
    const name = orderKeyName(entry);
    if (!name) return false;
    if (LIST_ONLY_ORDER_KEYS.has(name)) return false;
    if (groupByNames.has(name)) return true;
    if (aggKeys.has(name)) return true;
    if (/^\d+$/.test(name)) return true;
    if (name.includes("(")) return true;
    return false;
  });
  return filtered.length ? filtered : void 0;
}
function toV5BuilderSpec(spec, opts) {
  const signal = spec.signal || "metrics";
  const requestType = opts?.requestType;
  const rawAggs = Array.isArray(spec.aggregations) ? spec.aggregations : [];
  const aggregations = rawAggs.map((a) => {
    if (signal === "metrics" && a?.metricName) {
      return toV5MetricAggregation(a, opts?.metricMetadata);
    }
    if (signal === "metrics") {
      if (a?.timeAggregation || a?.spaceAggregation) {
        return {
          ...optString(a?.expression) ? { expression: String(a.expression) } : {},
          ...a?.timeAggregation ? { timeAggregation: String(a.timeAggregation) } : {},
          ...a?.spaceAggregation ? { spaceAggregation: String(a.spaceAggregation) } : {},
          ...optString(a?.reduceTo) ? { reduceTo: String(a.reduceTo) } : {},
          ...optString(a?.alias) ? { alias: String(a.alias) } : {}
        };
      }
      return toV5ExpressionAggregation(a || {});
    }
    return toV5ExpressionAggregation(a || {});
  });
  const filterObj = spec.filter && typeof spec.filter === "object" ? spec.filter : {};
  const havingObj = spec.having && typeof spec.having === "object" ? spec.having : {};
  const groupBy = Array.isArray(spec.groupBy) && spec.groupBy.length ? spec.groupBy : void 0;
  const out = {
    name: String(spec.name || "A"),
    signal,
    // null means auto step — must be preserved
    stepInterval: spec.stepInterval === void 0 ? null : spec.stepInterval,
    filter: {
      expression: normalizeFilterExpression(filterObj.expression)
    },
    having: {
      expression: normalizeFilterExpression(havingObj.expression)
    },
    aggregations
  };
  if (spec.disabled) out.disabled = true;
  if (groupBy) out.groupBy = groupBy;
  const sanitizedOrder = sanitizeV5Order(
    Array.isArray(spec.order) ? spec.order : void 0,
    {
      requestType,
      groupBy,
      aggregations
    }
  );
  if (sanitizedOrder) {
    out.order = sanitizedOrder;
  } else if (requestType === "raw" || requestType === "trace" || requestType === "raw_stream") {
    out.order = [{ key: { name: "timestamp" }, direction: "desc" }];
  }
  if (spec.limit != null && spec.limit !== "") out.limit = Number(spec.limit);
  if (spec.offset != null && spec.offset !== "")
    out.offset = Number(spec.offset);
  if (optString(spec.legend)) out.legend = String(spec.legend);
  if (Array.isArray(spec.functions) && spec.functions.length)
    out.functions = spec.functions;
  if (optString(spec.source)) out.source = String(spec.source);
  if (Array.isArray(spec.selectColumns) && spec.selectColumns.length)
    out.selectColumns = spec.selectColumns;
  if (Array.isArray(spec.selectFields) && spec.selectFields.length) {
    out.selectFields = spec.selectFields;
  }
  return out;
}
function toV5PromqlSpec(name, query, legend) {
  const out = {
    name,
    query,
    disabled: false
  };
  if (legend) out.legend = legend;
  return out;
}
function toV5ClickHouseSpec(name, query) {
  return {
    name,
    query,
    disabled: false
  };
}
function isDisabled(item) {
  if (item.type === "builder_formula") return Boolean(item.spec.disabled);
  if (item.type === "builder_query") return Boolean(item.spec.disabled);
  if (item.type === "builder_trace_operator")
    return Boolean(item.spec.disabled);
  if (item.type === "builder_sub_query") return Boolean(item.spec.disabled);
  if (item.type === "builder_join") return Boolean(item.spec.disabled);
  return false;
}
function parseFormulaDeps(expression) {
  const names = expression.match(/\b[A-Z][A-Z0-9_]*\b/g) || [];
  return [...new Set(names)];
}
function endpointFor(profile, signal) {
  if (signal === "logs") return profile.endpoints.logsQuery;
  if (signal === "traces") return profile.endpoints.tracesQuery;
  return profile.endpoints.metricsQuery;
}
function stripEmpty(obj) {
  if (Array.isArray(obj))
    return obj.map(stripEmpty).filter((v) => v !== void 0);
  if (obj && typeof obj === "object") {
    const out = {};
    for (const [k, v] of Object.entries(obj)) {
      if (v == null) continue;
      if (typeof v === "string" && v === "") continue;
      if (Array.isArray(v) && v.length === 0) continue;
      if (k === "metricType") continue;
      out[k] = stripEmpty(v);
    }
    return out;
  }
  return obj;
}
function normalizeBuilderAggregation(a, signal, metricMetadata) {
  if (!a || typeof a !== "object") return a;
  if (signal === "metrics") {
    if (a.metricName) {
      return toV5MetricAggregation(a, metricMetadata);
    }
    const out = {};
    if (a.expression != null && String(a.expression) !== "")
      out.expression = a.expression;
    if (a.timeAggregation != null) out.timeAggregation = a.timeAggregation;
    if (a.spaceAggregation != null) out.spaceAggregation = a.spaceAggregation;
    if (a.reduceTo != null && a.reduceTo !== "") out.reduceTo = a.reduceTo;
    if (a.alias != null && a.alias !== "") out.alias = a.alias;
    return out;
  }
  return toV5ExpressionAggregation(a);
}
function resolveRequestType(query, caps2) {
  const rt = query.requestType || "time_series";
  if (rt === "distribution") {
    if (!caps2?.distribution && !query.apiProfile) ;
  }
  return rt;
}
function assertRequestTypeAllowed(rt, options, caps2) {
  if (rt === "distribution") {
    const ok2 = Boolean(
      caps2?.distribution || options.experimentalCapabilities?.distribution
    );
    if (!ok2) {
      throw new DataSourceError(
        "UNSUPPORTED_CAPABILITY",
        "distribution requestType 需要 experimentalDistribution capability"
      );
    }
  }
}
function assertGatedItems(items, options, caps2) {
  for (const item of items) {
    if (item.type === "builder_sub_query") {
      const ok2 = Boolean(
        caps2?.builderSubQuery || options.experimentalCapabilities?.builderSubQuery
      );
      if (!ok2) {
        throw new DataSourceError(
          "UNSUPPORTED_CAPABILITY",
          "builder_sub_query 默认禁用，需当前 deployment capability"
        );
      }
    }
    if (item.type === "builder_join") {
      const ok2 = Boolean(
        caps2?.builderJoin || options.experimentalCapabilities?.builderJoin
      );
      if (!ok2) {
        throw new DataSourceError(
          "UNSUPPORTED_CAPABILITY",
          "builder_join 默认禁用，需当前 deployment capability"
        );
      }
    }
  }
}
function toTypeSpecItem(item, metricMetadata, requestType) {
  if (item.type === "builder_query") {
    if (item.queryType === "promql") {
      const queryText = String(item.rawQuery ?? "").trim();
      if (!queryText) {
        throw new DataSourceError(
          "INVALID_QUERY",
          `PromQL 查询表达式不能为空（${item.spec.name}）。请填写如 up 的表达式，或切回 Builder。`
        );
      }
      const spec2 = toV5PromqlSpec(
        item.spec.name,
        queryText,
        item.rawLegend || item.spec.legend
      );
      spec2.disabled = Boolean(item.spec.disabled);
      if (item.step) spec2.step = item.step;
      if (item.stats != null) spec2.stats = item.stats;
      return { type: "promql", spec: spec2 };
    }
    if (item.queryType === "clickhouse_sql") {
      const queryText = String(item.rawQuery ?? "").trim();
      if (!queryText) {
        throw new DataSourceError(
          "INVALID_QUERY",
          `ClickHouse SQL 不能为空（${item.spec.name}）`
        );
      }
      const spec2 = toV5ClickHouseSpec(item.spec.name, queryText);
      spec2.disabled = Boolean(item.spec.disabled);
      if (item.rawLegend || item.spec.legend) {
        spec2.legend = item.rawLegend || item.spec.legend;
      }
      return { type: "clickhouse_sql", spec: spec2 };
    }
    const signal = String(item.spec.signal || "metrics");
    const withAggs = {
      ...item.spec,
      signal,
      aggregations: item.spec.aggregations?.length ? item.spec.aggregations : defaultAggregationsForSignal(signal)
    };
    const spec = toV5BuilderSpec(withAggs, {
      metricMetadata,
      requestType
    });
    spec.aggregations = withAggs.aggregations.map(
      (a) => normalizeBuilderAggregation(a, signal, metricMetadata)
    );
    spec.disabled = Boolean(item.spec.disabled);
    if (signal !== "metrics") {
      delete spec.source;
    }
    return {
      type: "builder_query",
      spec
    };
  }
  if (item.type === "builder_formula") {
    const formulaSpec = {
      name: item.spec.name,
      expression: item.spec.expression,
      disabled: Boolean(item.spec.disabled)
    };
    if (item.spec.limit != null) formulaSpec.limit = item.spec.limit;
    if (item.spec.legend) formulaSpec.legend = item.spec.legend;
    if (item.spec.order) formulaSpec.order = item.spec.order;
    return {
      type: "builder_formula",
      spec: formulaSpec
    };
  }
  if (item.type === "builder_trace_operator") {
    return {
      type: "builder_trace_operator",
      spec: toV5BuilderSpec(item.spec, { requestType })
    };
  }
  if (item.type === "builder_sub_query") {
    return {
      type: "builder_sub_query",
      spec: toV5BuilderSpec(
        {
          ...item.spec,
          signal: item.spec.signal || "traces"
        },
        { requestType }
      )
    };
  }
  if (item.type === "builder_join") {
    return {
      type: "builder_join",
      spec: {
        ...toV5BuilderSpec(
          {
            ...item.spec,
            signal: item.spec.signal || "traces"
          },
          { requestType }
        ),
        // join-specific whitelist
        ...item.spec.on != null ? { on: item.spec.on } : {},
        ...item.spec.joinType != null ? { joinType: item.spec.joinType } : {},
        ...item.spec.left != null ? { left: item.spec.left } : {},
        ...item.spec.right != null ? { right: item.spec.right } : {}
      }
    };
  }
  throw new DataSourceError("INVALID_QUERY", `未知 query item type`);
}
function primarySignal(items) {
  for (const item of items) {
    if (item.type === "builder_query") return item.spec.signal;
  }
  return "metrics";
}
function buildSigNozRequests(input) {
  const {
    profile,
    options,
    query,
    fromMs,
    toMs: toMs2,
    intervalMs,
    metricMetadata,
    capabilities
  } = input;
  const stepSec = Math.max(1, Math.round((intervalMs || 6e4) / 1e3));
  const items = (query.queries || []).filter((q) => !isDisabled(q));
  const caps2 = {
    builderSubQuery: capabilities?.builderSubQuery ?? options.experimentalCapabilities?.builderSubQuery,
    builderJoin: capabilities?.builderJoin ?? options.experimentalCapabilities?.builderJoin,
    distribution: capabilities?.distribution ?? options.experimentalCapabilities?.distribution
  };
  assertGatedItems(items, options, caps2);
  const formulas = items.filter((i) => i.type === "builder_formula");
  const queries = items.filter((i) => i.type === "builder_query");
  const out = [];
  if (profile.id === "prometheus-compatible") {
    for (const q of queries) {
      if (q.queryType !== "promql") {
        throw new DataSourceError(
          "UNSUPPORTED_QUERY_API",
          `prometheus-compatible 不支持 ${q.queryType}`
        );
      }
      const expr = String(q.rawQuery || "");
      if (!profile.endpoints.metricsQuery) {
        throw new DataSourceError(
          "UNSUPPORTED_QUERY_API",
          "缺少 metrics endpoint"
        );
      }
      out.push({
        requestKey: `prom:${q.spec.name}`,
        queryNames: [q.spec.name],
        signal: "metrics",
        path: profile.endpoints.metricsQuery.path,
        method: profile.endpoints.metricsQuery.method || "GET",
        query: {
          query: expr,
          start: Math.floor(fromMs / 1e3),
          end: Math.floor(toMs2 / 1e3),
          step: stepSec,
          ...q.stats ? { stats: true } : {}
        }
      });
    }
    for (const f of formulas) {
      out.push({
        requestKey: `formula:${f.spec.name}`,
        queryNames: [f.spec.name],
        signal: "metrics",
        path: "",
        method: "GET",
        localFormula: {
          name: f.spec.name,
          expression: f.spec.expression,
          dependsOn: parseFormulaDeps(f.spec.expression)
        }
      });
    }
    return out;
  }
  if (profile.id === "signoz-v5") {
    if (!items.length) return out;
    const signal = primarySignal(items);
    const ep = endpointFor(profile, signal) || profile.endpoints.metricsQuery;
    if (!ep?.path) {
      throw new DataSourceError(
        "UNSUPPORTED_QUERY_API",
        `${profile.id} 缺少 query_range`
      );
    }
    const requestType = resolveRequestType(query, caps2);
    assertRequestTypeAllowed(requestType, options, caps2);
    const compositeQueries = items.map(
      (item) => toTypeSpecItem(item, metricMetadata, requestType)
    );
    const variables = {
      SIGNOZ_START: { value: String(fromMs) },
      SIGNOZ_END: { value: String(toMs2) }
    };
    if (options.organizationId)
      variables.SIGNOZ_ORGANIZATION_ID = { value: options.organizationId };
    if (options.defaultEnvironment)
      variables.SIGNOZ_ENVIRONMENT = { value: options.defaultEnvironment };
    const formatOptions = {
      formatTableResultForUI: Boolean(
        query.formatOptions?.formatTableResultForUI
      ),
      fillGaps: query.formatOptions?.fillGaps === true
      // default false
    };
    const body = {
      schemaVersion: "v1",
      start: fromMs,
      end: toMs2,
      requestType,
      compositeQuery: { queries: compositeQueries },
      formatOptions,
      variables
    };
    if (query.noCache) body.noCache = true;
    out.push({
      requestKey: `${profile.id}:composite`,
      queryNames: items.map((i) => i.spec?.name || i.type),
      signal,
      path: ep.path,
      method: ep.method || "POST",
      body
    });
    return out;
  }
  const groups = /* @__PURE__ */ new Map();
  for (const q of queries) {
    const key = `${q.spec.signal}:${q.queryType}`;
    const arr = groups.get(key) || [];
    arr.push(q);
    groups.set(key, arr);
  }
  for (const [key, group] of groups) {
    const signal = group[0].spec.signal;
    const mode2 = group[0].queryType;
    const ep = endpointFor(profile, signal);
    if (!ep?.path) {
      throw new DataSourceError(
        "UNSUPPORTED_QUERY_API",
        `profile ${profile.id} 未配置 ${signal} endpoint`
      );
    }
    const builderQueries = {};
    const promQueries = {};
    const chQueries = {};
    for (const q of group) {
      if (mode2 === "promql") {
        promQueries[q.spec.name] = {
          query: q.rawQuery || "",
          disabled: false,
          legend: q.rawLegend || q.spec.legend || ""
        };
      } else if (mode2 === "clickhouse_sql") {
        chQueries[q.spec.name] = {
          query: q.rawQuery || "",
          disabled: false,
          legend: q.rawLegend || ""
        };
      } else {
        const version = profile.id === "signoz-v4" ? "v4" : "v3";
        builderQueries[q.spec.name] = stripEmpty(
          specToV3Builder(q.spec, version)
        );
      }
    }
    const requestType = resolveRequestType(query, caps2);
    const compositeQuery = {
      queryType: mode2 === "promql" ? "promql" : mode2 === "clickhouse_sql" ? "clickhouse_sql" : "builder",
      panelType: requestTypeToPanelType(requestType, signal, {
        formatTable: Boolean(query.formatOptions?.formatTableResultForUI)
      })
    };
    if (Object.keys(builderQueries).length)
      compositeQuery.builderQueries = builderQueries;
    if (Object.keys(promQueries).length)
      compositeQuery.promQueries = promQueries;
    if (Object.keys(chQueries).length) compositeQuery.chQueries = chQueries;
    const body = {
      start: fromMs,
      end: toMs2,
      step: stepSec,
      compositeQuery
    };
    if (options.organizationId) body.organizationId = options.organizationId;
    if (options.defaultEnvironment)
      body.environment = options.defaultEnvironment;
    out.push({
      requestKey: `${profile.id}:${key}`,
      queryNames: group.map((g) => g.spec.name),
      signal,
      path: ep.path,
      method: ep.method || "POST",
      body: profile.id === "custom" ? {
        start: fromMs,
        end: toMs2,
        signal,
        queries: group.map((g) => stripEmpty({ ...g, spec: g.spec }))
      } : body
    });
  }
  for (const f of formulas) {
    out.push({
      requestKey: `formula:${f.spec.name}`,
      queryNames: [f.spec.name],
      signal: "metrics",
      path: "",
      method: "GET",
      localFormula: {
        name: f.spec.name,
        expression: f.spec.expression,
        dependsOn: parseFormulaDeps(f.spec.expression)
      }
    });
  }
  return out;
}
function asMetricFind(values) {
  return values.map((v) => ({ text: v, value: v }));
}
function withAllOption(values, includeAll) {
  if (!includeAll) return values;
  return ["__all__", ...values.filter((v) => v !== "__all__")];
}
async function runSigNozVariableQuery(api, query, opts = {}) {
  let q;
  if (typeof query === "string") {
    try {
      q = JSON.parse(query);
    } catch {
      q = { type: "service", search: query };
    }
  } else {
    q = query || { type: "service" };
  }
  const type = String(q.type || "service");
  const search = q.search != null ? String(q.search) : void 0;
  const includeAll = Boolean(
    q.includeAll || q.allValue === "__all__"
  );
  switch (type) {
    case "environment": {
      const res = await api.getMetadata(
        {
          type: "attributeValues",
          key: "deployment.environment",
          signal: "traces",
          search
        },
        opts.signal
      );
      const values = res.type === "attributeValues" ? res.values : [];
      return asMetricFind(withAllOption(values, includeAll));
    }
    case "service": {
      const res = await api.getMetadata(
        { type: "services", search },
        opts.signal
      );
      const values = res.type === "services" ? res.values : [];
      return asMetricFind(withAllOption(values, includeAll));
    }
    case "operation": {
      const service = String(q.service || "");
      if (!service) return [];
      const res = await api.getMetadata(
        { type: "operations", service, search },
        opts.signal
      );
      const values = res.type === "operations" ? res.values : [];
      return asMetricFind(withAllOption(values, includeAll));
    }
    case "metric": {
      const res = await api.getMetadata(
        { type: "metrics", search },
        opts.signal
      );
      const values = res.type === "metrics" ? res.values.map((m) => m.metricName) : [];
      return asMetricFind(withAllOption(values, includeAll));
    }
    case "attributeKey": {
      const signal = q.signal || "metrics";
      const res = await api.getMetadata(
        {
          type: "attributeKeys",
          signal,
          metricName: q.metricName,
          search
        },
        opts.signal
      );
      const values = res.type === "attributeKeys" ? res.values.map((f) => f.name) : [];
      return asMetricFind(withAllOption(values, includeAll));
    }
    case "attributeValue": {
      const key = String(q.key || "");
      if (!key) return [];
      const signal = q.signal || "metrics";
      const res = await api.getMetadata(
        { type: "attributeValues", key, signal, search },
        opts.signal
      );
      const values = res.type === "attributeValues" ? res.values : [];
      return asMetricFind(withAllOption(values, includeAll));
    }
    case "dynamic": {
      const key = String(q.field || q.key || "");
      const signal = q.source || q.signal || "metrics";
      if (!key) return [];
      const res = await api.getMetadata(
        { type: "attributeValues", key, signal, search },
        opts.signal
      );
      const values = res.type === "attributeValues" ? res.values : [];
      return asMetricFind(withAllOption(values, includeAll));
    }
    case "clickhouse_query": {
      const sql = String(q.query || q.sql || "").trim();
      if (!sql) return [];
      if (!opts.runClickHouseVariable) {
        throw new DataSourceError(
          "UNSUPPORTED_CAPABILITY",
          "ClickHouse 变量需要 variablesQuery endpoint（/api/v2/variables/query）"
        );
      }
      const values = await opts.runClickHouseVariable(sql, opts.signal);
      return asMetricFind(withAllOption(values, includeAll));
    }
    default:
      throw new DataSourceError("INVALID_QUERY", `未知变量类型 ${type}`);
  }
}
function emptyTypedFrame(signal, _uid) {
  return createDataFrame({
    fields: [
      { name: "Time", type: "time", values: [] },
      { name: "TimeEnd", type: "time", values: [] },
      { name: "Text", type: "string", values: [] },
      { name: "Tags", type: "string", values: [] },
      { name: "signal", type: "string", values: [] },
      { name: "traceId", type: "string", values: [] },
      { name: "spanId", type: "string", values: [] },
      { name: "alertId", type: "string", values: [] },
      { name: "DatasourceUid", type: "string", values: [] }
    ],
    meta: { signal, source: "annotation" }
  });
}
function fieldValues(frame, names) {
  for (const n of names) {
    const f = frame.fields.find(
      (x) => x.name === n || x.name.toLowerCase() === n.toLowerCase()
    );
    if (f?.values?.length) return f.values;
  }
  return [];
}
function normalizeToAnnotationFrames(frames, signal, uid, fallbackText) {
  if (!frames.length) return [emptyTypedFrame(signal)];
  const times = [];
  const ends = [];
  const texts = [];
  const tags = [];
  const signals = [];
  const traceIds = [];
  const spanIds = [];
  const alertIds = [];
  const uids = [];
  for (const fr of frames) {
    const n = Math.max(
      ...fr.fields.map((f) => f.values?.length || 0),
      0
    );
    const t = fieldValues(fr, ["Time", "time", "timestamp", "startTime"]);
    const te = fieldValues(fr, ["TimeEnd", "timeEnd", "endTime"]);
    const tx = fieldValues(fr, [
      "Text",
      "text",
      "title",
      "Line",
      "message",
      "name",
      "body"
    ]);
    const tg = fieldValues(fr, [
      "Tags",
      "tags",
      "service",
      "severity",
      "service.name"
    ]);
    const tr = fieldValues(fr, ["traceId", "trace_id", "TraceId"]);
    const sp = fieldValues(fr, ["spanId", "span_id", "SpanId"]);
    const al = fieldValues(fr, ["alertId", "id", "AlertId"]);
    for (let i = 0; i < n; i++) {
      times.push(Number(t[i] ?? Date.now()));
      ends.push(te[i] != null ? Number(te[i]) : null);
      texts.push(String(tx[i] ?? fallbackText));
      tags.push(String(tg[i] ?? ""));
      signals.push(signal);
      traceIds.push(String(tr[i] ?? ""));
      spanIds.push(String(sp[i] ?? ""));
      alertIds.push(String(al[i] ?? ""));
      uids.push(uid);
    }
  }
  if (!times.length) return [emptyTypedFrame(signal)];
  return [
    createDataFrame({
      fields: [
        { name: "Time", type: "time", values: times },
        { name: "TimeEnd", type: "time", values: ends },
        { name: "Text", type: "string", values: texts },
        { name: "Tags", type: "string", values: tags },
        { name: "signal", type: "string", values: signals },
        { name: "traceId", type: "string", values: traceIds },
        { name: "spanId", type: "string", values: spanIds },
        { name: "alertId", type: "string", values: alertIds },
        { name: "DatasourceUid", type: "string", values: uids }
      ],
      meta: { signal, source: "annotation" }
    })
  ];
}
function serviceFilter(service) {
  if (!service) return "";
  return `service.name = '${service.replace(/'/g, "\\'")}'`;
}
function andExpr(...parts) {
  return parts.filter(Boolean).join(" AND ");
}
async function querySigNozAnnotations(api, target, range, options) {
  const uid = options?.datasourceUid || "";
  const signal = options?.signal;
  const svc = target.service || "";
  if (target.source === "firingAlerts") {
    if (!options?.alertsCapable) {
      throw new DataSourceError(
        "UNSUPPORTED_CAPABILITY",
        "firing alerts 需要 alertsQuery capability（不生成占位 marker）"
      );
    }
    const res = await api.getMetadata(
      {
        type: "alerts",
        fromMs: range.fromMs,
        toMs: range.toMs,
        service: target.service,
        environment: target.environment
      },
      signal
    );
    return normalizeToAnnotationFrames(
      res.frames || [],
      "alerts",
      uid,
      "firing alert"
    );
  }
  if (target.source === "errorSpans") {
    const filter22 = andExpr("hasError = true", serviceFilter(svc));
    if (options?.runRawQuery) {
      const frames = await options.runRawQuery({
        signal: "traces",
        filterExpression: filter22 || "hasError = true",
        fromMs: range.fromMs,
        toMs: range.toMs,
        abort: signal
      });
      return normalizeToAnnotationFrames(frames, "traces", uid, "error span");
    }
    return [
      createDataFrame({
        fields: [
          { name: "Time", type: "time", values: [range.fromMs] },
          { name: "TimeEnd", type: "time", values: [range.toMs] },
          {
            name: "Text",
            type: "string",
            values: [svc ? `error span service=${svc}` : "error span"]
          },
          { name: "Tags", type: "string", values: [svc || "error"] },
          { name: "signal", type: "string", values: ["traces"] },
          { name: "traceId", type: "string", values: [""] },
          { name: "spanId", type: "string", values: [""] },
          { name: "alertId", type: "string", values: [""] },
          { name: "DatasourceUid", type: "string", values: [uid] }
        ],
        meta: {
          signal: "traces",
          source: "annotation",
          filter: {
            expression: filter22 || "hasError = true",
            service: svc || void 0
          },
          fromMs: range.fromMs,
          toMs: range.toMs,
          offline: true
        }
      })
    ];
  }
  const filter2 = andExpr(
    "(severity_text = 'ERROR' OR severity = 'ERROR' OR level = 'error')",
    serviceFilter(svc)
  );
  if (options?.runRawQuery) {
    const frames = await options.runRawQuery({
      signal: "logs",
      filterExpression: filter2,
      fromMs: range.fromMs,
      toMs: range.toMs,
      abort: signal
    });
    return normalizeToAnnotationFrames(frames, "logs", uid, "error log");
  }
  return [
    createDataFrame({
      fields: [
        { name: "Time", type: "time", values: [range.fromMs] },
        { name: "TimeEnd", type: "time", values: [range.toMs] },
        {
          name: "Text",
          type: "string",
          values: [svc ? `error log service=${svc}` : "error log"]
        },
        { name: "Tags", type: "string", values: [svc || "error"] },
        { name: "signal", type: "string", values: ["logs"] },
        { name: "traceId", type: "string", values: [""] },
        { name: "spanId", type: "string", values: [""] },
        { name: "alertId", type: "string", values: [""] },
        { name: "DatasourceUid", type: "string", values: [uid] }
      ],
      meta: {
        signal: "logs",
        source: "annotation",
        filter: { expression: filter2, service: svc || void 0 },
        fromMs: range.fromMs,
        toMs: range.toMs,
        offline: true
      }
    })
  ];
}
let sessionSeq = 1;
function parseSseChunk(buffer, onEvent) {
  const normalized = buffer.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
  const parts = normalized.split("\n\n");
  const incomplete = parts.pop() ?? "";
  for (const block of parts) {
    if (!block.trim()) continue;
    let event = "message";
    let id;
    const dataLines = [];
    for (const line of block.split("\n")) {
      if (!line || line.startsWith(":")) continue;
      if (line.startsWith("event:")) {
        event = line.slice(6).trim();
      } else if (line.startsWith("data:")) {
        dataLines.push(line.slice(5).replace(/^\s/, ""));
      } else if (line.startsWith("id:")) {
        id = line.slice(3).trim();
      }
    }
    if (dataLines.length || event === "error") {
      onEvent({ event, data: dataLines.join("\n"), id });
    }
  }
  return incomplete;
}
function parseLiveTailDataPayload(data) {
  if (!data) return null;
  try {
    const parsed = JSON.parse(data);
    const ts = Number(
      parsed.timestamp ?? parsed.time ?? parsed.ts ?? (parsed.data && parsed.data.timestamp) ?? Date.now()
    );
    const body = parsed.data !== void 0 ? parsed.data : parsed;
    const rowId = stableRowId(ts, body, parsed.id);
    return { timestamp: ts, data: body, rowId };
  } catch {
    const ts = Date.now();
    return { timestamp: ts, data, rowId: stableRowId(ts, data) };
  }
}
function stableRowId(timestamp, data, hint) {
  if (hint) return `${timestamp}:${hint}`;
  if (data && typeof data === "object") {
    const o = data;
    const id = o.id ?? o.uuid ?? o.log_id ?? o.span_id ?? o.spanId;
    if (id != null) return `${timestamp}:${String(id)}`;
    const line = o.body ?? o.message ?? o.line;
    if (line != null) return `${timestamp}:${hashShort(String(line))}`;
  }
  return `${timestamp}:${hashShort(JSON.stringify(data))}`;
}
function hashShort(s) {
  let h = 0;
  for (let i = 0; i < s.length; i++)
    h = Math.imul(31, h) + s.charCodeAt(i) | 0;
  return (h >>> 0).toString(16);
}
function defaultSleep(ms, signal) {
  return new Promise((resolve, reject) => {
    if (signal.aborted) {
      reject(new DataSourceError("CANCELLED", "live tail aborted"));
      return;
    }
    const t = setTimeout(() => {
      signal.removeEventListener("abort", onAbort);
      resolve();
    }, ms);
    const onAbort = () => {
      clearTimeout(t);
      reject(new DataSourceError("CANCELLED", "live tail aborted"));
    };
    signal.addEventListener("abort", onAbort, { once: true });
  });
}
function resolveLiveTailTransport(caps2) {
  if (caps2.sseVerified && caps2.liveTailPath) return "sse";
  if (caps2.legacySseEnabled && caps2.legacyLiveTailPath) return "sse";
  if (caps2.cursorPoll) return "cursor_poll";
  return "none";
}
function createLiveTailSession(config) {
  const sessionId = sessionSeq++;
  const maxRows = Math.max(100, config.maxRows ?? 5e3);
  const pollIntervalMs = Math.max(200, config.pollIntervalMs ?? 2e3);
  const maxRetries = config.maxRetries ?? 8;
  const sleep2 = config.sleep || defaultSleep;
  let state2 = "idle";
  let transport = resolveLiveTailTransport(
    config.capabilities
  );
  let controller = null;
  let rows = [];
  const seen = /* @__PURE__ */ new Set();
  let lastTimestamp = config.startMs;
  let nextCursor = null;
  let retryCount = 0;
  let paused = false;
  let runToken = 0;
  const setState = (s, detail) => {
    state2 = s;
    config.onState?.(s, detail);
  };
  const isCurrent = (token) => token === runToken && controller != null && !controller.signal.aborted;
  const pushRows = (incoming) => {
    if (!incoming.length) return;
    const fresh = [];
    for (const r of incoming) {
      if (seen.has(r.rowId)) continue;
      seen.add(r.rowId);
      fresh.push(r);
      if (r.timestamp > lastTimestamp) lastTimestamp = r.timestamp;
    }
    if (!fresh.length) return;
    rows = rows.concat(fresh);
    if (rows.length > maxRows) {
      const drop = rows.length - maxRows;
      for (let i = 0; i < drop; i++) seen.delete(rows[i].rowId);
      rows = rows.slice(drop);
    }
    config.onRows?.(fresh, { sessionId, transport });
  };
  const cancelActive = () => {
    runToken += 1;
    if (controller) {
      controller.abort();
      controller = null;
    }
  };
  async function runSse(token) {
    if (!config.fetchStream) {
      throw new DataSourceError(
        "UNSUPPORTED_CAPABILITY",
        "SSE live tail 需要 fetchStream（API key/Bearer 不可用 EventSource）"
      );
    }
    const path = config.capabilities.sseVerified && config.capabilities.liveTailPath ? config.capabilities.liveTailPath : config.capabilities.legacyLiveTailPath;
    const query = {
      start: String(lastTimestamp || config.startMs),
      filter: config.filterExpression || ""
    };
    setState("connecting");
    const res = await config.fetchStream({
      path,
      query,
      signal: controller.signal
    });
    if (!isCurrent(token)) return;
    const ct = String(
      res.headers?.get?.("content-type") || res.headers?.get?.("Content-Type") || ""
    );
    if (!ct.includes("text/event-stream")) {
      throw new DataSourceError(
        "UNSUPPORTED_CAPABILITY",
        `live tail Content-Type 必须是 text/event-stream，得到 ${ct || "empty"}`
      );
    }
    if (!res.body || typeof res.body.getReader !== "function") {
      throw new DataSourceError("INVALID_RESPONSE", "SSE response body 不可读");
    }
    setState("live");
    retryCount = 0;
    const reader = res.body.getReader();
    const decoder = new TextDecoder();
    let buf = "";
    while (isCurrent(token)) {
      if (paused) {
        setState("paused");
        await sleep2(100, controller.signal);
        continue;
      }
      if (state2 === "paused") setState("live");
      const { done, value } = await reader.read();
      if (!isCurrent(token)) return;
      if (done) break;
      buf += decoder.decode(value, { stream: true });
      buf = parseSseChunk(buf, (ev) => {
        if (!isCurrent(token)) return;
        if (ev.event === "error") {
          throw new DataSourceError(
            "UPSTREAM_ERROR",
            ev.data || "SSE event: error"
          );
        }
        const row = parseLiveTailDataPayload(ev.data);
        if (row) pushRows([row]);
      });
    }
  }
  async function runCursorPoll(token) {
    if (!config.fetchCursorPage) {
      throw new DataSourceError(
        "UNSUPPORTED_CAPABILITY",
        "cursor poll 需要 fetchCursorPage"
      );
    }
    setState("connecting");
    setState("live");
    retryCount = 0;
    let firstPageDone = false;
    while (isCurrent(token)) {
      if (paused) {
        setState("paused");
        await sleep2(100, controller.signal);
        continue;
      }
      if (state2 === "paused") setState("live");
      const page = await config.fetchCursorPage({
        cursor: nextCursor,
        startMs: lastTimestamp || config.startMs,
        signal: controller.signal
      });
      if (!isCurrent(token) || controller.signal.aborted) return;
      pushRows(page.rows || []);
      if (page.nextCursor) {
        nextCursor = page.nextCursor;
        firstPageDone = true;
      } else if (!firstPageDone) {
        firstPageDone = true;
        if (!page.rows?.length) {
          throw new DataSourceError(
            "UNSUPPORTED_CAPABILITY",
            "无 SSE 且无 nextCursor，不能循环重拉第一页"
          );
        }
      } else if (!page.nextCursor && !page.rows?.length) ;
      await sleep2(pollIntervalMs, controller.signal);
      if (!nextCursor && firstPageDone && !page.rows?.length) ;
    }
  }
  async function loop() {
    const token = runToken;
    transport = resolveLiveTailTransport(config.capabilities);
    if (transport === "none") {
      setState("error", "UNSUPPORTED_CAPABILITY");
      const err = new DataSourceError(
        "UNSUPPORTED_CAPABILITY",
        "live tail 需要已验证 SSE 或 cursor poll capability"
      );
      config.onError?.(err, sessionId);
      return;
    }
    while (isCurrent(token) && state2 !== "stopped") {
      try {
        if (transport === "sse") await runSse(token);
        else await runCursorPoll(token);
        if (isCurrent(token) && !paused) {
          setState("retrying");
          retryCount += 1;
          if (retryCount > maxRetries) {
            setState("error", "max retries");
            config.onError?.(
              new DataSourceError("UPSTREAM_ERROR", "live tail max retries"),
              sessionId
            );
            return;
          }
          const backoff = Math.min(3e4, 500 * 2 ** Math.min(retryCount, 6));
          await sleep2(backoff, controller.signal);
        }
      } catch (e) {
        if (!isCurrent(token)) return;
        if (e?.code === "CANCELLED" || /abort/i.test(String(e?.message || "")))
          return;
        retryCount += 1;
        if (retryCount > maxRetries) {
          setState("error", e?.message || "error");
          config.onError?.(
            e instanceof Error ? e : new Error(String(e)),
            sessionId
          );
          return;
        }
        setState("retrying", e?.message);
        const backoff = Math.min(3e4, 500 * 2 ** Math.min(retryCount, 6));
        try {
          await sleep2(backoff, controller.signal);
        } catch {
          return;
        }
      }
    }
  }
  return {
    get sessionId() {
      return sessionId;
    },
    get state() {
      return state2;
    },
    get transport() {
      return transport;
    },
    get rows() {
      return rows;
    },
    async start() {
      cancelActive();
      paused = false;
      controller = new AbortController();
      void loop();
    },
    pause() {
      paused = true;
      if (state2 === "live" || state2 === "connecting") setState("paused");
    },
    resume() {
      if (state2 === "stopped" || state2 === "idle") return;
      paused = false;
      if (state2 === "paused") setState("live");
    },
    stop() {
      paused = false;
      cancelActive();
      setState("stopped");
    },
    dispose() {
      paused = false;
      cancelActive();
      setState("stopped");
      rows = [];
      seen.clear();
    }
  };
}
const MAX_EXPORT_BYTES = 50 * 1024 * 1024;
const MAX_PAGES = 1e4;
function isHtmlContentType(ct) {
  return /text\/html/i.test(ct);
}
function isJsonContentType(ct) {
  return /application\/json|text\/json|\+json/i.test(ct);
}
function looksLikeErrorJson(text) {
  try {
    const o = JSON.parse(text);
    if (o && typeof o === "object") {
      if (o.error || o.errors || o.status === "error" || o.success === false)
        return true;
    }
  } catch {
  }
  return false;
}
function redactSecrets(value, depth = 0) {
  if (depth > 12) return "[MaxDepth]";
  if (value == null) return value;
  if (Array.isArray(value))
    return value.map((v) => redactSecrets(v, depth + 1));
  if (typeof value !== "object") return value;
  const out = {};
  for (const [k, v] of Object.entries(value)) {
    if (/token|password|secret|authorization|api[_-]?key|credential/i.test(k)) {
      out[k] = "[REDACTED]";
    } else {
      out[k] = redactSecrets(v, depth + 1);
    }
  }
  return out;
}
function framesToCsv(frames) {
  const lines = [];
  for (const fr of frames) {
    const names = fr.fields.map((f) => f.name);
    lines.push(names.map(csvEscape).join(","));
    const n = fr.fields[0]?.values?.length || 0;
    for (let i = 0; i < n; i++) {
      lines.push(
        fr.fields.map((f) => {
          const v = f.values?.[i];
          if (v == null) return "";
          if (typeof v === "object") return csvEscape(stableJson(v));
          return csvEscape(String(v));
        }).join(",")
      );
    }
    lines.push("");
  }
  return lines.join("\n");
}
function csvEscape(s) {
  if (/[",\n\r]/.test(s)) return `"${s.replace(/"/g, '""')}"`;
  return s;
}
function stableJson(value) {
  return JSON.stringify(redactSecrets(value), (_k, v) => {
    if (v && typeof v === "object" && !Array.isArray(v)) {
      const o = v;
      const sorted = {};
      for (const k of Object.keys(o).sort()) sorted[k] = o[k];
      return sorted;
    }
    return v;
  });
}
async function exportUpstreamRaw(args) {
  const res = await args.http({
    path: args.path,
    method: "POST",
    body: args.body,
    signal: args.signal
  });
  const status = Number(res.status || 0);
  if (status < 200 || status >= 300) {
    throw new DataSourceError(
      "UPSTREAM_ERROR",
      `export_raw_data HTTP ${status}`,
      { status }
    );
  }
  const headers = res.headers;
  const getHeader = (name) => {
    if (!headers) return "";
    if (typeof headers.get === "function")
      return String(headers.get(name) || "");
    const h = headers;
    return String(h[name] || h[name.toLowerCase()] || "");
  };
  const ct = getHeader("content-type") || getHeader("Content-Type");
  if (isHtmlContentType(ct)) {
    throw new DataSourceError(
      "INVALID_RESPONSE",
      "export 返回 HTML，不能当作导出成功"
    );
  }
  let body;
  let size;
  if (typeof res.data === "string") {
    if (isJsonContentType(ct) && looksLikeErrorJson(res.data)) {
      throw new DataSourceError("UPSTREAM_ERROR", "export 返回 error JSON");
    }
    body = res.data;
    size = new TextEncoder().encode(res.data).byteLength;
  } else if (res.data instanceof Uint8Array) {
    body = res.data;
    size = res.data.byteLength;
  } else if (res.data && typeof res.data === "object") {
    if (res.data.error || res.data.success === false) {
      throw new DataSourceError(
        "UPSTREAM_ERROR",
        "export 返回 error JSON object"
      );
    }
    body = stableJson(res.data);
    size = new TextEncoder().encode(body).byteLength;
  } else {
    body = String(res.data ?? "");
    size = body.length;
  }
  if (size > MAX_EXPORT_BYTES) {
    throw new DataSourceError(
      "INVALID_RESPONSE",
      `export 超过 size limit ${MAX_EXPORT_BYTES}`
    );
  }
  const cd = getHeader("content-disposition") || getHeader("Content-Disposition");
  const filename = /filename\*?=(?:UTF-8''|")?([^\";]+)/i.exec(cd)?.[1] || args.filenameHint || `signoz-export-${Date.now()}.raw`;
  return {
    mode: "upstream",
    filename: decodeURIComponent(filename.replace(/"/g, "")),
    contentType: ct || "application/octet-stream",
    body,
    size
  };
}
async function exportViaCursorPages(args) {
  const maxPages = Math.min(MAX_PAGES, args.maxPages ?? MAX_PAGES);
  let cursor = null;
  let pages = 0;
  let rows = 0;
  let complete = false;
  let truncatedByUpstream = false;
  const allRows = [];
  const allFrames = [];
  const envelopes = [];
  while (pages < maxPages) {
    if (args.signal?.aborted) {
      args.onProgress?.({
        mode: "cursor_pages",
        pages,
        rows,
        bytes: 0,
        complete: false,
        truncatedByUpstream: false,
        cancelled: true
      });
      throw new DataSourceError("CANCELLED", "export cancelled");
    }
    const page = await args.fetchPage(cursor, args.signal);
    pages += 1;
    const pageRows = page.rows || [];
    rows += pageRows.length;
    allRows.push(...pageRows);
    if (page.frames) allFrames.push(...page.frames);
    if (page.envelope !== void 0)
      envelopes.push(redactSecrets(page.envelope));
    args.onProgress?.({
      mode: "cursor_pages",
      pages,
      rows,
      bytes: 0,
      complete: false,
      truncatedByUpstream: false,
      cancelled: false
    });
    if (!page.nextCursor) {
      complete = true;
      break;
    }
    if (page.nextCursor === cursor) {
      truncatedByUpstream = true;
      break;
    }
    cursor = page.nextCursor;
  }
  if (!complete && pages >= maxPages) truncatedByUpstream = true;
  let body;
  if (args.format === "csv") {
    if (allFrames.length) body = framesToCsv(allFrames);
    else {
      const keys = /* @__PURE__ */ new Set();
      for (const r of allRows) {
        if (r && typeof r === "object")
          Object.keys(r).forEach((k) => keys.add(k));
      }
      const cols = [...keys].sort();
      const lines = [cols.map(csvEscape).join(",")];
      for (const r of allRows) {
        const o = r && typeof r === "object" ? r : { value: r };
        lines.push(
          cols.map((c) => {
            const v = o[c];
            if (v == null) return "";
            if (typeof v === "object") return csvEscape(stableJson(v));
            return csvEscape(String(v));
          }).join(",")
        );
      }
      body = lines.join("\n");
    }
  } else {
    body = stableJson({
      exportMode: "cursor_pages",
      pages,
      rowCount: rows,
      complete,
      truncatedByUpstream,
      envelopes: envelopes.length ? envelopes : void 0,
      data: redactSecrets(allRows)
    });
  }
  const bytes = new TextEncoder().encode(body).byteLength;
  if (bytes > MAX_EXPORT_BYTES) {
    throw new DataSourceError(
      "INVALID_RESPONSE",
      `export 超过 size limit ${MAX_EXPORT_BYTES}`
    );
  }
  args.onProgress?.({
    mode: "cursor_pages",
    pages,
    rows,
    bytes,
    complete,
    truncatedByUpstream,
    cancelled: false
  });
  return {
    mode: "cursor_pages",
    format: args.format,
    filename: args.filenameHint || `signoz-export-pages-${Date.now()}.${args.format}`,
    body,
    pages,
    rows,
    complete,
    truncatedByUpstream
  };
}
function exportLoadedOnly(args) {
  const rows = args.rows || [];
  let body;
  if (args.format === "csv") {
    body = args.frames?.length ? framesToCsv(args.frames) : framesToCsv([]);
    if (!args.frames?.length && rows.length) {
      const keys = /* @__PURE__ */ new Set();
      for (const r of rows) {
        if (r && typeof r === "object")
          Object.keys(r).forEach((k) => keys.add(k));
      }
      const cols = [...keys].sort();
      const lines = [cols.map(csvEscape).join(",")];
      for (const r of rows) {
        const o = r && typeof r === "object" ? r : { value: r };
        lines.push(cols.map((c) => csvEscape(String(o[c] ?? ""))).join(","));
      }
      body = lines.join("\n");
    }
  } else {
    body = stableJson({
      exportMode: "loaded_only",
      disclaimer: "EXPORT_LOADED_ONLY",
      rows: redactSecrets(rows),
      frames: args.frames ? redactSecrets(
        args.frames.map((f) => ({
          name: f.name,
          fields: f.fields.map((x) => x.name)
        }))
      ) : void 0
    });
  }
  return {
    mode: "loaded_only",
    format: args.format,
    filename: args.filenameHint || `signoz-loaded-${Date.now()}.${args.format}`,
    body,
    rows: rows.length || args.frames?.reduce(
      (n, f) => n + (f.fields[0]?.values?.length || 0),
      0
    ) || 0,
    disclaimer: "EXPORT_LOADED_ONLY"
  };
}
async function exportSigNozRaw(args) {
  const format = args.format || "json";
  if (args.preferLoadedOnly) {
    return exportLoadedOnly({
      format,
      frames: args.loadedFrames,
      rows: args.loadedRows
    });
  }
  if (args.capabilities.exportRawVerified && args.capabilities.exportRawPath && args.http) {
    return exportUpstreamRaw({
      path: args.capabilities.exportRawPath,
      body: args.upstreamBody,
      signal: args.signal,
      http: args.http
    });
  }
  if (args.capabilities.cursorPaging && args.fetchPage) {
    return exportViaCursorPages({
      format,
      signal: args.signal,
      fetchPage: args.fetchPage,
      onProgress: args.onProgress
    });
  }
  if (args.loadedFrames?.length || args.loadedRows?.length) {
    return exportLoadedOnly({
      format,
      frames: args.loadedFrames,
      rows: args.loadedRows
    });
  }
  throw new DataSourceError(
    "UNSUPPORTED_CAPABILITY",
    "export 需要已验证 export_raw_data 或 cursor paging（禁止用屏幕前 N 行冒充全部）"
  );
}
const SIGNOZ_CAPABILITIES = {
  signals: ["metrics", "logs", "traces"],
  query: true,
  health: true,
  metadata: true,
  variables: true,
  annotations: true,
  exemplars: false,
  streaming: false,
  queryLanguages: ["promql", "signoz-builder", "clickhouse_sql"]
};
function rangeMs(range) {
  const from = range.from instanceof Date ? range.from.getTime() : Number(range.from?.valueOf?.() ?? range.from);
  const to = range.to instanceof Date ? range.to.getTime() : Number(range.to?.valueOf?.() ?? range.to);
  return { fromMs: from, toMs: to };
}
function createSignozDataSource(instance, meta2) {
  const dataMode = instance.jsonData?.dataMode === "fixture" ? "fixture" : "live";
  const useFixture = dataMode === "fixture";
  const fallback = createBuiltinDataSourceApi(instance, meta2);
  const options = migrateSigNozConfig(
    instance.jsonData || {}
  );
  const profile = resolveSigNozProfile(options);
  const profileId = String(options.apiProfile || profile.id);
  const base = String(instance.url || "").replace(/\/$/, "");
  const timeoutMs = parseTimeoutMs(options.timeout, 3e4);
  const cacheTtlMs = parseCacheTtlMs(options.metadataCacheTTL, 3e5);
  let observedVersion = "";
  let credentialRevision = "";
  async function resolveCredential() {
    const cred = await getRuntimeCredential(instance.uid);
    if (cred && options.credentialKind === "signozApiKey" && cred.kind === "apiKey") {
      return {
        ...cred,
        headerName: options.credentialHeaderName || profile.defaultCredentialHeader || "SIGNOZ-API-KEY"
      };
    }
    if (cred && options.credentialKind === "signozApiKey" && cred.kind === "bearer" && cred.value) {
      return {
        kind: "apiKey",
        value: cred.value,
        headerName: options.credentialHeaderName || profile.defaultCredentialHeader || "SIGNOZ-API-KEY"
      };
    }
    credentialRevision = cred ? `${cred.kind}:${cred.headerName || ""}` : "none";
    return cred;
  }
  function cacheIdentity() {
    return buildCapabilityIdentity({
      uid: instance.uid,
      options,
      baseUrl: base,
      credentialRevision,
      observedVersion
    });
  }
  async function signozHttp(req) {
    const run = async () => {
      const cred2 = await resolveCredential();
      const mode2 = String(
        options.credentialMode || instance.jsonData?.credentialMode || ""
      );
      if (!useFixture && !cred2 && mode2 !== "proxy" && mode2 !== "none") {
        throw new DataSourceError(
          "AUTH",
          "SigNoz live 请求缺少运行时凭证（Authorization 不会被自动发明）。请设置 VITE_SIGNOZ_NATIVE_TOKEN 并重启 dev server，或使用 credentialMode=proxy 并由 Vite/BFF 注入。"
        );
      }
      return datasourceHttp({
        forceNetwork: !useFixture,
        baseUrl: base,
        path: req.path,
        method: req.method || "GET",
        body: req.body,
        query: req.query,
        uid: instance.uid,
        credential: cred2,
        signal: req.signal,
        timeoutMs
      });
    };
    const cred = await resolveCredential();
    const session = asSessionCredential(cred);
    if (session && !String(req.path || "").includes("/sessions/")) {
      return withAuthRetry(run, {
        uid: instance.uid,
        baseUrl: base,
        credential: session,
        signal: req.signal
      });
    }
    return run();
  }
  const metadataApi = createSigNozMetadataApi({
    offline: useFixture,
    profile,
    http: useFixture ? void 0 : signozHttp,
    identity: cacheIdentity(),
    cache: sharedSigNozMetadataCache,
    ttlMs: cacheTtlMs
  });
  const activeLiveTails = /* @__PURE__ */ new Map();
  const waterfallCache = createMemoryWaterfallCache();
  function liveExportCaps() {
    return resolveLiveExportCapabilities({ profile, options });
  }
  async function listServices(signal) {
    if (useFixture) {
      return [
        { text: "frontend", value: "frontend" },
        { text: "api", value: "api" },
        { text: "checkout", value: "checkout" }
      ];
    }
    try {
      const meta22 = await metadataApi.getMetadata({ type: "services" }, signal);
      if (meta22.type === "services") {
        return meta22.values.map((v) => ({ text: v, value: v }));
      }
    } catch {
    }
    return [];
  }
  async function mutate(request) {
    if (useFixture) {
      return {
        status: "success",
        message: "offline preview",
        data: {
          action: request.action,
          payload: request.payload,
          preview: true
        }
      };
    }
    const action = String(request.action || "");
    if (action !== "signoz.acknowledge" && action !== "signoz.resolve") {
      return {
        status: "error",
        message: `Unsupported action: ${action}`
      };
    }
    const payload = request.payload || {};
    if (payload.source && payload.source !== "alert") {
      return {
        status: "error",
        message: "only alert source supports actions"
      };
    }
    const endpoints = profile.endpoints;
    const path = action === "signoz.acknowledge" ? options.customAcknowledgePath || endpoints.acknowledge?.path : options.customResolvePath || endpoints.resolve?.path;
    if (!path) {
      return {
        status: "error",
        message: `Unsupported action: ${action}`
      };
    }
    const body = {
      alertId: payload.alertId || payload.issueId,
      source: "alert",
      message: payload.message
    };
    const cred = await getRuntimeCredential(instance.uid);
    const res = await datasourceHttp({
      forceNetwork: !useFixture,
      baseUrl: base,
      path,
      method: "POST",
      body,
      uid: instance.uid,
      credential: cred,
      signal: request.signal
    });
    const status = Number(res?.status ?? 200);
    if (!isSuccessfulActionResponse(status, res?.data)) {
      return {
        status: "error",
        message: "action response indicates failure"
      };
    }
    return {
      status: "success",
      message: "ok",
      data: res?.data
    };
  }
  return {
    ...fallback,
    uid: instance.uid,
    name: instance.name,
    type: instance.type,
    meta: meta2,
    capabilities: { ...SIGNOZ_CAPABILITIES },
    async query(request, signal) {
      const { fromMs, toMs: toMs2 } = rangeMs(request.range);
      const intervalMs = request.intervalMs || 6e4;
      const frames = [];
      const framesByName = /* @__PURE__ */ new Map();
      const pushNamed = (key, fr) => {
        const arr = framesByName.get(key) || [];
        arr.push(fr);
        framesByName.set(key, arr);
      };
      for (const rawTarget of request.targets || []) {
        if (rawTarget.hide) continue;
        const query = migrateSigNozQuery(rawTarget);
        if (useFixture) {
          try {
            buildSigNozRequests({
              profile,
              options,
              query,
              fromMs,
              toMs: toMs2,
              intervalMs
            });
          } catch (e) {
            if (e instanceof DataSourceError) throw e;
            throw new DataSourceError(
              "INVALID_QUERY",
              e instanceof Error ? e.message : String(e)
            );
          }
          const signalName = String(
            query.signal || query.queries?.[0]?.spec?.signal || "metrics"
          );
          if (signalName === "alerts") {
            const fr = createDataFrame({
              refId: query.refId,
              name: "issues",
              fields: [
                {
                  name: "Time",
                  type: "time",
                  values: [fromMs, fromMs + intervalMs, toMs2]
                },
                {
                  name: "id",
                  type: "string",
                  values: ["iss-1", "iss-2", "iss-3"]
                },
                {
                  name: "title",
                  type: "string",
                  values: ["High latency", "Error rate", "DB timeout"]
                },
                {
                  name: "service",
                  type: "string",
                  values: ["frontend", "api", "checkout"]
                },
                {
                  name: "severity",
                  type: "string",
                  values: ["critical", "warning", "error"]
                },
                {
                  name: "status",
                  type: "string",
                  values: ["firing", "firing", "acknowledged"]
                },
                { name: "traceId", type: "string", values: ["t1", "t2", "t3"] }
              ],
              meta: {
                preferredVisualisationType: "table",
                offline: useFixture,
                signal: "alerts"
              }
            });
            frames.push(fr);
            pushNamed("issues", fr);
            continue;
          }
          for (const item of query.queries || []) {
            if (item.type === "builder_formula") continue;
            if (item.spec?.disabled) continue;
            const name = item.spec.name || query.refId;
            const times = [fromMs, fromMs + intervalMs, toMs2];
            const fr = createDataFrame({
              refId: query.refId,
              name,
              fields: [
                { name: "Time", type: "time", values: times },
                { name, type: "number", values: [1, 2, 3] }
              ],
              meta: {
                preferredVisualisationType: "graph",
                offline: useFixture
              }
            });
            frames.push(fr);
            pushNamed(name, fr);
          }
          for (const item of query.queries || []) {
            if (item.type !== "builder_formula" || item.spec.disabled) continue;
            const f = evaluateLocalFormula(
              item.spec.expression,
              framesByName,
              item.spec.name
            );
            frames.push(f);
            pushNamed(item.spec.name, f);
          }
          continue;
        }
        if (profileId === "prometheus-compatible") {
          const onlyProm = (query.queries || []).every(
            (q) => q.type === "builder_formula" || q.type === "builder_query" && q.queryType === "promql"
          );
          if (onlyProm) {
            const prom = createPrometheusDataSource(
              {
                ...instance,
                jsonData: { ...instance.jsonData, httpMethod: "GET" }
              },
              meta2
            );
            const promTargets = (query.queries || []).filter((q) => q.type === "builder_query").map((q) => ({
              refId: q.spec.name || query.refId,
              expr: q.rawQuery || "",
              legendFormat: q.rawLegend || q.spec.legend || ""
            }));
            const res = await prom.query(
              { ...request, targets: promTargets },
              signal
            );
            for (const fr of res.data || []) {
              frames.push(fr);
              pushNamed(String(fr.refId || fr.name), fr);
            }
            for (const item of query.queries || []) {
              if (item.type !== "builder_formula" || item.spec.disabled)
                continue;
              const f = evaluateLocalFormula(
                item.spec.expression,
                framesByName,
                item.spec.name
              );
              frames.push(f);
            }
            continue;
          }
        }
        let built;
        try {
          built = buildSigNozRequests({
            profile,
            options,
            query,
            fromMs,
            toMs: toMs2,
            intervalMs
          });
        } catch (e) {
          if (e instanceof DataSourceError) throw e;
          throw new DataSourceError(
            "UNSUPPORTED_QUERY_API",
            e instanceof Error ? e.message : String(e)
          );
        }
        const cred = await getRuntimeCredential(instance.uid);
        for (const req of built) {
          if (req.localFormula) {
            const f = evaluateLocalFormula(
              req.localFormula.expression,
              framesByName,
              req.localFormula.name
            );
            frames.push(f);
            pushNamed(req.localFormula.name, f);
            continue;
          }
          if (!req.path) continue;
          const res = await datasourceHttp({
            forceNetwork: !useFixture,
            baseUrl: base,
            path: req.path,
            method: req.method,
            body: req.body,
            query: req.query,
            uid: instance.uid,
            credential: cred,
            signal
          });
          const isPromEnvelope = typeof res.data?.data?.resultType === "string" && Array.isArray(res.data?.data?.result);
          let mapped = [];
          if (isPromEnvelope) {
            mapped = normalizeDataFrames(
              mapPrometheusResponse(res.data, {
                refId: query.refId,
                legendFormat: "",
                expr: String(req.query?.query || "")
              }),
              {
                refId: query.refId,
                source: "signoz",
                datasourceUid: instance.uid,
                profile: profileId,
                signal: "metrics",
                requestId: request.requestId
              }
            );
          } else {
            mapped = normalizeDataFrames(
              mapSignozResponse(res.data, profileId, {
                refId: query.refId,
                signal: req.signal,
                requestType: String(
                  query.requestType || req.body?.requestType || ""
                ),
                datasourceUid: instance.uid,
                experimentalDistribution: Boolean(
                  options.experimentalCapabilities?.distribution
                )
              }),
              {
                refId: query.refId,
                source: "signoz",
                datasourceUid: instance.uid,
                profile: profileId,
                signal: String(req.signal || "metrics"),
                requestId: request.requestId
              }
            );
          }
          for (const fr of mapped) {
            frames.push(fr);
            const key = String(
              fr.name || fr.refId || req.queryNames[0] || query.refId
            );
            pushNamed(key, fr);
            for (const n of req.queryNames) {
              pushNamed(n, fr);
            }
          }
        }
      }
      return { data: frames };
    },
    async testDatasource(signal) {
      if (useFixture)
        return { status: "success", message: "SigNoz offline OK" };
      if (!base) return { status: "error", message: "Datasource URL is empty" };
      try {
        const healthRes = await probeHealth(
          async (req) => {
            const r = await signozHttp({
              ...req,
              signal: req.signal || signal
            });
            return { status: Number(r.status ?? 200), data: r.data };
          },
          profile,
          { signal }
        );
        if (!healthRes.ok) {
          if (healthRes.reasonCode === "AUTH") {
            sharedSigNozMetadataCache.clearUid(instance.uid);
            return {
              status: "error",
              message: `AUTH: ${healthRes.reason} @ ${healthRes.path}`
            };
          }
          return {
            status: "error",
            message: `health failed (${healthRes.reasonCode || "ERROR"}): ${healthRes.reason} @ ${healthRes.path || "n/a"}`
          };
        }
        const versionEp = profile.endpoints.version;
        let versionInfo = "";
        if (versionEp?.path) {
          try {
            const vres = await signozHttp({
              path: versionEp.path,
              method: "GET",
              signal
            });
            const parsed = parseVersionPayload(vres.data);
            if (parsed.version) {
              observedVersion = parsed.version;
              versionInfo = ` version=${parsed.version}`;
              if (parsed.ee != null) versionInfo += ` ee=${parsed.ee}`;
              if (parsed.setupCompleted != null)
                versionInfo += ` setupCompleted=${parsed.setupCompleted}`;
            }
          } catch {
          }
        }
        try {
          if (profileId === "signoz-v5") {
            await metadataApi.getMetadata({ type: "metrics" }, signal);
          } else if (profile.endpoints.metricsList || profile.endpoints.metadata || profile.endpoints.fieldsKeys) {
            try {
              await metadataApi.getMetadata({ type: "metrics" }, signal);
            } catch {
              await metadataApi.getMetadata(
                { type: "attributeKeys", signal: "metrics" },
                signal
              );
            }
          }
        } catch (e) {
          const msg = e instanceof Error ? e.message : String(e);
          if (/401|403|AUTH/i.test(msg)) {
            sharedSigNozMetadataCache.clearUid(instance.uid);
            return {
              status: "error",
              message: `AUTH: authenticated probe failed: ${msg}`
            };
          }
          return {
            status: "error",
            message: `authenticated probe failed: ${msg}`
          };
        }
        return {
          status: "success",
          message: `SigNoz profile ${profileId} healthy via ${healthRes.path}${versionInfo}`
        };
      } catch (e) {
        return {
          status: "error",
          message: e instanceof Error ? e.message : String(e)
        };
      }
    },
    listServices,
    async metricFindQuery(query, signal) {
      const caps2 = resolveEditorCapabilities({
        profile,
        options
      });
      try {
        return await runSigNozVariableQuery(metadataApi, query, {
          signal,
          profileId,
          capabilities: caps2,
          runClickHouseVariable: useFixture ? async () => ["offline-ch-1", "offline-ch-2"] : profile.endpoints.variablesQuery?.path ? async (sql, abort) => {
            const cred = await getRuntimeCredential(instance.uid);
            const res = await datasourceHttp({
              forceNetwork: true,
              baseUrl: base,
              path: profile.endpoints.variablesQuery.path,
              method: profile.endpoints.variablesQuery.method || "POST",
              body: { query: sql },
              uid: instance.uid,
              credential: cred,
              signal: abort
            });
            const rows = Array.isArray(res.data) ? res.data : Array.isArray(res.data?.data) ? res.data.data : Array.isArray(res.data?.values) ? res.data.values : [];
            return rows.map(
              (r) => typeof r === "string" || typeof r === "number" ? String(r) : String(r?.value ?? r?.name ?? "")
            ).filter(Boolean);
          } : void 0
        });
      } catch (e) {
        throw e;
      }
    },
    async annotationQuery(request, signal) {
      const { fromMs, toMs: toMs2 } = rangeMs(request.range);
      const ann = request.annotation || {};
      const target = ann.target || ann;
      const caps2 = resolveEditorCapabilities({
        profile,
        options
      });
      const alertsCapable = caps2.alerts || Boolean(
        options.customAlertsPath || profile.endpoints.alertsQuery?.path
      );
      const frames = await querySigNozAnnotations(
        metadataApi,
        {
          source: target.source || "errorLogs",
          service: target.service,
          environment: target.environment
        },
        { fromMs, toMs: toMs2 },
        {
          signal,
          datasourceUid: instance.uid,
          alertsCapable,
          runRawQuery: useFixture ? void 0 : async ({
            signal: sig,
            filterExpression,
            fromMs: f,
            toMs: t,
            abort
          }) => {
            const ep = sig === "logs" ? profile.endpoints.logsQuery || profile.endpoints.metricsQuery : profile.endpoints.tracesQuery || profile.endpoints.metricsQuery;
            if (!ep?.path) {
              throw new DataSourceError(
                "UNSUPPORTED_CAPABILITY",
                `annotation raw ${sig} 需要 query_range endpoint`
              );
            }
            const cred = await getRuntimeCredential(instance.uid);
            const body = {
              start: f,
              end: t,
              requestType: "raw",
              compositeQuery: {
                queries: [
                  {
                    type: "builder_query",
                    spec: {
                      name: "A",
                      signal: sig,
                      disabled: false,
                      filter: { expression: filterExpression },
                      limit: 100
                    }
                  }
                ]
              }
            };
            if (String(profile.id).includes("v3") || String(profile.id).includes("v4")) {
              body.compositeQuery = {
                queryType: "builder",
                panelType: sig === "traces" ? "trace" : "list",
                builderQueries: {
                  A: {
                    dataSource: sig,
                    filters: { items: [], op: "AND" },
                    filter: filterExpression,
                    aggregateOperator: "noop",
                    limit: 100
                  }
                }
              };
              delete body.requestType;
              body.start = f;
              body.end = t;
            }
            const res = await datasourceHttp({
              forceNetwork: true,
              baseUrl: base,
              path: ep.path,
              method: ep.method || "POST",
              body,
              uid: instance.uid,
              credential: cred,
              signal: abort
            });
            return normalizeDataFrames(
              mapSignozResponse(res.data, profileId, {
                refId: "annotation",
                signal: sig,
                requestType: "raw",
                datasourceUid: instance.uid
              }),
              {
                refId: "annotation",
                source: "signoz",
                datasourceUid: instance.uid,
                profile: profileId,
                signal: String(sig || "logs"),
                requestId: "annotation"
              }
            );
          }
        }
      );
      return frames;
    },
    async getMetadata(request, signal) {
      const api = createSigNozMetadataApi({
        offline: useFixture,
        profile,
        http: useFixture ? void 0 : signozHttp,
        identity: cacheIdentity(),
        cache: sharedSigNozMetadataCache,
        ttlMs: cacheTtlMs
      });
      return api.getMetadata(request, signal);
    },
    /** Capability-gated live tail session. Switching UID/query should dispose prior session. */
    startLiveTail(args = {}) {
      const key = args.sessionKey || "default";
      const prev = activeLiveTails.get(key);
      if (prev) prev.dispose();
      const caps2 = liveExportCaps();
      const session = createLiveTailSession({
        uid: instance.uid,
        profileId,
        filterExpression: args.filterExpression || "",
        startMs: args.startMs ?? Date.now() - 6e4,
        pollIntervalMs: Number(options.liveTailIntervalMs) || 2e3,
        maxRows: 5e3,
        capabilities: {
          sseVerified: caps2.sseVerified,
          legacySseEnabled: caps2.legacySseEnabled,
          cursorPoll: caps2.cursorPoll || useFixture,
          liveTailPath: caps2.liveTailPath,
          legacyLiveTailPath: caps2.legacyLiveTailPath
        },
        fetchStream: useFixture ? void 0 : async ({ path, query, signal }) => {
          const qs = new URLSearchParams(query).toString();
          const fullPath = qs ? `${path}?${qs}` : path;
          const cred = await resolveCredential();
          if (typeof fetch !== "function") {
            throw new DataSourceError(
              "UNSUPPORTED_CAPABILITY",
              "fetch unavailable for SSE"
            );
          }
          const headers = {
            Accept: "text/event-stream"
          };
          if (cred?.kind === "bearer" && cred.value)
            headers.Authorization = `Bearer ${cred.value}`;
          if (cred?.kind === "apiKey" && cred.value) {
            headers[cred.headerName || options.credentialHeaderName || "SIGNOZ-API-KEY"] = cred.value;
          }
          const url = `${base}${fullPath.startsWith("/") ? "" : "/"}${fullPath}`;
          return fetch(url, {
            method: "GET",
            headers,
            credentials: options.fetchCredentials || "omit",
            signal
          });
        },
        fetchCursorPage: async ({ cursor, startMs, signal }) => {
          if (useFixture) {
            if (cursor) return { rows: [], nextCursor: null };
            return {
              rows: [
                {
                  timestamp: startMs + 1,
                  data: { body: "offline live tail row", service: "frontend" },
                  rowId: stableRowId(startMs + 1, {
                    body: "offline live tail row"
                  })
                }
              ],
              nextCursor: null
            };
          }
          const path = profile.endpoints.logsQuery?.path || profile.endpoints.metricsQuery?.path;
          if (!path) {
            throw new DataSourceError(
              "UNSUPPORTED_CAPABILITY",
              "no logs query_range for cursor poll"
            );
          }
          const body = {
            start: startMs,
            end: Date.now(),
            requestType: "raw",
            compositeQuery: {
              queries: [
                {
                  type: "builder_query",
                  spec: {
                    name: "A",
                    signal: "logs",
                    filter: { expression: args.filterExpression || "" },
                    cursor: cursor || void 0
                  }
                }
              ]
            }
          };
          if (cursor) body.cursor = cursor;
          const res = await signozHttp({ path, method: "POST", body, signal });
          const data = res?.data;
          const results = data?.data?.data?.results ?? data?.data?.results ?? data?.results ?? [];
          const first = Array.isArray(results) ? results[0] : null;
          const rawRows = first?.rows || first?.data || [];
          const nextCursor = first?.nextCursor ?? first?.cursor ?? null;
          const rows = (Array.isArray(rawRows) ? rawRows : []).map((r) => {
            const ts = Number(r?.timestamp ?? r?.time ?? startMs);
            return { timestamp: ts, data: r, rowId: stableRowId(ts, r, r?.id) };
          });
          return { rows, nextCursor };
        },
        onState: args.onState,
        onRows: args.onRows,
        onError: args.onError
      });
      activeLiveTails.set(key, session);
      void session.start();
      return session;
    },
    stopLiveTail(sessionKey = "default") {
      const s = activeLiveTails.get(sessionKey);
      if (s) {
        s.dispose();
        activeLiveTails.delete(sessionKey);
      }
    },
    async exportRawData(args = {}) {
      const caps2 = liveExportCaps();
      return exportSigNozRaw({
        capabilities: {
          exportRawVerified: caps2.exportRawVerified && !useFixture,
          exportRawPath: caps2.exportRawPath,
          cursorPaging: caps2.cursorPoll || useFixture
        },
        format: args.format || "json",
        signal: args.signal,
        preferLoadedOnly: args.preferLoadedOnly,
        loadedRows: args.loadedRows,
        loadedFrames: args.loadedFrames,
        upstreamBody: args.upstreamBody,
        onProgress: args.onProgress,
        http: useFixture ? void 0 : async (req) => {
          const res = await signozHttp({
            path: req.path,
            method: req.method,
            body: req.body,
            signal: req.signal
          });
          return {
            status: Number(res?.status ?? 200),
            data: res?.data,
            headers: res?.headers
          };
        },
        fetchPage: async (cursor, signal) => {
          if (useFixture) {
            if (cursor) return { rows: [], nextCursor: null };
            return { rows: [{ body: "offline export row" }], nextCursor: null };
          }
          const path = profile.endpoints.logsQuery?.path || profile.endpoints.metricsQuery?.path;
          if (!path) return { rows: [], nextCursor: null };
          const body = {
            start: Date.now() - 36e5,
            end: Date.now(),
            requestType: "raw",
            compositeQuery: {
              queries: [
                {
                  type: "builder_query",
                  spec: {
                    name: "A",
                    signal: "logs",
                    cursor: cursor || void 0
                  }
                }
              ]
            }
          };
          const res = await signozHttp({ path, method: "POST", body, signal });
          const data = res?.data;
          const results = data?.data?.data?.results ?? data?.data?.results ?? data?.results ?? [];
          const first = Array.isArray(results) ? results[0] : null;
          return {
            rows: first?.rows || [],
            nextCursor: first?.nextCursor ?? first?.cursor ?? null,
            envelope: redactExportEnvelope(data)
          };
        }
      });
    },
    async getTraceWaterfall(args, signal) {
      if (useFixture) {
        const detail2 = {
          candidateId: "v4-waterfall",
          path: `/api/v4/traces/${args.traceId}/waterfall`,
          status: 200,
          rootService: "frontend",
          entryPoint: "GET /",
          spans: [
            {
              spanId: "root",
              parentSpanId: "",
              name: "GET /",
              service: "frontend",
              timeUnixMs: Date.now() - 1e3,
              durationNano: "2000000",
              durationMs: 2,
              attributes: { "http.method": "GET" },
              events: []
            }
          ],
          raw: { offline: true }
        };
        return { frames: waterfallDetailToFrames(detail2), detail: detail2 };
      }
      const detail = await fetchWaterfall({
        traceId: args.traceId,
        state: {
          selectedSpanId: args.selectedSpanId,
          uncollapsedSpans: args.uncollapsedSpans,
          limit: args.limit
        },
        http: async (req) => {
          const res = await signozHttp({
            path: req.path,
            method: req.method,
            body: req.body,
            signal: req.signal
          });
          return {
            status: Number(res?.status ?? 200),
            data: res?.data
          };
        },
        identity: cacheIdentity(),
        cache: waterfallCache,
        hasObservedV3Evidence: Boolean(
          options.experimentalCapabilities?.waterfallV3Observed
        ),
        signal
      });
      return { frames: waterfallDetailToFrames(detail), detail };
    },
    getIssuesWriteCapabilities() {
      return issuesWriteEnabled({
        profileId,
        enableWrites: Boolean(options.enableWrites),
        envGate: Boolean(options.enableWrites),
        hasAcknowledgeEndpoint: Boolean(
          profile.endpoints.acknowledge?.path || options.customAcknowledgePath
        ),
        hasResolveEndpoint: Boolean(
          profile.endpoints.resolve?.path || options.customResolvePath
        ),
        actionCapabilityVerified: Boolean(
          options.experimentalCapabilities?.actionsVerified
        )
      });
    },
    mutate
  };
}
function redactExportEnvelope(data) {
  if (data == null || typeof data !== "object") return data;
  const o = { ...data };
  for (const k of Object.keys(o)) {
    if (/token|password|secret|authorization|api[_-]?key/i.test(k))
      o[k] = "[REDACTED]";
  }
  return o;
}
const _hoisted_1$2 = ["data-save-allowed"];
const _hoisted_2$2 = ["checked"];
const _hoisted_3$1 = {
  key: 0,
  "data-testid": "signoz-session-login-msg"
};
const _hoisted_4$1 = ["data-ok"];
const _hoisted_5$1 = {
  key: 0,
  class: "block",
  "data-testid": "signoz-save-blocked"
};
const _hoisted_6$1 = { "data-testid": "signoz-test-message" };
const _hoisted_7$1 = { class: "hint" };
const _sfc_main$2 = /* @__PURE__ */ defineComponent({
  __name: "ConfigEditor",
  props: {
    options: {},
    onOptionsChange: { type: Function },
    onValidationChange: { type: Function }
  },
  setup(__props) {
    const props = __props;
    const tokenLocal = ref("");
    const refreshTokenLocal = ref("");
    const sessionEmail = ref("");
    const sessionPassword = ref("");
    const rememberPassword = ref(false);
    const sessionLoginLoading = ref(false);
    const sessionLoginMessage = ref("");
    const testMessage = ref("");
    const testLoading = ref(false);
    const jsonData = computed(
      () => migrateSigNozConfig(
        props.options?.jsonData || {}
      )
    );
    const profile = computed(() => resolveSigNozProfile(jsonData.value));
    function patchJson(patch, url2) {
      const options = props.options;
      const nextJson = migrateSigNozConfig({ ...jsonData.value, ...patch });
      props.onOptionsChange({
        ...options,
        ...url2 != null ? { url: url2 } : {},
        jsonData: nextJson
      });
      emitValidation(nextJson, url2 != null ? url2 : String(options?.url || ""));
    }
    function emitValidation(jd = jsonData.value, url2 = String(props.options?.url || "")) {
      let isValid = Boolean(String(url2).trim());
      let message;
      if (!isValid) message = "请填写 Base URL";
      if (jd.apiProfile === "custom") {
        const sig = buildCustomHealthSignature(url2, jd);
        if (!jd.customHealthOk || jd.customHealthSignature !== sig) {
          isValid = false;
          message = "custom profile 必须先通过健康检查";
        }
      }
      props.onValidationChange?.({ isValid, message });
    }
    const url = computed({
      get: () => String(props.options?.url || ""),
      set: (v) => patchJson({}, v)
    });
    const apiProfile = computed({
      get: () => jsonData.value.apiProfile,
      set: (v) => patchJson({
        apiProfile: v,
        customHealthOk: v === "custom" ? false : jsonData.value.customHealthOk,
        customHealthSignature: v === "custom" ? "" : jsonData.value.customHealthSignature
      })
    });
    const organizationId = computed({
      get: () => String(jsonData.value.organizationId || ""),
      set: (v) => patchJson({ organizationId: v })
    });
    const defaultEnvironment = computed({
      get: () => String(jsonData.value.defaultEnvironment || ""),
      set: (v) => patchJson({ defaultEnvironment: v })
    });
    const timeout = computed({
      get: () => Number(jsonData.value.timeout || 3e4),
      set: (v) => patchJson({ timeout: Number(v) || 3e4 })
    });
    const cacheTTL = computed({
      get: () => String(jsonData.value.metadataCacheTTL || "5m"),
      set: (v) => patchJson({ metadataCacheTTL: v })
    });
    const credentialKind = computed({
      get: () => jsonData.value.credentialKind || "bearer",
      set: (v) => patchJson({ credentialKind: v })
    });
    const headerName = computed({
      get: () => String(jsonData.value.credentialHeaderName || ""),
      set: (v) => patchJson({ credentialHeaderName: v })
    });
    function setToken(v) {
      tokenLocal.value = v;
      const uid = String(props.options?.uid || "signoz");
      const kind = credentialKind.value;
      if (!v) {
        setRuntimeCredential(uid, null);
        return;
      }
      if (kind === "apiKey" || kind === "signozApiKey") {
        setRuntimeCredential(uid, {
          kind: "apiKey",
          value: v,
          headerName: headerName.value || (kind === "signozApiKey" ? "SIGNOZ-API-KEY" : "X-API-Key")
        });
      } else if (kind === "headers") {
        const h = headerName.value || "Authorization";
        setRuntimeCredential(uid, { kind: "headers", headers: { [h]: v } });
      } else if (kind === "session") {
        setRuntimeCredential(uid, {
          kind: "session",
          value: v || void 0,
          refreshToken: refreshTokenLocal.value || void 0,
          email: sessionEmail.value || void 0,
          password: rememberPassword.value ? sessionPassword.value || void 0 : void 0,
          orgID: organizationId.value || void 0,
          rememberPassword: rememberPassword.value
        });
      } else if (kind === "proxy") {
        setRuntimeCredential(uid, { kind: "headers", headers: {} });
      } else {
        setRuntimeCredential(uid, { kind: "bearer", value: v });
      }
    }
    async function loginSession() {
      const uid = String(props.options?.uid || "signoz");
      const baseUrl2 = String(props.options?.url || "").trim();
      if (!baseUrl2) {
        sessionLoginMessage.value = "请先填写 Base URL";
        return;
      }
      if (!sessionEmail.value || !sessionPassword.value) {
        sessionLoginMessage.value = "请填写邮箱和密码";
        return;
      }
      sessionLoginLoading.value = true;
      sessionLoginMessage.value = "";
      try {
        const next = await refreshSession({
          uid,
          baseUrl: baseUrl2,
          credential: {
            kind: "session",
            email: sessionEmail.value,
            password: sessionPassword.value,
            orgID: organizationId.value || void 0,
            rememberPassword: rememberPassword.value
          }
        });
        tokenLocal.value = next.value || "";
        refreshTokenLocal.value = next.refreshToken || "";
        if (next.orgID) {
          patchJson({ organizationId: next.orgID });
        }
        setToken(tokenLocal.value);
        sessionLoginMessage.value = "登录成功，access/refresh 已写入 runtime 内存";
      } catch (e) {
        sessionLoginMessage.value = String(e?.message || e || "登录失败");
      } finally {
        sessionLoginLoading.value = false;
      }
    }
    function patchCustomPath(key, value) {
      patchJson({
        [key]: value,
        customHealthOk: false,
        customHealthSignature: ""
      });
    }
    const canSave = computed(() => {
      if (apiProfile.value !== "custom") return Boolean(url.value.trim());
      const sig = buildCustomHealthSignature(url.value, jsonData.value);
      return Boolean(
        jsonData.value.customHealthOk && jsonData.value.customHealthSignature === sig && url.value.trim()
      );
    });
    async function testHealth() {
      testLoading.value = true;
      testMessage.value = "检测中…";
      try {
        const ds2 = createSignozDataSource(
          {
            uid: props.options?.uid || "signoz-cfg",
            name: props.options?.name || "SigNoz",
            type: "signoz",
            url: url.value,
            jsonData: jsonData.value,
            meta: { id: "signoz", name: "SigNoz" }
          },
          { id: "signoz", name: "SigNoz" }
        );
        const res = await ds2.testDatasource();
        const ok2 = res.status === "success";
        if (apiProfile.value === "custom") {
          if (ok2) {
            const sig = buildCustomHealthSignature(url.value, jsonData.value);
            patchJson({ customHealthOk: true, customHealthSignature: sig });
          } else {
            patchJson({ customHealthOk: false, customHealthSignature: "" });
          }
        }
        testMessage.value = res.message || (ok2 ? "OK" : "failed");
      } catch (e) {
        if (apiProfile.value === "custom")
          patchJson({ customHealthOk: false, customHealthSignature: "" });
        testMessage.value = e instanceof Error ? e.message : String(e);
      } finally {
        testLoading.value = false;
      }
    }
    watch(
      () => props.options,
      () => emitValidation(),
      { deep: true, immediate: true }
    );
    onUnmounted(() => {
      tokenLocal.value = "";
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", {
        class: "signoz-cfg",
        "data-testid": "config-editor-signoz",
        "data-save-allowed": String(canSave.value)
      }, [
        createVNode(unref(_sfc_main$1c), { layout: "vertical" }, {
          default: withCtx(() => [
            _cache[37] || (_cache[37] = createElementVNode(
              "h4",
              null,
              "连接",
              -1
              /* CACHED */
            )),
            _cache[38] || (_cache[38] = createElementVNode(
              "label",
              null,
              "Base URL",
              -1
              /* CACHED */
            )),
            createVNode(unref(GInput), {
              modelValue: url.value,
              "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => url.value = $event),
              placeholder: "http://localhost:3301",
              "test-id": "signoz-url"
            }, null, 8, ["modelValue"]),
            _cache[39] || (_cache[39] = createElementVNode(
              "label",
              null,
              "API Profile",
              -1
              /* CACHED */
            )),
            createVNode(unref(GSelect), {
              modelValue: apiProfile.value,
              "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => apiProfile.value = $event),
              options: [
                { label: "prometheus-compatible", value: "prometheus-compatible" },
                { label: "signoz-v5", value: "signoz-v5" },
                { label: "signoz-v3", value: "signoz-v3" },
                { label: "signoz-v4", value: "signoz-v4" },
                { label: "custom", value: "custom" }
              ],
              "test-id": "signoz-profile"
            }, null, 8, ["modelValue"]),
            _cache[40] || (_cache[40] = createElementVNode(
              "label",
              null,
              "Organization ID",
              -1
              /* CACHED */
            )),
            createVNode(unref(GInput), {
              modelValue: organizationId.value,
              "onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => organizationId.value = $event),
              "test-id": "signoz-organization-id"
            }, null, 8, ["modelValue"]),
            _cache[41] || (_cache[41] = createElementVNode(
              "label",
              null,
              "Default Environment",
              -1
              /* CACHED */
            )),
            createVNode(unref(GInput), {
              modelValue: defaultEnvironment.value,
              "onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => defaultEnvironment.value = $event),
              "test-id": "signoz-environment"
            }, null, 8, ["modelValue"]),
            _cache[42] || (_cache[42] = createElementVNode(
              "label",
              null,
              "超时 (ms)",
              -1
              /* CACHED */
            )),
            createVNode(unref(GInput), {
              "model-value": timeout.value,
              type: "number",
              "test-id": "signoz-timeout",
              "onUpdate:modelValue": _cache[4] || (_cache[4] = ($event) => timeout.value = Number($event))
            }, null, 8, ["model-value"]),
            _cache[43] || (_cache[43] = createElementVNode(
              "label",
              null,
              "元数据缓存 TTL",
              -1
              /* CACHED */
            )),
            createVNode(unref(GInput), {
              modelValue: cacheTTL.value,
              "onUpdate:modelValue": _cache[5] || (_cache[5] = ($event) => cacheTTL.value = $event),
              "test-id": "signoz-cache-ttl"
            }, null, 8, ["modelValue"]),
            _cache[44] || (_cache[44] = createElementVNode(
              "h4",
              null,
              "认证",
              -1
              /* CACHED */
            )),
            _cache[45] || (_cache[45] = createElementVNode(
              "label",
              null,
              "Credential Kind",
              -1
              /* CACHED */
            )),
            createVNode(unref(GSelect), {
              modelValue: credentialKind.value,
              "onUpdate:modelValue": _cache[6] || (_cache[6] = ($event) => credentialKind.value = $event),
              options: [
                { label: "Bearer / API Token", value: "bearer" },
                { label: "API Key", value: "apiKey" },
                { label: "Headers", value: "headers" },
                { label: "邮箱密码会话", value: "session" }
              ],
              "test-id": "signoz-credential-kind"
            }, null, 8, ["modelValue"]),
            _cache[46] || (_cache[46] = createElementVNode(
              "label",
              null,
              "Header Name",
              -1
              /* CACHED */
            )),
            createVNode(unref(GInput), {
              modelValue: headerName.value,
              "onUpdate:modelValue": _cache[7] || (_cache[7] = ($event) => headerName.value = $event),
              "test-id": "signoz-header-name",
              placeholder: "X-API-Key / Authorization"
            }, null, 8, ["modelValue"]),
            _cache[47] || (_cache[47] = createElementVNode(
              "label",
              null,
              "Token / Secret（runtime only）",
              -1
              /* CACHED */
            )),
            createVNode(unref(GInput), {
              "model-value": tokenLocal.value,
              type: "password",
              autocomplete: "off",
              "test-id": "signoz-token",
              "onUpdate:modelValue": _cache[8] || (_cache[8] = ($event) => setToken(String($event)))
            }, null, 8, ["model-value"]),
            credentialKind.value === "session" ? (openBlock(), createElementBlock(
              Fragment,
              { key: 0 },
              [
                _cache[23] || (_cache[23] = createElementVNode(
                  "label",
                  null,
                  "Refresh Token（runtime only，用于 /sessions/rotate）",
                  -1
                  /* CACHED */
                )),
                createVNode(unref(GInput), {
                  "model-value": refreshTokenLocal.value,
                  type: "password",
                  autocomplete: "off",
                  "test-id": "signoz-refresh-token",
                  "onUpdate:modelValue": _cache[9] || (_cache[9] = ($event) => {
                    refreshTokenLocal.value = String($event);
                    setToken(tokenLocal.value);
                  })
                }, null, 8, ["model-value"]),
                _cache[24] || (_cache[24] = createElementVNode(
                  "label",
                  null,
                  "邮箱",
                  -1
                  /* CACHED */
                )),
                createVNode(unref(GInput), {
                  "model-value": sessionEmail.value,
                  "test-id": "signoz-session-email",
                  "onUpdate:modelValue": _cache[10] || (_cache[10] = ($event) => {
                    sessionEmail.value = String($event);
                    setToken(tokenLocal.value);
                  })
                }, null, 8, ["model-value"]),
                _cache[25] || (_cache[25] = createElementVNode(
                  "label",
                  null,
                  "密码（仅 runtime 内存）",
                  -1
                  /* CACHED */
                )),
                createVNode(unref(GInput), {
                  "model-value": sessionPassword.value,
                  type: "password",
                  autocomplete: "off",
                  "test-id": "signoz-session-password",
                  "onUpdate:modelValue": _cache[11] || (_cache[11] = ($event) => {
                    sessionPassword.value = String($event);
                    setToken(tokenLocal.value);
                  })
                }, null, 8, ["model-value"]),
                createElementVNode("label", null, [
                  createElementVNode("input", {
                    type: "checkbox",
                    "data-testid": "signoz-remember-password",
                    checked: rememberPassword.value,
                    onChange: _cache[12] || (_cache[12] = ($event) => {
                      rememberPassword.value = $event.target.checked;
                      setToken(tokenLocal.value);
                    })
                  }, null, 40, _hoisted_2$2),
                  _cache[22] || (_cache[22] = createTextVNode(
                    " 记住密码用于自动续期 ",
                    -1
                    /* CACHED */
                  ))
                ]),
                createVNode(unref(GButton), {
                  "html-type": "button",
                  "test-id": "signoz-session-login",
                  loading: sessionLoginLoading.value,
                  disabled: sessionLoginLoading.value,
                  onClick: loginSession
                }, {
                  default: withCtx(() => [
                    createTextVNode(
                      toDisplayString(sessionLoginLoading.value ? "登录中…" : "邮箱密码登录并获取 token"),
                      1
                      /* TEXT */
                    )
                  ]),
                  _: 1
                  /* STABLE */
                }, 8, ["loading", "disabled"]),
                sessionLoginMessage.value ? (openBlock(), createElementBlock(
                  "p",
                  _hoisted_3$1,
                  toDisplayString(sessionLoginMessage.value),
                  1
                  /* TEXT */
                )) : createCommentVNode("v-if", true)
              ],
              64
              /* STABLE_FRAGMENT */
            )) : createCommentVNode("v-if", true),
            apiProfile.value === "custom" ? (openBlock(), createElementBlock(
              Fragment,
              { key: 1 },
              [
                _cache[26] || (_cache[26] = createElementVNode(
                  "h4",
                  null,
                  "Custom Endpoints",
                  -1
                  /* CACHED */
                )),
                _cache[27] || (_cache[27] = createElementVNode(
                  "label",
                  null,
                  "Health",
                  -1
                  /* CACHED */
                )),
                createVNode(unref(GInput), {
                  "model-value": jsonData.value.customHealthPath || "",
                  "test-id": "signoz-custom-health",
                  "onUpdate:modelValue": _cache[13] || (_cache[13] = ($event) => patchCustomPath("customHealthPath", String($event)))
                }, null, 8, ["model-value"]),
                _cache[28] || (_cache[28] = createElementVNode(
                  "label",
                  null,
                  "Metrics",
                  -1
                  /* CACHED */
                )),
                createVNode(unref(GInput), {
                  "model-value": jsonData.value.customMetricsPath || "",
                  "test-id": "signoz-custom-metrics",
                  "onUpdate:modelValue": _cache[14] || (_cache[14] = ($event) => patchCustomPath("customMetricsPath", String($event)))
                }, null, 8, ["model-value"]),
                _cache[29] || (_cache[29] = createElementVNode(
                  "label",
                  null,
                  "Logs",
                  -1
                  /* CACHED */
                )),
                createVNode(unref(GInput), {
                  "model-value": jsonData.value.customLogsPath || "",
                  "test-id": "signoz-custom-logs",
                  "onUpdate:modelValue": _cache[15] || (_cache[15] = ($event) => patchCustomPath("customLogsPath", String($event)))
                }, null, 8, ["model-value"]),
                _cache[30] || (_cache[30] = createElementVNode(
                  "label",
                  null,
                  "Traces",
                  -1
                  /* CACHED */
                )),
                createVNode(unref(GInput), {
                  "model-value": jsonData.value.customTracesPath || "",
                  "test-id": "signoz-custom-traces",
                  "onUpdate:modelValue": _cache[16] || (_cache[16] = ($event) => patchCustomPath("customTracesPath", String($event)))
                }, null, 8, ["model-value"]),
                _cache[31] || (_cache[31] = createElementVNode(
                  "label",
                  null,
                  "Alerts",
                  -1
                  /* CACHED */
                )),
                createVNode(unref(GInput), {
                  "model-value": jsonData.value.customAlertsPath || "",
                  "test-id": "signoz-custom-alerts",
                  "onUpdate:modelValue": _cache[17] || (_cache[17] = ($event) => patchCustomPath("customAlertsPath", String($event)))
                }, null, 8, ["model-value"]),
                _cache[32] || (_cache[32] = createElementVNode(
                  "label",
                  null,
                  "Trace by ID",
                  -1
                  /* CACHED */
                )),
                createVNode(unref(GInput), {
                  "model-value": jsonData.value.customTraceByIdPath || "",
                  "test-id": "signoz-custom-trace-detail",
                  "onUpdate:modelValue": _cache[18] || (_cache[18] = ($event) => patchCustomPath("customTraceByIdPath", String($event)))
                }, null, 8, ["model-value"]),
                _cache[33] || (_cache[33] = createElementVNode(
                  "label",
                  null,
                  "Metadata",
                  -1
                  /* CACHED */
                )),
                createVNode(unref(GInput), {
                  "model-value": jsonData.value.customMetadataPath || "",
                  "test-id": "signoz-custom-metadata",
                  "onUpdate:modelValue": _cache[19] || (_cache[19] = ($event) => patchCustomPath("customMetadataPath", String($event)))
                }, null, 8, ["model-value"]),
                _cache[34] || (_cache[34] = createElementVNode(
                  "label",
                  null,
                  "Acknowledge",
                  -1
                  /* CACHED */
                )),
                createVNode(unref(GInput), {
                  "model-value": jsonData.value.customAcknowledgePath || "",
                  "test-id": "signoz-custom-acknowledge",
                  "onUpdate:modelValue": _cache[20] || (_cache[20] = ($event) => patchCustomPath("customAcknowledgePath", String($event)))
                }, null, 8, ["model-value"]),
                _cache[35] || (_cache[35] = createElementVNode(
                  "label",
                  null,
                  "Resolve",
                  -1
                  /* CACHED */
                )),
                createVNode(unref(GInput), {
                  "model-value": jsonData.value.customResolvePath || "",
                  "test-id": "signoz-custom-resolve",
                  "onUpdate:modelValue": _cache[21] || (_cache[21] = ($event) => patchCustomPath("customResolvePath", String($event)))
                }, null, 8, ["model-value"]),
                createElementVNode("div", {
                  class: "health",
                  "data-ok": String(jsonData.value.customHealthOk),
                  "data-testid": "signoz-health-status"
                }, toDisplayString(jsonData.value.customHealthOk ? "已通过" : "未通过"), 9, _hoisted_4$1),
                !canSave.value ? (openBlock(), createElementBlock("div", _hoisted_5$1, " 保存已阻止：custom 未通过 health ")) : createCommentVNode("v-if", true)
              ],
              64
              /* STABLE_FRAGMENT */
            )) : createCommentVNode("v-if", true),
            createVNode(unref(GButton), {
              variant: "primary",
              loading: testLoading.value,
              "test-id": "signoz-health-test",
              onClick: testHealth
            }, {
              default: withCtx(() => [..._cache[36] || (_cache[36] = [
                createTextVNode(
                  " 测试连接 / 健康检查 ",
                  -1
                  /* CACHED */
                )
              ])]),
              _: 1
              /* STABLE */
            }, 8, ["loading"]),
            createElementVNode(
              "span",
              _hoisted_6$1,
              toDisplayString(testMessage.value),
              1
              /* TEXT */
            ),
            createElementVNode(
              "pre",
              _hoisted_7$1,
              toDisplayString(JSON.stringify(profile.value.endpoints, null, 2)),
              1
              /* TEXT */
            )
          ]),
          _: 1
          /* STABLE */
        })
      ], 8, _hoisted_1$2);
    };
  }
});
const ConfigEditor = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["__scopeId", "data-v-3a3dee0f"]]);
const _hoisted_1$1 = { "data-testid": "signoz-variable-query-editor" };
const _hoisted_2$1 = { key: 0 };
const _hoisted_3 = { key: 2 };
const _hoisted_4 = { key: 4 };
const _hoisted_5 = { key: 6 };
const _hoisted_6 = { key: 8 };
const _hoisted_7 = {
  key: 10,
  class: "warn",
  "data-testid": "signoz-var-unsupported",
  role: "status"
};
const _sfc_main$1 = /* @__PURE__ */ defineComponent({
  __name: "VariableQueryEditor",
  props: {
    query: {},
    onChange: { type: Function },
    datasource: {}
  },
  setup(__props) {
    const props = __props;
    function model() {
      if (typeof props.query === "string") {
        try {
          return JSON.parse(props.query);
        } catch {
          return { type: "service", search: props.query };
        }
      }
      return props.query?.type ? props.query : { type: "service", search: props.query?.query || "" };
    }
    const m = computed(() => model());
    const jsonData = computed(
      () => props.datasource?.jsonData || {}
    );
    const profile = computed(() => resolveSigNozProfile(jsonData.value));
    const caps2 = computed(
      () => resolveEditorCapabilities({
        profile: profile.value,
        options: jsonData.value
      })
    );
    function patch(p) {
      props.onChange({ ...m.value, ...p });
    }
    const unsupportedReason = computed(() => {
      const type = String(m.value.type || "service");
      const blocked = caps2.value?.unsupportedVariableTypes;
      if (blocked?.includes(type)) {
        return `当前 API Profile 不支持变量类型「${type}」`;
      }
      if (type === "clickhouse_query" && caps2.value?.clickhouseSql === false) {
        return "当前 Profile 未启用 ClickHouse SQL 变量";
      }
      return "";
    });
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1$1, [
        _cache[7] || (_cache[7] = createElementVNode(
          "label",
          null,
          "变量类型",
          -1
          /* CACHED */
        )),
        createVNode(unref(GSelect), {
          value: m.value.type || "service",
          options: [
            { label: "Environment", value: "environment" },
            { label: "Service", value: "service" },
            { label: "Operation", value: "operation" },
            { label: "Metric", value: "metric" },
            { label: "Attribute Key", value: "attributeKey" },
            { label: "Attribute Value", value: "attributeValue" },
            { label: "Dynamic (field+source)", value: "dynamic" },
            { label: "ClickHouse Query", value: "clickhouse_query" }
          ],
          "test-id": "signoz-var-type",
          "onUpdate:value": _cache[0] || (_cache[0] = ($event) => patch({ type: String($event) }))
        }, null, 8, ["value"]),
        _cache[8] || (_cache[8] = createElementVNode(
          "label",
          null,
          "搜索",
          -1
          /* CACHED */
        )),
        createVNode(unref(GInput), {
          "model-value": String(m.value.search || ""),
          "test-id": "signoz-var-search",
          "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => patch({ search: String($event) }))
        }, null, 8, ["model-value"]),
        m.value.type === "operation" ? (openBlock(), createElementBlock("label", _hoisted_2$1, "Service")) : createCommentVNode("v-if", true),
        m.value.type === "operation" ? (openBlock(), createBlock(unref(GInput), {
          key: 1,
          "model-value": String(m.value.service || ""),
          "test-id": "signoz-var-service",
          "onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => patch({ service: String($event) }))
        }, null, 8, ["model-value"])) : createCommentVNode("v-if", true),
        m.value.type === "attributeValue" || m.value.type === "attributeKey" ? (openBlock(), createElementBlock("label", _hoisted_3, "Key / Metric")) : createCommentVNode("v-if", true),
        m.value.type === "attributeValue" ? (openBlock(), createBlock(unref(GInput), {
          key: 3,
          "model-value": String(m.value.key || ""),
          "test-id": "signoz-var-key",
          "onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => patch({ key: String($event) }))
        }, null, 8, ["model-value"])) : createCommentVNode("v-if", true),
        m.value.type === "dynamic" ? (openBlock(), createElementBlock("label", _hoisted_4, "Field")) : createCommentVNode("v-if", true),
        m.value.type === "dynamic" ? (openBlock(), createBlock(unref(GInput), {
          key: 5,
          "model-value": String(m.value.field || m.value.key || ""),
          "test-id": "signoz-var-dynamic-field",
          "onUpdate:modelValue": _cache[4] || (_cache[4] = ($event) => patch({ field: String($event) }))
        }, null, 8, ["model-value"])) : createCommentVNode("v-if", true),
        m.value.type === "dynamic" ? (openBlock(), createElementBlock("label", _hoisted_5, "Source")) : createCommentVNode("v-if", true),
        m.value.type === "dynamic" ? (openBlock(), createBlock(unref(GSelect), {
          key: 7,
          value: m.value.source || m.value.signal || "metrics",
          options: [
            { label: "metrics", value: "metrics" },
            { label: "logs", value: "logs" },
            { label: "traces", value: "traces" }
          ],
          "test-id": "signoz-var-dynamic-source",
          "onUpdate:value": _cache[5] || (_cache[5] = ($event) => patch({ source: String($event) }))
        }, null, 8, ["value"])) : createCommentVNode("v-if", true),
        m.value.type === "clickhouse_query" ? (openBlock(), createElementBlock("label", _hoisted_6, "SQL")) : createCommentVNode("v-if", true),
        m.value.type === "clickhouse_query" ? (openBlock(), createBlock(unref(GInput), {
          key: 9,
          "model-value": String(m.value.query || m.value.sql || ""),
          "test-id": "signoz-var-ch-sql",
          "onUpdate:modelValue": _cache[6] || (_cache[6] = ($event) => patch({ query: String($event) }))
        }, null, 8, ["model-value"])) : createCommentVNode("v-if", true),
        unsupportedReason.value ? (openBlock(), createElementBlock(
          "p",
          _hoisted_7,
          toDisplayString(unsupportedReason.value),
          1
          /* TEXT */
        )) : createCommentVNode("v-if", true)
      ]);
    };
  }
});
const VariableQueryEditor = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["__scopeId", "data-v-96cf0d9a"]]);
const _hoisted_1 = { "data-testid": "signoz-annotation-query-editor" };
const _hoisted_2 = {
  key: 0,
  class: "hint",
  "data-testid": "signoz-anno-alerts-hidden"
};
const _sfc_main = /* @__PURE__ */ defineComponent({
  __name: "AnnotationQueryEditor",
  props: {
    annotation: {},
    onChange: { type: Function },
    datasource: {}
  },
  setup(__props) {
    const props = __props;
    const target = computed(
      () => props.annotation.target || {}
    );
    const jsonData = computed(
      () => props.datasource?.jsonData || {}
    );
    const profile = computed(() => {
      const jd = jsonData.value;
      const resolved = resolveSigNozProfile(jd);
      if (jd.customAlertsPath && !resolved.endpoints.alertsQuery) {
        return {
          ...resolved,
          endpoints: {
            ...resolved.endpoints,
            alertsQuery: { path: jd.customAlertsPath, method: "POST" }
          }
        };
      }
      return resolved;
    });
    const caps2 = computed(
      () => resolveEditorCapabilities({
        profile: profile.value,
        options: jsonData.value
      })
    );
    const sourceOptions = computed(() => {
      const opts = [
        { label: "Error Logs", value: "errorLogs" },
        { label: "Error Spans", value: "errorSpans" }
      ];
      if (caps2.value.alerts) {
        opts.push({ label: "Firing Alerts", value: "firingAlerts" });
      }
      return opts;
    });
    function patchTarget(partial) {
      props.onChange({
        ...props.annotation,
        name: props.annotation.name,
        enable: props.annotation.enable,
        iconColor: props.annotation.iconColor,
        target: { ...target.value, ...partial }
      });
    }
    return (_ctx, _cache) => {
      return openBlock(), createElementBlock("div", _hoisted_1, [
        _cache[3] || (_cache[3] = createElementVNode(
          "label",
          null,
          "来源",
          -1
          /* CACHED */
        )),
        createVNode(unref(GSelect), {
          value: target.value.source || "errorLogs",
          options: sourceOptions.value,
          "test-id": "signoz-anno-source",
          "onUpdate:value": _cache[0] || (_cache[0] = ($event) => patchTarget({ source: String($event) }))
        }, null, 8, ["value", "options"]),
        _cache[4] || (_cache[4] = createElementVNode(
          "label",
          null,
          "Service",
          -1
          /* CACHED */
        )),
        createVNode(unref(GInput), {
          "model-value": String(target.value.service || ""),
          "test-id": "signoz-anno-service",
          "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => patchTarget({ service: String($event) }))
        }, null, 8, ["model-value"]),
        _cache[5] || (_cache[5] = createElementVNode(
          "label",
          null,
          "Environment",
          -1
          /* CACHED */
        )),
        createVNode(unref(GInput), {
          "model-value": String(target.value.environment || ""),
          "test-id": "signoz-anno-environment",
          "onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => patchTarget({ environment: String($event) }))
        }, null, 8, ["model-value"]),
        !caps2.value.alerts ? (openBlock(), createElementBlock("p", _hoisted_2, " Firing Alerts 已隐藏（当前 profile 无 alertsQuery capability） ")) : createCommentVNode("v-if", true)
      ]);
    };
  }
});
const AnnotationQueryEditor = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-5fb7503e"]]);
registerSignozDataSourceFactory(createSignozDataSource);
const meta = {
  id: "signoz",
  name: "SigNoz",
  metrics: true,
  logs: true,
  tracing: true,
  capabilities: SIGNOZ_CAPABILITIES
};
const plugin = createDataSourcePlugin({
  meta,
  QueryEditor,
  ConfigEditor,
  VariableQueryEditor,
  AnnotationQueryEditor,
  createDataSource: (instance) => createSignozDataSource(instance, meta)
});
const module$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
  __proto__: null,
  default: plugin,
  plugin
}, Symbol.toStringTag, { value: "Module" }));
export {
  bootstrapGrafanaVue,
  bootstrapObservabilityDataSources,
  defaultObservabilityDataSources,
  isBuiltinPluginsRegistered,
  isHeavyPluginsRegistered,
  mergeObservabilityDataSourceInput,
  mergeObservabilityDataSourceInputsByUid,
  registerBuiltinPlugins,
  registerHeavyPlugins,
  resolveObservabilityDataSources
};
//# sourceMappingURL=register.js.map
